1 float scoreboard_alpha_bg;
2 float scoreboard_alpha_fg;
3 float scoreboard_highlight;
4 float scoreboard_highlight_alpha;
5 float scoreboard_highlight_alpha_self;
6 float scoreboard_alpha_name;
7 float scoreboard_alpha_name_self;
9 void drawstringright(vector, string, vector, vector, float, float);
10 void drawstringcenter(vector, string, vector, vector, float, float);
12 const float SCOREBOARD_OFFSET = 50;
14 // wrapper to put all possible scores titles through gettext
15 string TranslateScoresLabel(string l)
19 case "bckills": return CTX(_("SCO^bckills"));
20 case "bctime": return CTX(_("SCO^bctime"));
21 case "caps": return CTX(_("SCO^caps"));
22 case "captime": return CTX(_("SCO^captime"));
23 case "deaths": return CTX(_("SCO^deaths"));
24 case "destroyed": return CTX(_("SCO^destroyed"));
25 case "drops": return CTX(_("SCO^drops"));
26 case "faults": return CTX(_("SCO^faults"));
27 case "fckills": return CTX(_("SCO^fckills"));
28 case "goals": return CTX(_("SCO^goals"));
29 case "kckills": return CTX(_("SCO^kckills"));
30 case "kdratio": return CTX(_("SCO^kdratio"));
31 case "k/d": return CTX(_("SCO^k/d"));
32 case "kd": return CTX(_("SCO^kd"));
33 case "kdr": return CTX(_("SCO^kdr"));
34 case "kills": return CTX(_("SCO^kills"));
35 case "laps": return CTX(_("SCO^laps"));
36 case "lives": return CTX(_("SCO^lives"));
37 case "losses": return CTX(_("SCO^losses"));
38 case "name": return CTX(_("SCO^name"));
39 case "sum": return CTX(_("SCO^sum"));
40 case "nick": return CTX(_("SCO^nick"));
41 case "objectives": return CTX(_("SCO^objectives"));
42 case "pickups": return CTX(_("SCO^pickups"));
43 case "ping": return CTX(_("SCO^ping"));
44 case "pl": return CTX(_("SCO^pl"));
45 case "pushes": return CTX(_("SCO^pushes"));
46 case "rank": return CTX(_("SCO^rank"));
47 case "returns": return CTX(_("SCO^returns"));
48 case "revivals": return CTX(_("SCO^revivals"));
49 case "score": return CTX(_("SCO^score"));
50 case "suicides": return CTX(_("SCO^suicides"));
51 case "takes": return CTX(_("SCO^takes"));
52 case "ticks": return CTX(_("SCO^ticks"));
57 void Cmd_HUD_SetFields(float argc);
62 ps_primary = ps_secondary = ts_primary = ts_secondary = -1;
63 for(i = 0; i < MAX_SCORE; ++i)
65 f = (scores_flags[i] & SFL_SORT_PRIO_MASK);
66 if(f == SFL_SORT_PRIO_PRIMARY)
68 if(f == SFL_SORT_PRIO_SECONDARY)
71 if(ps_secondary == -1)
72 ps_secondary = ps_primary;
74 for(i = 0; i < MAX_TEAMSCORE; ++i)
76 f = (teamscores_flags[i] & SFL_SORT_PRIO_MASK);
77 if(f == SFL_SORT_PRIO_PRIMARY)
79 if(f == SFL_SORT_PRIO_SECONDARY)
82 if(ts_secondary == -1)
83 ts_secondary = ts_primary;
88 void HUD_UpdatePlayerPos(entity pl);
89 float SetTeam(entity pl, float Team);
91 void HUD_UpdatePlayerTeams()
98 for(pl = players.sort_next; pl; pl = pl.sort_next)
101 Team = GetPlayerColor(pl.sv_entnum);
102 if(SetTeam(pl, Team))
105 HUD_UpdatePlayerPos(pl);
109 pl = players.sort_next;
114 print(strcat("PNUM: ", ftos(num), "\n"));
119 float HUD_CompareScore(float vl, float vr, float f)
121 if(f & SFL_ZERO_IS_WORST)
123 if(vl == 0 && vr != 0)
125 if(vl != 0 && vr == 0)
129 return IS_INCREASING(f);
131 return IS_DECREASING(f);
135 float HUD_ComparePlayerScores(entity left, entity right)
138 vl = GetPlayerColor(left.sv_entnum);
139 vr = GetPlayerColor(right.sv_entnum);
151 if(vl == NUM_SPECTATOR)
153 // FIRST the one with scores (spectators), THEN the ones without (downloaders)
155 if(!left.gotscores && right.gotscores)
160 r = HUD_CompareScore(left.scores[ps_primary], right.scores[ps_primary], scores_flags[ps_primary]);
164 r = HUD_CompareScore(left.scores[ps_secondary], right.scores[ps_secondary], scores_flags[ps_secondary]);
168 for(i = 0; i < MAX_SCORE; ++i)
170 r = HUD_CompareScore(left.scores[i], right.scores[i], scores_flags[i]);
175 if (left.sv_entnum < right.sv_entnum)
181 void HUD_UpdatePlayerPos(entity player)
183 for(other = player.sort_next; other && HUD_ComparePlayerScores(player, other); other = player.sort_next)
185 SORT_SWAP(player, other);
187 for(other = player.sort_prev; other != players && HUD_ComparePlayerScores(other, player); other = player.sort_prev)
189 SORT_SWAP(other, player);
193 float HUD_CompareTeamScores(entity left, entity right)
197 if(left.team == NUM_SPECTATOR)
199 if(right.team == NUM_SPECTATOR)
202 r = HUD_CompareScore(left.teamscores[ts_primary], right.teamscores[ts_primary], teamscores_flags[ts_primary]);
206 r = HUD_CompareScore(left.teamscores[ts_secondary], right.teamscores[ts_secondary], teamscores_flags[ts_secondary]);
210 for(i = 0; i < MAX_SCORE; ++i)
212 r = HUD_CompareScore(left.teamscores[i], right.teamscores[i], teamscores_flags[i]);
217 if (left.team < right.team)
223 void HUD_UpdateTeamPos(entity Team)
225 for(other = Team.sort_next; other && HUD_CompareTeamScores(Team, other); other = Team.sort_next)
227 SORT_SWAP(Team, other);
229 for(other = Team.sort_prev; other != teams && HUD_CompareTeamScores(other, Team); other = Team.sort_prev)
231 SORT_SWAP(other, Team);
237 print(_("You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"));
238 print(_("^3|---------------------------------------------------------------|\n"));
239 print(_("Usage:\n"));
240 print(_("^2scoreboard_columns_set default\n"));
241 print(_("^2scoreboard_columns_set ^7field1 field2 ...\n"));
242 print(_("The following field names are recognized (case insensitive):\n"));
243 print(_("You can use a ^3|^7 to start the right-aligned fields.\n\n"));
245 print(_("^3name^7 or ^3nick^7 Name of a player\n"));
246 print(_("^3ping^7 Ping time\n"));
247 print(_("^3pl^7 Packet loss\n"));
248 print(_("^3kills^7 Number of kills\n"));
249 print(_("^3deaths^7 Number of deaths\n"));
250 print(_("^3suicides^7 Number of suicides\n"));
251 print(_("^3frags^7 kills - suicides\n"));
252 print(_("^3kd^7 The kill-death ratio\n"));
253 print(_("^3sum^7 frags - deaths\n"));
254 print(_("^3caps^7 How often a flag (CTF) or a key (KeyHunt) was captured\n"));
255 print(_("^3pickups^7 How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\n"));
256 print(_("^3captime^7 Time of fastest cap (CTF)\n"));
257 print(_("^3fckills^7 Number of flag carrier kills\n"));
258 print(_("^3returns^7 Number of flag returns\n"));
259 print(_("^3drops^7 Number of flag drops\n"));
260 print(_("^3lives^7 Number of lives (LMS)\n"));
261 print(_("^3rank^7 Player rank\n"));
262 print(_("^3pushes^7 Number of players pushed into void\n"));
263 print(_("^3destroyed^7 Number of keys destroyed by pushing them into void\n"));
264 print(_("^3kckills^7 Number of keys carrier kills\n"));
265 print(_("^3losses^7 Number of times a key was lost\n"));
266 print(_("^3laps^7 Number of laps finished (race/cts)\n"));
267 print(_("^3time^7 Total time raced (race/cts)\n"));
268 print(_("^3fastest^7 Time of fastest lap (race/cts)\n"));
269 print(_("^3ticks^7 Number of ticks (DOM)\n"));
270 print(_("^3takes^7 Number of domination points taken (DOM)\n"));
271 print(_("^3bckills^7 Number of ball carrier kills\n"));
272 print(_("^3bctime^7 Total amount of time holding the ball in Keepaway\n"));
273 print(_("^3score^7 Total score\n\n"));
275 print(_("Before a field you can put a + or - sign, then a comma separated list\n"
276 "of game types, then a slash, to make the field show up only in these\n"
277 "or in all but these game types. You can also specify 'all' as a\n"
278 "field to show all fields available for the current game mode.\n\n"));
280 print(_("The special game type names 'teams' and 'noteams' can be used to\n"
281 "include/exclude ALL teams/noteams game modes.\n\n"));
283 print(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"));
284 print(_("will display name, ping and pl aligned to the left, and the fields\n"
285 "right of the vertical bar aligned to the right.\n"));
286 print(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
287 "other gamemodes except DM.\n"));
290 string HUD_DefaultColumnLayout()
292 return strcat( // fteqcc sucks
294 "-teams,race,lms/kills +freezetag,tdm/kills -teams,lms/deaths +freezetag,tdm/deaths -teams,lms,race,ka/suicides +freezetag,tdm/suicides -race,dm,tdm,ka,freezetag/frags ", // tdm already has this in "score"
295 "+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns ",
296 "+lms/lives +lms/rank ",
297 "+kh/caps +kh/pushes +kh/destroyed ",
298 "?+race/laps ?+race/time ?+race/fastest ",
299 "+as/objectives +nexball/faults +nexball/goals +ka/pickups +ka/bckills +ka/bctime +freezetag/revivals ",
300 "-lms,race,nexball/score");
303 void Cmd_HUD_SetFields(float argc)
307 float have_name = 0, have_primary = 0, have_secondary = 0, have_separator = 0;
310 // TODO: re enable with gametype dependant cvars?
311 if(argc < 3) // no arguments provided
312 argc = tokenizebyseparator(strcat("0 1 ", autocvar_scoreboard_columns), " ");
315 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
319 if(argv(2) == "default")
320 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
321 else if(argv(2) == "all")
324 s = "ping pl name |";
325 for(i = 0; i < MAX_SCORE; ++i)
328 if(i != ps_secondary)
329 if(scores_label[i] != "")
330 s = strcat(s, " ", scores_label[i]);
332 if(ps_secondary != ps_primary)
333 s = strcat(s, " ", scores_label[ps_secondary]);
334 s = strcat(s, " ", scores_label[ps_primary]);
335 argc = tokenizebyseparator(strcat("0 1 ", s), " ");
342 hud_fontsize = HUD_GetFontsize("hud_fontsize");
344 draw_beginBoldFont();
345 for(i = 1; i < argc - 1; ++i)
351 if(substring(str, 0, 1) == "?")
354 str = substring(str, 1, strlen(str) - 1);
357 slash = strstrofs(str, "/", 0);
360 pattern = substring(str, 0, slash);
361 str = substring(str, slash + 1, strlen(str) - (slash + 1));
363 if (!isGametypeInFilter(gametype, teamplay, FALSE, pattern))
367 strunzone(hud_title[hud_num_fields]);
368 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(str));
369 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
370 str = strtolower(str);
373 hud_field[hud_num_fields] = SP_PING;
374 } else if(str == "pl") {
375 hud_field[hud_num_fields] = SP_PL;
376 } else if(str == "kd" || str == "kdr" || str == "kdratio" || str == "k/d") {
377 hud_field[hud_num_fields] = SP_KDRATIO;
378 } else if(str == "sum" || str == "diff" || str == "k-d") {
379 hud_field[hud_num_fields] = SP_SUM;
380 } else if(str == "name" || str == "nick") {
381 hud_field[hud_num_fields] = SP_NAME;
383 } else if(str == "|") {
384 hud_field[hud_num_fields] = SP_SEPARATOR;
387 for(j = 0; j < MAX_SCORE; ++j)
388 if(str == strtolower(scores_label[j]))
389 goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
398 printf("^1Error:^7 Unknown score field: '%s'\n", str);
402 hud_field[hud_num_fields] = j;
405 if(j == ps_secondary)
409 if(hud_num_fields >= MAX_HUD_FIELDS)
413 if(scores_flags[ps_primary] & SFL_ALLOW_HIDE)
415 if(scores_flags[ps_secondary] & SFL_ALLOW_HIDE)
417 if(ps_primary == ps_secondary)
419 missing = (!have_primary) + (!have_secondary) + (!have_separator) + (!have_name);
421 if(hud_num_fields+missing < MAX_HUD_FIELDS)
425 strunzone(hud_title[hud_num_fields]);
426 for(i = hud_num_fields; i > 0; --i)
428 hud_title[i] = hud_title[i-1];
429 hud_size[i] = hud_size[i-1];
430 hud_field[i] = hud_field[i-1];
432 hud_title[0] = strzone(TranslateScoresLabel("name"));
433 hud_field[0] = SP_NAME;
435 print("fixed missing field 'name'\n");
439 strunzone(hud_title[hud_num_fields]);
440 for(i = hud_num_fields; i > 1; --i)
442 hud_title[i] = hud_title[i-1];
443 hud_size[i] = hud_size[i-1];
444 hud_field[i] = hud_field[i-1];
446 hud_title[1] = strzone("|");
447 hud_field[1] = SP_SEPARATOR;
448 hud_size[1] = stringwidth("|", FALSE, hud_fontsize);
450 print("fixed missing field '|'\n");
453 else if(!have_separator)
455 strunzone(hud_title[hud_num_fields]);
456 hud_title[hud_num_fields] = strzone("|");
457 hud_size[hud_num_fields] = stringwidth("|", FALSE, hud_fontsize);
458 hud_field[hud_num_fields] = SP_SEPARATOR;
460 print("fixed missing field '|'\n");
464 strunzone(hud_title[hud_num_fields]);
465 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_secondary]));
466 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
467 hud_field[hud_num_fields] = ps_secondary;
469 printf("fixed missing field '%s'\n", scores_label[ps_secondary]);
473 strunzone(hud_title[hud_num_fields]);
474 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_primary]));
475 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
476 hud_field[hud_num_fields] = ps_primary;
478 printf("fixed missing field '%s'\n", scores_label[ps_primary]);
482 hud_field[hud_num_fields] = SP_END;
487 vector hud_field_rgb;
488 string hud_field_icon0;
489 string hud_field_icon1;
490 string hud_field_icon2;
491 vector hud_field_icon0_rgb;
492 vector hud_field_icon1_rgb;
493 vector hud_field_icon2_rgb;
494 float hud_field_icon0_alpha;
495 float hud_field_icon1_alpha;
496 float hud_field_icon2_alpha;
497 string HUD_GetField(entity pl, float field)
499 float tmp, num, denom, f;
501 hud_field_rgb = '1 1 1';
502 hud_field_icon0 = "";
503 hud_field_icon1 = "";
504 hud_field_icon2 = "";
505 hud_field_icon0_rgb = '1 1 1';
506 hud_field_icon1_rgb = '1 1 1';
507 hud_field_icon2_rgb = '1 1 1';
508 hud_field_icon0_alpha = 1;
509 hud_field_icon1_alpha = 1;
510 hud_field_icon2_alpha = 1;
515 return "\xEE\x82\x8D\xEE\x82\x8D\xEE\x82\x8D"; // >>> sign
516 //str = getplayerkeyvalue(pl.sv_entnum, "ping");
520 tmp = max(0, min(220, f-80)) / 220;
521 hud_field_rgb = '1 1 1' - '0 1 1'*tmp;
527 f = pl.ping_packetloss;
528 tmp = pl.ping_movementloss;
529 if(f == 0 && tmp == 0)
531 str = ftos(ceil(f * 100));
533 str = strcat(str, "~", ftos(ceil(tmp * 100)));
534 tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
535 hud_field_rgb = '1 0.5 0.5' - '0 0.5 0.5'*tmp;
539 if(ready_waiting && pl.ready)
541 hud_field_icon0 = "gfx/scoreboard/player_ready";
545 f = stof(getplayerkeyvalue(pl.sv_entnum, "colors"));
547 hud_field_icon0 = "gfx/scoreboard/playercolor_base";
548 hud_field_icon1 = "gfx/scoreboard/playercolor_shirt";
549 hud_field_icon1_rgb = colormapPaletteColor(floor(f / 16), 0);
550 hud_field_icon2 = "gfx/scoreboard/playercolor_pants";
551 hud_field_icon2_rgb = colormapPaletteColor(mod(f, 16), 1);
554 return GetPlayerName(pl.sv_entnum);
557 f = pl.(scores[SP_KILLS]);
558 f -= pl.(scores[SP_SUICIDES]);
562 num = pl.(scores[SP_KILLS]);
563 denom = pl.(scores[SP_DEATHS]);
566 hud_field_rgb = '0 1 0';
567 str = sprintf("%d", num);
568 } else if(num <= 0) {
569 hud_field_rgb = '1 0 0';
570 str = sprintf("%.1f", num/denom);
572 str = sprintf("%.1f", num/denom);
576 f = pl.(scores[SP_KILLS]);
577 f -= pl.(scores[SP_DEATHS]);
580 hud_field_rgb = '0 1 0';
582 hud_field_rgb = '1 1 1';
584 hud_field_rgb = '1 0 0';
589 tmp = pl.(scores[field]);
590 f = scores_flags[field];
591 if(field == ps_primary)
592 hud_field_rgb = '1 1 0';
593 else if(field == ps_secondary)
594 hud_field_rgb = '0 1 1';
596 hud_field_rgb = '1 1 1';
597 return ScoreString(f, tmp);
602 float xmin, xmax, ymin, ymax, sbwidth;
603 float hud_fixscoreboardcolumnwidth_len;
604 float hud_fixscoreboardcolumnwidth_iconlen;
605 float hud_fixscoreboardcolumnwidth_marginlen;
607 string HUD_FixScoreboardColumnWidth(float i, string str)
611 field = hud_field[i];
613 hud_fixscoreboardcolumnwidth_iconlen = 0;
615 if(hud_field_icon0 != "")
617 sz = draw_getimagesize(hud_field_icon0);
619 if(hud_fixscoreboardcolumnwidth_iconlen < f)
620 hud_fixscoreboardcolumnwidth_iconlen = f;
623 if(hud_field_icon1 != "")
625 sz = draw_getimagesize(hud_field_icon1);
627 if(hud_fixscoreboardcolumnwidth_iconlen < f)
628 hud_fixscoreboardcolumnwidth_iconlen = f;
631 if(hud_field_icon2 != "")
633 sz = draw_getimagesize(hud_field_icon2);
635 if(hud_fixscoreboardcolumnwidth_iconlen < f)
636 hud_fixscoreboardcolumnwidth_iconlen = f;
639 hud_fixscoreboardcolumnwidth_iconlen *= hud_fontsize_y / hud_fontsize_x; // fix icon aspect
641 if(hud_fixscoreboardcolumnwidth_iconlen != 0)
642 hud_fixscoreboardcolumnwidth_marginlen = stringwidth(" ", FALSE, hud_fontsize);
644 hud_fixscoreboardcolumnwidth_marginlen = 0;
646 if(field == SP_NAME) // name gets all remaining space
649 namesize = sbwidth;// / hud_fontsize_x;
650 for(j = 0; j < hud_num_fields; ++j)
652 if (hud_field[i] != SP_SEPARATOR)
653 namesize -= hud_size[j] + hud_fontsize_x;
654 namesize += hud_fontsize_x;
655 hud_size[i] = namesize;
657 if (hud_fixscoreboardcolumnwidth_iconlen != 0)
658 namesize -= hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
659 str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
660 hud_fixscoreboardcolumnwidth_len = stringwidth(str, TRUE, hud_fontsize);
663 hud_fixscoreboardcolumnwidth_len = stringwidth(str, FALSE, hud_fontsize);
665 f = hud_fixscoreboardcolumnwidth_len + hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
672 void HUD_PrintScoreboardItem(vector pos, entity pl, float is_self, float pl_number)
675 rgb = Team_ColorRGB(pl.team);
679 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
681 if((rgb == '1 1 1') && (!is_spec)) {
682 rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
683 rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
684 rgb_z = autocvar_scoreboard_color_bg_b + 0.5; }
688 tmp_y = hud_fontsize_y * 1.25;
691 // alternated rows highlighting
693 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
694 else if((scoreboard_highlight) && (!mod(pl_number,2)))
695 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
699 for(i = 0; i < hud_num_fields; ++i)
701 field = hud_field[i];
702 if(field == SP_SEPARATOR)
705 if(is_spec && field != SP_NAME && field != SP_PING) {
706 pos_x += hud_size[i] + hud_fontsize_x;
709 str = HUD_GetField(pl, field);
710 str = HUD_FixScoreboardColumnWidth(i, str);
712 pos_x += hud_size[i] + hud_fontsize_x;
714 if(field == SP_NAME) {
715 tmp_x = hud_size[i] - hud_fontsize_x*hud_fixscoreboardcolumnwidth_iconlen - hud_fixscoreboardcolumnwidth_marginlen + hud_fontsize_x;
717 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
719 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
721 tmp_x = hud_fixscoreboardcolumnwidth_len + hud_fontsize_x;
723 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
725 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
728 tmp_x = hud_size[i] + hud_fontsize_x;
729 if(hud_field_icon0 != "")
731 drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
733 drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
734 if(hud_field_icon1 != "")
736 drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
738 drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
739 if(hud_field_icon2 != "")
741 drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
743 drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
746 if(hud_field[i] == SP_SEPARATOR)
749 for(i = hud_num_fields-1; i > 0; --i)
751 field = hud_field[i];
752 if(field == SP_SEPARATOR)
755 if(is_spec && field != SP_NAME && field != SP_PING) {
756 pos_x -= hud_size[i] + hud_fontsize_x;
760 str = HUD_GetField(pl, field);
761 str = HUD_FixScoreboardColumnWidth(i, str);
763 if(field == SP_NAME) {
764 tmp_x = hud_fixscoreboardcolumnwidth_len; // left or right aligned? let's put it right...
766 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
768 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
770 tmp_x = hud_fixscoreboardcolumnwidth_len;
772 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
774 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
778 if(hud_field_icon0 != "")
780 drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
782 drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
783 if(hud_field_icon1 != "")
785 drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
787 drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
788 if(hud_field_icon2 != "")
790 drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
792 drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
793 pos_x -= hud_size[i] + hud_fontsize_x;
799 * HUD_Scoreboard_MakeTable
801 * Makes a table for a team (for all playing players in DM) and fills it
804 vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
806 float body_table_height, i;
807 vector tmp = '0 0 0', column_dim = '0 0 0';
810 body_table_height = 1.25 * hud_fontsize_y * max(1, tm.team_size); // no player? show 1 empty line
812 pos_y += autocvar_scoreboard_border_thickness;
816 tmp_y = 1.25 * hud_fontsize_y;
820 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, (rgb * autocvar_scoreboard_color_bg_team) + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
822 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
825 tmp_y += autocvar_scoreboard_border_thickness;
826 tmp_y += body_table_height;
827 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // more transparency for the scoreboard
829 // separator header/table
830 pos_y += 1.25 * hud_fontsize_y;
831 tmp_y = autocvar_scoreboard_border_thickness;
832 drawfill(pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
834 pos_y += autocvar_scoreboard_border_thickness;
837 tmp_y = body_table_height;
839 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
841 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
843 // anyway, apply some color
844 //drawfill(pos, tmp + '2 0 0', rgb, 0.1, DRAWFLAG_NORMAL);
846 // go back to the top to make alternated columns highlighting and to print the strings
847 pos_y -= 1.25 * hud_fontsize_y;
848 pos_y -= autocvar_scoreboard_border_thickness;
852 if (scoreboard_highlight)
854 column_dim_y = 1.25 * hud_fontsize_y; // header
855 column_dim_y += autocvar_scoreboard_border_thickness;
856 column_dim_y += body_table_height;
859 // print the strings of the columns headers and draw the columns
860 draw_beginBoldFont();
861 for(i = 0; i < hud_num_fields; ++i)
863 if(hud_field[i] == SP_SEPARATOR)
865 column_dim_x = hud_size[i] + hud_fontsize_x;
866 if (scoreboard_highlight)
869 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
871 drawstring(pos, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
872 pos_x += column_dim_x;
874 if(hud_field[i] == SP_SEPARATOR)
878 for(i = hud_num_fields-1; i > 0; --i)
880 if(hud_field[i] == SP_SEPARATOR)
883 pos_x -= hud_size[i];
885 if (scoreboard_highlight)
889 if (i == hud_num_fields-1)
890 column_dim_x = hud_size[i] + hud_fontsize_x / 2 + 1;
892 column_dim_x = hud_size[i] + hud_fontsize_x;
893 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
897 tmp_x = stringwidth(hud_title[i], FALSE, hud_fontsize);
898 tmp_x = (hud_size[i] - tmp_x);
899 drawstring(pos + tmp, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
900 pos_x -= hud_fontsize_x;
906 pos_y += 1.25 * hud_fontsize_y; // skip the header
907 pos_y += autocvar_scoreboard_border_thickness;
909 // fill the table and draw the rows
912 for(pl = players.sort_next; pl; pl = pl.sort_next)
914 if(pl.team != tm.team)
916 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
917 pos_y += 1.25 * hud_fontsize_y;
921 for(pl = players.sort_next; pl; pl = pl.sort_next)
923 if(pl.team == NUM_SPECTATOR)
925 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
926 pos_y += 1.25 * hud_fontsize_y;
931 pos_y += 1.25 * hud_fontsize_y; // move to the end of the table
932 pos_y += 1.25 * hud_fontsize_y; // move empty row (out of the table)
937 float HUD_WouldDrawScoreboard() {
938 if (autocvar__hud_configure)
940 else if (scoreboard_showscores)
942 else if (intermission == 1)
944 else if (intermission == 2)
946 else if (spectatee_status != -1 && getstati(STAT_HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS)
948 else if (scoreboard_showscores_force)
953 float average_accuracy;
954 vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
957 float weapon_cnt = WEP_COUNT - 3; // either minstanex/nex are hidden, no port-o-launch, no tuba
959 if(autocvar_scoreboard_accuracy_doublerows)
964 float fontsize = height * 1/3;
965 float weapon_height = height * 2/3;
966 float weapon_width = sbwidth / weapon_cnt;
967 float g_instagib = 0;
969 drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
970 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
971 vector tmp = '0 0 0';
973 tmp_y = height * rows;
976 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
978 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
979 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
981 // column highlighting
982 for(i = 0; i < weapon_cnt/rows; ++i)
985 drawfill(pos + '1 0 0' * weapon_width * rows * i, '0 1 0' * height * rows + '1 0 0' * weapon_width * rows, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
989 for(i = 0; i < rows; ++i)
991 drawfill(pos + '0 1 0' * weapon_height + '0 1 0' * height * i, '1 0 0' * sbwidth + '0 1 0' * fontsize, '1 1 1', scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
994 average_accuracy = 0;
995 float weapons_with_stats;
996 weapons_with_stats = 0;
998 pos_x += weapon_width / 2;
1000 if(switchweapon == WEP_MINSTANEX)
1001 g_instagib = 1; // TODO: real detection for instagib?
1004 if(autocvar_scoreboard_accuracy_nocolors)
1007 Accuracy_LoadColors();
1009 for(i = WEP_FIRST; i <= WEP_LAST; ++i)
1011 self = get_weaponinfo(i);
1014 if ((i == WEP_NEX && g_instagib) || i == WEP_PORTO || (i == WEP_MINSTANEX && !g_instagib) || i == WEP_TUBA) // skip port-o-launch, vortex || vaporizer and tuba
1016 weapon_stats = weapon_accuracy[i-WEP_FIRST];
1019 if(weapon_stats >= 0)
1020 weapon_alpha = scoreboard_alpha_fg;
1022 weapon_alpha = 0.2 * scoreboard_alpha_fg;
1025 drawpic_aspect_skin(pos, strcat("weapon", self.netname), '1 0 0' * weapon_width + '0 1 0' * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
1027 if(weapon_stats >= 0) {
1028 weapons_with_stats += 1;
1029 average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
1032 s = sprintf(_("%d%%"), weapon_stats*100);
1035 padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
1037 if(!autocvar_scoreboard_accuracy_nocolors)
1038 rgb = Accuracy_GetColor(weapon_stats);
1040 drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1042 pos_x += weapon_width * rows;
1043 if(rows == 2 && i == 6) {
1049 if(weapons_with_stats)
1050 average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
1053 pos_x -= weapon_width / 2;
1057 pos_y += 1.25 * hud_fontsize_y;
1061 vector HUD_DrawKeyValue(vector pos, string key, string value) {
1063 pos_x += hud_fontsize_x * 0.25;
1064 drawstring(pos, key, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1065 pos_x = xmax - stringwidth(value, FALSE, hud_fontsize) - hud_fontsize_x * 0.25;
1066 drawstring(pos, value, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1068 pos_y+= hud_fontsize_y;
1073 vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
1074 float stat_secrets_found, stat_secrets_total;
1075 float stat_monsters_killed, stat_monsters_total;
1079 // get monster stats
1080 stat_monsters_killed = getstatf(STAT_MONSTERS_KILLED);
1081 stat_monsters_total = getstatf(STAT_MONSTERS_TOTAL);
1083 // get secrets stats
1084 stat_secrets_found = getstatf(STAT_SECRETS_FOUND);
1085 stat_secrets_total = getstatf(STAT_SECRETS_TOTAL);
1087 // get number of rows
1088 if(stat_secrets_total)
1090 if(stat_monsters_total)
1093 // if no rows, return
1097 // draw table header
1098 drawstring(pos, _("Map stats:"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1099 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
1102 vector tmp = '0 0 0';
1104 tmp_y = hud_fontsize_y * rows;
1107 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1109 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1110 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1113 if(stat_monsters_total)
1115 val = sprintf("%d/%d", stat_monsters_killed, stat_monsters_total);
1116 pos = HUD_DrawKeyValue(pos, _("Monsters killed:"), val);
1120 if(stat_secrets_total)
1122 val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
1123 pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val);
1127 pos_y += 1.25 * hud_fontsize_y;
1132 vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_size)
1135 RANKINGS_RECEIVED_CNT = 0;
1136 for (i=RANKINGS_CNT-1; i>=0; --i)
1138 ++RANKINGS_RECEIVED_CNT;
1140 if (RANKINGS_RECEIVED_CNT == 0)
1144 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
1146 hl_rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
1147 hl_rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
1148 hl_rgb_z = autocvar_scoreboard_color_bg_b + 0.5;
1150 pos_y += hud_fontsize_y;
1151 drawstring(pos, _("Rankings"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1152 pos_y += hud_fontsize_y + autocvar_scoreboard_border_thickness;
1153 vector tmp = '0 0 0';
1155 tmp_y = 1.25 * hud_fontsize_y * RANKINGS_RECEIVED_CNT;
1158 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1160 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1161 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1164 for(i = 0; i<RANKINGS_RECEIVED_CNT; ++i)
1171 n = grecordholder[i];
1172 p = count_ordinal(i+1);
1173 if(grecordholder[i] == GetPlayerName(player_localnum))
1174 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
1175 else if(!mod(i, 2) && scoreboard_highlight)
1176 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
1177 drawstring(pos, p, '1 1 0' * hud_fontsize_y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1178 drawstring(pos + '3 0 0' * hud_fontsize_y, TIME_ENCODED_TOSTRING(t), '1 1 0' * hud_fontsize_y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1179 drawcolorcodedstring(pos + '8 0 0' * hud_fontsize_y, n, '1 1 0' * hud_fontsize_y, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1180 pos_y += 1.25 * hud_fontsize_y;
1182 pos_y += autocvar_scoreboard_border_thickness;
1187 float hud_woulddrawscoreboard_prev;
1188 float hud_woulddrawscoreboard_change; // "time" at which HUD_WouldDrawScoreboard() changed
1189 void HUD_DrawScoreboard()
1191 float hud_woulddrawscoreboard;
1192 hud_woulddrawscoreboard = scoreboard_active;
1193 if(hud_woulddrawscoreboard != hud_woulddrawscoreboard_prev) {
1194 hud_woulddrawscoreboard_change = time;
1195 hud_woulddrawscoreboard_prev = hud_woulddrawscoreboard;
1198 if(hud_woulddrawscoreboard) {
1199 float scoreboard_fadeinspeed = autocvar_scoreboard_fadeinspeed;
1200 if (scoreboard_fadeinspeed)
1201 scoreboard_fade_alpha = bound (0, (time - hud_woulddrawscoreboard_change) * scoreboard_fadeinspeed, 1);
1203 scoreboard_fade_alpha = 1;
1206 float scoreboard_fadeoutspeed = autocvar_scoreboard_fadeoutspeed;
1207 if (scoreboard_fadeoutspeed)
1208 scoreboard_fade_alpha = bound (0, (1/scoreboard_fadeoutspeed - (time - hud_woulddrawscoreboard_change)) * scoreboard_fadeoutspeed, 1);
1210 scoreboard_fade_alpha = 0;
1213 if (!scoreboard_fade_alpha)
1216 HUD_UpdatePlayerTeams();
1218 scoreboard_alpha_bg = autocvar_scoreboard_alpha_bg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1219 scoreboard_alpha_fg = autocvar_scoreboard_alpha_fg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1220 scoreboard_highlight = autocvar_scoreboard_highlight;
1221 scoreboard_highlight_alpha = autocvar_scoreboard_highlight_alpha * scoreboard_alpha_fg;
1222 scoreboard_highlight_alpha_self = autocvar_scoreboard_highlight_alpha_self * scoreboard_alpha_fg;
1223 scoreboard_alpha_name = autocvar_scoreboard_alpha_name * scoreboard_alpha_fg;
1224 scoreboard_alpha_name_self = autocvar_scoreboard_alpha_name_self * scoreboard_alpha_fg;
1226 vector rgb, pos, tmp;
1230 xmin = (autocvar_scoreboard_offset_left * vid_conwidth);
1231 ymin = max((autocvar_con_notify * autocvar_con_notifysize), (autocvar_scoreboard_offset_vertical * vid_conwidth));
1233 xmax = ((1 - autocvar_scoreboard_offset_right) * vid_conwidth);
1234 ymax = (vid_conheight - ymin);
1236 sbwidth = xmax - xmin;
1238 // Initializes position
1244 vector sb_heading_fontsize;
1245 sb_heading_fontsize = hud_fontsize * 2;
1246 draw_beginBoldFont();
1247 drawstring(pos, _("Scoreboard"), sb_heading_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1250 pos_y += sb_heading_fontsize_y + hud_fontsize_y * 0.25;
1252 // Draw the scoreboard
1253 vector bg_size = draw_getimagesize("gfx/scoreboard/scoreboard_bg") * autocvar_scoreboard_bg_scale;
1257 vector team_score_baseoffset;
1258 team_score_baseoffset = eY * (2 * autocvar_scoreboard_border_thickness + hud_fontsize_y) - eX * (autocvar_scoreboard_border_thickness + hud_fontsize_x * 0.25);
1259 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1261 if(tm.team == NUM_SPECTATOR)
1264 draw_beginBoldFont();
1265 rgb = Team_ColorRGB(tm.team);
1266 str = ftos(tm.(teamscores[ts_primary]));
1267 drawstring(pos + team_score_baseoffset - eX * stringwidth(str, FALSE, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1269 if(ts_primary != ts_secondary)
1271 str = ftos(tm.(teamscores[ts_secondary]));
1272 drawstring(pos + team_score_baseoffset - eX * stringwidth(str, FALSE, hud_fontsize) + eY * hud_fontsize_y * 1.5, str, hud_fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1276 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1282 rgb_x = autocvar_scoreboard_color_bg_r;
1283 rgb_y = autocvar_scoreboard_color_bg_g;
1284 rgb_z = autocvar_scoreboard_color_bg_b;
1291 rgb_x = autocvar_scoreboard_color_bg_r;
1292 rgb_y = autocvar_scoreboard_color_bg_g;
1293 rgb_z = autocvar_scoreboard_color_bg_b;
1295 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1297 if(tm.team == NUM_SPECTATOR)
1300 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1304 if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE) {
1305 if(race_speedaward) {
1306 drawcolorcodedstring(pos, sprintf(_("Speed award: %d ^7(%s^7)"), race_speedaward, race_speedaward_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1307 pos_y += 1.25 * hud_fontsize_y;
1309 if(race_speedaward_alltimebest) {
1310 drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1311 pos_y += 1.25 * hud_fontsize_y;
1313 pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
1315 else if(autocvar_scoreboard_accuracy && spectatee_status == 0 && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL) {
1317 pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size);
1319 pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size);
1324 pos = HUD_DrawMapStats(pos, Team_ColorRGB(myteam), bg_size);
1326 pos = HUD_DrawMapStats(pos, rgb, bg_size);
1332 for(pl = players.sort_next; pl; pl = pl.sort_next)
1334 if(pl.team != NUM_SPECTATOR)
1336 pos_y += 1.25 * hud_fontsize_y;
1337 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), specs);
1343 draw_beginBoldFont();
1344 drawstring(tmp, _("Spectators"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1346 pos_y += 1.25 * hud_fontsize_y;
1349 // Print info string
1351 str = sprintf(_("playing ^3%s^7 on ^2%s^7"), MapInfo_Type_ToText(gametype), shortmapname);
1352 tl = getstatf(STAT_TIMELIMIT);
1353 fl = getstatf(STAT_FRAGLIMIT);
1354 ll = getstatf(STAT_LEADLIMIT);
1355 if(gametype == MAPINFO_TYPE_LMS)
1358 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1363 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1367 str = strcat(str, _(" or"));
1370 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], fl),
1371 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1372 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1373 TranslateScoresLabel(teamscores_label[ts_primary])));
1377 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(scores_flags[ps_primary], fl),
1378 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1379 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1380 TranslateScoresLabel(scores_label[ps_primary])));
1385 if(tl > 0 || fl > 0)
1386 str = strcat(str, _(" or"));
1389 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], ll),
1390 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1391 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1392 TranslateScoresLabel(teamscores_label[ts_primary])));
1396 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(scores_flags[ps_primary], ll),
1397 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1398 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1399 TranslateScoresLabel(scores_label[ps_primary])));
1404 pos_y += 1.2 * hud_fontsize_y;
1405 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1407 // print information about respawn status
1408 float respawn_time = getstatf(STAT_RESPAWN_TIME);
1412 if(respawn_time < 0)
1414 // a negative number means we are awaiting respawn, time value is still the same
1415 respawn_time *= -1; // remove mark now that we checked it
1416 respawn_time = max(time, respawn_time); // don't show a negative value while the server is respawning the player (lag)
1418 str = sprintf(_("^1Respawning in ^3%s^1..."),
1419 (autocvar_scoreboard_respawntime_decimals ?
1420 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1422 count_seconds(respawn_time - time)
1426 else if(time < respawn_time)
1428 str = sprintf(_("You are dead, wait ^3%s^7 before respawning"),
1429 (autocvar_scoreboard_respawntime_decimals ?
1430 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1432 count_seconds(respawn_time - time)
1436 else if(time >= respawn_time)
1437 str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
1439 pos_y += 1.2 * hud_fontsize_y;
1440 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1443 scoreboard_bottom = pos_y + 2 * hud_fontsize_y;