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 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 "deaths": return CTX(_("SCO^deaths"));
23 case "destroyed": return CTX(_("SCO^destroyed"));
24 case "drops": return CTX(_("SCO^drops"));
25 case "faults": return CTX(_("SCO^faults"));
26 case "fckills": return CTX(_("SCO^fckills"));
27 case "goals": return CTX(_("SCO^goals"));
28 case "kckills": return CTX(_("SCO^kckills"));
29 case "kdratio": return CTX(_("SCO^kdratio"));
30 case "k/d": return CTX(_("SCO^k/d"));
31 case "kd": return CTX(_("SCO^kd"));
32 case "kdr": return CTX(_("SCO^kdr"));
33 case "kills": return CTX(_("SCO^kills"));
34 case "laps": return CTX(_("SCO^laps"));
35 case "lives": return CTX(_("SCO^lives"));
36 case "losses": return CTX(_("SCO^losses"));
37 case "name": return CTX(_("SCO^name"));
38 case "nick": return CTX(_("SCO^nick"));
39 case "objectives": return CTX(_("SCO^objectives"));
40 case "pickups": return CTX(_("SCO^pickups"));
41 case "ping": return CTX(_("SCO^ping"));
42 case "pl": return CTX(_("SCO^pl"));
43 case "pushes": return CTX(_("SCO^pushes"));
44 case "rank": return CTX(_("SCO^rank"));
45 case "returns": return CTX(_("SCO^returns"));
46 case "revivals": return CTX(_("SCO^revivals"));
47 case "score": return CTX(_("SCO^score"));
48 case "suicides": return CTX(_("SCO^suicides"));
49 case "takes": return CTX(_("SCO^takes"));
50 case "ticks": return CTX(_("SCO^ticks"));
56 void HUD_FinaleOverlay()
59 pos_x = (vid_conwidth - 1)/2;
63 //drawpic(pos, "gfx/finale", '0 0 0', '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
65 //drawstring(pos, "END", hud_fontsize, '1 1 1', 1, DRAWFLAG_NORMAL);
69 void Cmd_HUD_SetFields(float argc);
74 ps_primary = ps_secondary = ts_primary = ts_secondary = -1;
75 for(i = 0; i < MAX_SCORE; ++i)
77 f = (scores_flags[i] & SFL_SORT_PRIO_MASK);
78 if(f == SFL_SORT_PRIO_PRIMARY)
80 if(f == SFL_SORT_PRIO_SECONDARY)
83 if(ps_secondary == -1)
84 ps_secondary = ps_primary;
86 for(i = 0; i < MAX_TEAMSCORE; ++i)
88 f = (teamscores_flags[i] & SFL_SORT_PRIO_MASK);
89 if(f == SFL_SORT_PRIO_PRIMARY)
91 if(f == SFL_SORT_PRIO_SECONDARY)
94 if(ts_secondary == -1)
95 ts_secondary = ts_primary;
100 void HUD_UpdatePlayerPos(entity pl);
101 float SetTeam(entity pl, float Team);
103 void HUD_UpdatePlayerTeams()
110 for(pl = players.sort_next; pl; pl = pl.sort_next)
113 Team = GetPlayerColor(pl.sv_entnum);
114 if(SetTeam(pl, Team))
117 HUD_UpdatePlayerPos(pl);
121 pl = players.sort_next;
126 print(strcat("PNUM: ", ftos(num), "\n"));
131 float HUD_ComparePlayerScores(entity left, entity right)
134 vl = GetPlayerColor(left.sv_entnum);
135 vr = GetPlayerColor(right.sv_entnum);
138 vl = COLOR_SPECTATOR;
140 vr = COLOR_SPECTATOR;
147 if(vl == COLOR_SPECTATOR)
149 // FIRST the one with scores (spectators), THEN the ones without (downloaders)
151 if(!left.gotscores && right.gotscores)
156 vl = left.scores[ps_primary];
157 vr = right.scores[ps_primary];
158 if(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)
160 if(vl == 0 && vr != 0)
162 if(vl != 0 && vr == 0)
166 return IS_INCREASING(scores_flags[ps_primary]);
168 return IS_DECREASING(scores_flags[ps_primary]);
170 vl = left.scores[ps_secondary];
171 vr = right.scores[ps_secondary];
172 if(scores_flags[ps_secondary] & SFL_ZERO_IS_WORST)
174 if(vl == 0 && vr != 0)
176 if(vl != 0 && vr == 0)
180 return IS_INCREASING(scores_flags[ps_secondary]);
182 return IS_DECREASING(scores_flags[ps_secondary]);
187 void HUD_UpdatePlayerPos(entity player)
189 for(other = player.sort_next; other && HUD_ComparePlayerScores(player, other); other = player.sort_next)
191 SORT_SWAP(player, other);
193 for(other = player.sort_prev; other != players && HUD_ComparePlayerScores(other, player); other = player.sort_prev)
195 SORT_SWAP(other, player);
199 float HUD_CompareTeamScores(entity left, entity right)
203 if(left.team == COLOR_SPECTATOR)
205 if(right.team == COLOR_SPECTATOR)
208 vl = left.teamscores[ts_primary];
209 vr = right.teamscores[ts_primary];
211 return IS_INCREASING(teamscores_flags[ts_primary]);
213 return IS_DECREASING(teamscores_flags[ts_primary]);
215 vl = left.teamscores[ts_secondary];
216 vr = right.teamscores[ts_secondary];
218 return IS_INCREASING(teamscores_flags[ts_secondary]);
220 return IS_DECREASING(teamscores_flags[ts_secondary]);
225 void HUD_UpdateTeamPos(entity Team)
227 for(other = Team.sort_next; other && HUD_CompareTeamScores(Team, other); other = Team.sort_next)
229 SORT_SWAP(Team, other);
231 for(other = Team.sort_prev; other != teams && HUD_CompareTeamScores(other, Team); other = Team.sort_prev)
233 SORT_SWAP(other, Team);
237 void Cmd_HUD_Help(float argc)
239 print(_("You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"));
240 print(_("^3|---------------------------------------------------------------|\n"));
241 print(_("Usage:\n"));
242 print(_("^2scoreboard_columns_set default\n"));
243 print(_("^2scoreboard_columns_set ^7field1 field2 ...\n"));
244 print(_("The following field names are recognized (case insensitive):\n"));
245 print(_("You can use a ^3|^7 to start the right-aligned fields.\n\n"));
247 print(_("^3name^7 or ^3nick^7 Name of a player\n"));
248 print(_("^3ping^7 Ping time\n"));
249 print(_("^3pl^7 Packet loss\n"));
250 print(_("^3kills^7 Number of kills\n"));
251 print(_("^3deaths^7 Number of deaths\n"));
252 print(_("^3suicides^7 Number of suicides\n"));
253 print(_("^3frags^7 kills - suicides\n"));
254 print(_("^3kd^7 The kill-death ratio\n"));
255 print(_("^3caps^7 How often a flag (CTF) or a key (KeyHunt) was captured\n"));
256 print(_("^3pickups^7 How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\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/kills -teams,lms/deaths +freezetag/deaths -teams,lms,race,ka/suicides +freezetag/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, have_primary, have_secondary, have_separator;
310 // TODO: re enable with gametype dependant cvars?
311 if(argc < 3) // no arguments provided
312 argc = tokenizebyseparator(strcat("x ", autocvar_scoreboard_columns), " ");
315 argc = tokenizebyseparator(strcat("x ", HUD_DefaultColumnLayout()), " ");
319 if(argv(2) == "default")
320 argc = tokenizebyseparator(strcat("x ", HUD_DefaultColumnLayout()), " ");
321 else if(argv(2) == "all")
324 s = "ping pl color 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("x ", s), " ");
342 hud_fontsize = HUD_GetFontsize("hud_fontsize");
344 for(i = 0; i < argc - 2; ++i)
350 if(substring(str, 0, 1) == "?")
353 str = substring(str, 1, strlen(str) - 1);
356 slash = strstrofs(str, "/", 0);
359 pattern = substring(str, 0, slash);
360 str = substring(str, slash + 1, strlen(str) - (slash + 1));
362 if not(isGametypeInFilter(gametype, teamplay, FALSE, pattern))
366 strunzone(hud_title[hud_num_fields]);
367 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(str));
368 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
369 str = strtolower(str);
372 hud_field[hud_num_fields] = SP_PING;
373 } else if(str == "pl") {
374 hud_field[hud_num_fields] = SP_PL;
375 } else if(str == "kd" || str == "kdr" || str == "kdratio" || str == "k/d") {
376 hud_field[hud_num_fields] = SP_KDRATIO;
377 } else if(str == "name" || str == "nick") {
378 hud_field[hud_num_fields] = SP_NAME;
380 } else if(str == "|") {
381 hud_field[hud_num_fields] = SP_SEPARATOR;
384 for(j = 0; j < MAX_SCORE; ++j)
385 if(str == strtolower(scores_label[j]))
386 goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
395 print(sprintf("^1Error:^7 Unknown score field: '%s'\n", str));
399 hud_field[hud_num_fields] = j;
402 if(j == ps_secondary)
406 if(hud_num_fields >= MAX_HUD_FIELDS)
410 if(scores_flags[ps_primary] & SFL_ALLOW_HIDE)
412 if(scores_flags[ps_secondary] & SFL_ALLOW_HIDE)
414 if(ps_primary == ps_secondary)
416 missing = (!have_primary) + (!have_secondary) + (!have_separator) + (!have_name);
418 if(hud_num_fields+missing < MAX_HUD_FIELDS)
422 strunzone(hud_title[hud_num_fields]);
423 for(i = hud_num_fields; i > 0; --i)
425 hud_title[i] = hud_title[i-1];
426 hud_size[i] = hud_size[i-1];
427 hud_field[i] = hud_field[i-1];
429 hud_title[0] = strzone(TranslateScoresLabel("name"));
430 hud_field[0] = SP_NAME;
432 print(sprintf(_("fixed missing field '%s'\n"), "name"));
436 strunzone(hud_title[hud_num_fields]);
437 for(i = hud_num_fields; i > 1; --i)
439 hud_title[i] = hud_title[i-1];
440 hud_size[i] = hud_size[i-1];
441 hud_field[i] = hud_field[i-1];
443 hud_title[1] = strzone("|");
444 hud_field[1] = SP_SEPARATOR;
445 hud_size[1] = stringwidth("|", FALSE, hud_fontsize);
447 print(sprintf(_("fixed missing field '%s'\n"), "|"));
450 else if(!have_separator)
452 strunzone(hud_title[hud_num_fields]);
453 hud_title[hud_num_fields] = strzone("|");
454 hud_size[hud_num_fields] = stringwidth("|", FALSE, hud_fontsize);
455 hud_field[hud_num_fields] = SP_SEPARATOR;
457 print(sprintf(_("fixed missing field '%s'\n"), "|"));
461 strunzone(hud_title[hud_num_fields]);
462 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_secondary]));
463 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
464 hud_field[hud_num_fields] = ps_secondary;
466 print(sprintf(_("fixed missing field '%s'\n"), scores_label[ps_secondary]));
470 strunzone(hud_title[hud_num_fields]);
471 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_primary]));
472 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
473 hud_field[hud_num_fields] = ps_primary;
475 print(sprintf(_("fixed missing field '%s'\n"), scores_label[ps_primary]));
479 hud_field[hud_num_fields] = SP_END;
483 vector hud_field_rgb;
484 string hud_field_icon0;
485 string hud_field_icon1;
486 string hud_field_icon2;
487 vector hud_field_icon0_rgb;
488 vector hud_field_icon1_rgb;
489 vector hud_field_icon2_rgb;
490 float hud_field_icon0_alpha;
491 float hud_field_icon1_alpha;
492 float hud_field_icon2_alpha;
493 string HUD_GetField(entity pl, float field)
495 float tmp, num, denom, f;
497 hud_field_rgb = '1 1 1';
498 hud_field_icon0 = "";
499 hud_field_icon1 = "";
500 hud_field_icon2 = "";
501 hud_field_icon0_rgb = '1 1 1';
502 hud_field_icon1_rgb = '1 1 1';
503 hud_field_icon2_rgb = '1 1 1';
504 hud_field_icon0_alpha = 1;
505 hud_field_icon1_alpha = 1;
506 hud_field_icon2_alpha = 1;
511 return "\xEE\x82\x8D\xEE\x82\x8D\xEE\x82\x8D"; // >>> sign
512 //str = getplayerkeyvalue(pl.sv_entnum, "ping");
516 tmp = max(0, min(220, f-80)) / 220;
517 hud_field_rgb = '1 1 1' - '0 1 1'*tmp;
523 f = pl.ping_packetloss;
524 tmp = pl.ping_movementloss;
525 if(f == 0 && tmp == 0)
527 str = ftos(ceil(f * 100));
529 str = strcat(str, "~", ftos(ceil(tmp * 100)));
530 tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
531 hud_field_rgb = '1 0.5 0.5' - '0 0.5 0.5'*tmp;
535 if(ready_waiting && pl.ready)
537 hud_field_icon0 = "gfx/scoreboard/player_ready";
541 f = stof(getplayerkeyvalue(pl.sv_entnum, "colors"));
543 hud_field_icon0 = "gfx/scoreboard/playercolor_base";
544 hud_field_icon1 = "gfx/scoreboard/playercolor_shirt";
545 hud_field_icon1_rgb = colormapPaletteColor(floor(f / 16), 0);
546 hud_field_icon2 = "gfx/scoreboard/playercolor_pants";
547 hud_field_icon2_rgb = colormapPaletteColor(mod(f, 16), 1);
550 return GetPlayerName(pl.sv_entnum);
553 f = pl.(scores[SP_KILLS]);
554 f -= pl.(scores[SP_SUICIDES]);
558 num = pl.(scores[SP_KILLS]);
559 denom = pl.(scores[SP_DEATHS]);
562 hud_field_rgb = '0 1 0';
563 str = sprintf("%d", num);
564 } else if(num <= 0) {
565 hud_field_rgb = '1 0 0';
566 str = sprintf("%.1f", num/denom);
568 str = sprintf("%.1f", num/denom);
572 tmp = pl.(scores[field]);
573 f = scores_flags[field];
574 if(field == ps_primary)
575 hud_field_rgb = '1 1 0';
576 else if(field == ps_secondary)
577 hud_field_rgb = '0 1 1';
579 hud_field_rgb = '1 1 1';
580 return ScoreString(f, tmp);
585 float xmin, xmax, ymin, ymax, sbwidth;
586 float hud_fixscoreboardcolumnwidth_len;
587 float hud_fixscoreboardcolumnwidth_iconlen;
588 float hud_fixscoreboardcolumnwidth_marginlen;
590 string HUD_FixScoreboardColumnWidth(float i, string str)
594 field = hud_field[i];
596 hud_fixscoreboardcolumnwidth_iconlen = 0;
598 if(hud_field_icon0 != "")
600 sz = draw_getimagesize(hud_field_icon0);
602 if(hud_fixscoreboardcolumnwidth_iconlen < f)
603 hud_fixscoreboardcolumnwidth_iconlen = f;
606 if(hud_field_icon1 != "")
608 sz = draw_getimagesize(hud_field_icon1);
610 if(hud_fixscoreboardcolumnwidth_iconlen < f)
611 hud_fixscoreboardcolumnwidth_iconlen = f;
614 if(hud_field_icon2 != "")
616 sz = draw_getimagesize(hud_field_icon2);
618 if(hud_fixscoreboardcolumnwidth_iconlen < f)
619 hud_fixscoreboardcolumnwidth_iconlen = f;
622 hud_fixscoreboardcolumnwidth_iconlen *= hud_fontsize_y / hud_fontsize_x; // fix icon aspect
624 if(hud_fixscoreboardcolumnwidth_iconlen != 0)
625 hud_fixscoreboardcolumnwidth_marginlen = stringwidth(" ", FALSE, hud_fontsize);
627 hud_fixscoreboardcolumnwidth_marginlen = 0;
629 if(field == SP_NAME) // name gets all remaining space
632 namesize = sbwidth;// / hud_fontsize_x;
633 for(j = 0; j < hud_num_fields; ++j)
635 if (hud_field[i] != SP_SEPARATOR)
636 namesize -= hud_size[j] + hud_fontsize_x;
637 namesize += hud_fontsize_x;
638 hud_size[i] = namesize;
640 if (hud_fixscoreboardcolumnwidth_iconlen != 0)
641 namesize -= hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
642 str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
643 hud_fixscoreboardcolumnwidth_len = stringwidth(str, TRUE, hud_fontsize);
646 hud_fixscoreboardcolumnwidth_len = stringwidth(str, FALSE, hud_fontsize);
648 f = hud_fixscoreboardcolumnwidth_len + hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
655 void HUD_PrintScoreboardItem(vector pos, entity pl, float is_self, float pl_number)
658 rgb = GetTeamRGB(pl.team);
662 is_spec = (GetPlayerColor(pl.sv_entnum) == COLOR_SPECTATOR);
664 if((rgb == '1 1 1') && (!is_spec)) {
665 rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
666 rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
667 rgb_z = autocvar_scoreboard_color_bg_b + 0.5; }
671 tmp_y = hud_fontsize_y * 1.25;
674 // alternated rows highlighting
676 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
677 else if((scoreboard_highlight) && (!mod(pl_number,2)))
678 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
682 for(i = 0; i < hud_num_fields; ++i)
684 field = hud_field[i];
685 if(field == SP_SEPARATOR)
688 if(is_spec && field != SP_NAME && field != SP_PING) {
689 pos_x += hud_size[i] + hud_fontsize_x;
692 str = HUD_GetField(pl, field);
693 str = HUD_FixScoreboardColumnWidth(i, str);
695 pos_x += hud_size[i] + hud_fontsize_x;
697 if(field == SP_NAME) {
698 tmp_x = hud_size[i] - hud_fontsize_x*hud_fixscoreboardcolumnwidth_iconlen - hud_fixscoreboardcolumnwidth_marginlen + hud_fontsize_x;
700 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
702 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
704 tmp_x = hud_fixscoreboardcolumnwidth_len + hud_fontsize_x;
706 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
708 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
711 tmp_x = hud_size[i] + hud_fontsize_x;
712 if(hud_field_icon0 != "")
714 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);
716 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);
717 if(hud_field_icon1 != "")
719 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);
721 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);
722 if(hud_field_icon2 != "")
724 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);
726 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);
729 if(hud_field[i] == SP_SEPARATOR)
732 for(i = hud_num_fields-1; i > 0; --i)
734 field = hud_field[i];
735 if(field == SP_SEPARATOR)
738 if(is_spec && field != SP_NAME && field != SP_PING) {
739 pos_x -= hud_size[i] + hud_fontsize_x;
743 str = HUD_GetField(pl, field);
744 str = HUD_FixScoreboardColumnWidth(i, str);
746 if(field == SP_NAME) {
747 tmp_x = hud_fixscoreboardcolumnwidth_len; // left or right aligned? let's put it right...
749 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
751 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
753 tmp_x = hud_fixscoreboardcolumnwidth_len;
755 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
757 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
761 if(hud_field_icon0 != "")
763 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);
765 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);
766 if(hud_field_icon1 != "")
768 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);
770 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);
771 if(hud_field_icon2 != "")
773 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);
775 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);
776 pos_x -= hud_size[i] + hud_fontsize_x;
782 * HUD_Scoreboard_MakeTable
784 * Makes a table for a team (for all playing players in DM) and fills it
787 vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
789 float body_table_height, i;
790 vector tmp, column_dim;
793 body_table_height = 1.25 * hud_fontsize_y * max(1, tm.team_size); // no player? show 1 empty line
795 pos_y += autocvar_scoreboard_border_thickness;
799 tmp_y = 1.25 * hud_fontsize_y;
803 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, (rgb * autocvar_scoreboard_color_bg_team) + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
805 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
808 tmp_y += autocvar_scoreboard_border_thickness;
809 tmp_y += body_table_height;
810 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // more transparency for the scoreboard
812 // separator header/table
813 pos_y += 1.25 * hud_fontsize_y;
814 tmp_y = autocvar_scoreboard_border_thickness;
815 drawfill(pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
817 pos_y += autocvar_scoreboard_border_thickness;
820 tmp_y = body_table_height;
822 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
824 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
826 // anyway, apply some color
827 //drawfill(pos, tmp + '2 0 0', rgb, 0.1, DRAWFLAG_NORMAL);
829 // go back to the top to make alternated columns highlighting and to print the strings
830 pos_y -= 1.25 * hud_fontsize_y;
831 pos_y -= autocvar_scoreboard_border_thickness;
835 if (scoreboard_highlight)
837 column_dim_y = 1.25 * hud_fontsize_y; // header
838 column_dim_y += autocvar_scoreboard_border_thickness;
839 column_dim_y += body_table_height;
842 // print the strings of the columns headers and draw the columns
843 for(i = 0; i < hud_num_fields; ++i)
845 if(hud_field[i] == SP_SEPARATOR)
847 column_dim_x = hud_size[i] + hud_fontsize_x;
848 if (scoreboard_highlight)
851 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
853 drawstring(pos, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
854 pos_x += column_dim_x;
856 if(hud_field[i] == SP_SEPARATOR)
860 for(i = hud_num_fields-1; i > 0; --i)
862 if(hud_field[i] == SP_SEPARATOR)
865 pos_x -= hud_size[i];
867 if (scoreboard_highlight)
871 if (i == hud_num_fields-1)
872 column_dim_x = hud_size[i] + hud_fontsize_x / 2 + 1;
874 column_dim_x = hud_size[i] + hud_fontsize_x;
875 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
879 tmp_x = stringwidth(hud_title[i], FALSE, hud_fontsize);
880 tmp_x = (hud_size[i] - tmp_x);
881 drawstring(pos + tmp, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
882 pos_x -= hud_fontsize_x;
887 pos_y += 1.25 * hud_fontsize_y; // skip the header
888 pos_y += autocvar_scoreboard_border_thickness;
890 // fill the table and draw the rows
893 for(pl = players.sort_next; pl; pl = pl.sort_next)
895 if(pl.team != tm.team)
897 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
898 pos_y += 1.25 * hud_fontsize_y;
902 for(pl = players.sort_next; pl; pl = pl.sort_next)
904 if(pl.team == COLOR_SPECTATOR)
906 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
907 pos_y += 1.25 * hud_fontsize_y;
912 pos_y += 1.25 * hud_fontsize_y; // move to the end of the table
913 pos_y += 1.25 * hud_fontsize_y; // move empty row (out of the table)
918 float HUD_WouldDrawScoreboard() {
919 if (autocvar__hud_configure)
921 else if (scoreboard_showscores)
923 else if (intermission == 1)
925 else if (intermission == 2)
927 else if (spectatee_status != -1 && getstati(STAT_HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != GAME_CTS)
929 else if (scoreboard_showscores_force)
935 float average_accuracy;
936 vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
939 float weapon_cnt = WEP_COUNT - 3; // either minstanex/nex are hidden, no port-o-launch, no tuba
941 if(autocvar_scoreboard_accuracy_doublerows)
946 float fontsize = height * 1/3;
947 float weapon_height = height * 2/3;
948 float weapon_width = sbwidth / weapon_cnt;
950 drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
951 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
954 tmp_y = height * rows;
957 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
959 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
960 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
962 // column highlighting
963 for(i = 0; i < weapon_cnt/rows; ++i)
966 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);
970 for(i = 0; i < rows; ++i)
972 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);
975 average_accuracy = 0;
976 float weapons_with_stats;
977 weapons_with_stats = 0;
979 pos_x += weapon_width / 2;
981 if(switchweapon == WEP_MINSTANEX)
982 g_minstagib = 1; // TODO: real detection for minstagib?
988 else if (acc_col_x[0] == -1)
989 for (i = 0; i < acc_levels; ++i)
990 acc_col[i] = stov(cvar_string(strcat("accuracy_color", ftos(i))));
992 for(i = WEP_FIRST; i <= WEP_LAST; ++i)
994 self = get_weaponinfo(i);
997 if ((i == WEP_NEX && g_minstagib) || i == WEP_PORTO || (i == WEP_MINSTANEX && !g_minstagib) || i == WEP_TUBA) // skip port-o-launch, nex || minstanex and tuba
999 weapon_stats = weapon_accuracy[i-WEP_FIRST];
1002 if(weapon_stats >= 0)
1003 weapon_alpha = scoreboard_alpha_fg;
1005 weapon_alpha = 0.2 * scoreboard_alpha_fg;
1008 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);
1010 if(weapon_stats >= 0) {
1011 weapons_with_stats += 1;
1012 average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
1015 s = sprintf(_("%d%%"), weapon_stats*100);
1018 padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
1022 // find the max level lower than weapon_stats
1025 while ( j && weapon_stats < acc_lev[j] )
1028 // inject color j+1 in color j, how much depending on how much weapon_stats is higher than level j
1030 factor = (weapon_stats - acc_lev[j]) / (acc_lev[j+1] - acc_lev[j]);
1032 rgb = rgb + factor * (acc_col[j+1] - rgb);
1035 drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1037 pos_x += weapon_width * rows;
1038 if(rows == 2 && i == 6) {
1044 if(weapons_with_stats)
1045 average_accuracy = floor(average_accuracy / weapons_with_stats);
1048 pos_x -= weapon_width / 2;
1052 pos_y += 1.25 * hud_fontsize_y;
1056 vector HUD_DrawKeyValue(vector pos, string key, string value) {
1058 pos_x += hud_fontsize_x * 0.25;
1059 drawstring(pos, key, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1060 pos_x = xmax - stringwidth(value, FALSE, hud_fontsize) - hud_fontsize_x * 0.25;
1061 drawstring(pos, value, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1063 pos_y+= hud_fontsize_y;
1068 vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
1069 float stat_secrets_found, stat_secrets_total;
1073 // get secrets stats
1074 stat_secrets_found = getstatf(STAT_SECRETS_FOUND);
1075 stat_secrets_total = getstatf(STAT_SECRETS_TOTAL);
1077 // get number of rows
1078 rows = (stat_secrets_total ? 1 : 0);
1080 // if no rows, return
1084 // draw table header
1085 drawstring(pos, _("Map stats:"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1086 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
1091 tmp_y = hud_fontsize_y * rows;
1094 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1096 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1097 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1100 val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
1101 pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val);
1104 pos_y += 1.25 * hud_fontsize_y;
1109 vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_size)
1112 RANKINGS_RECEIVED_CNT = 0;
1113 for (i=RANKINGS_CNT-1; i>=0; --i)
1115 ++RANKINGS_RECEIVED_CNT;
1117 if (RANKINGS_RECEIVED_CNT == 0)
1121 is_spec = (GetPlayerColor(pl.sv_entnum) == COLOR_SPECTATOR);
1123 hl_rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
1124 hl_rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
1125 hl_rgb_z = autocvar_scoreboard_color_bg_b + 0.5;
1127 pos_y += hud_fontsize_y;
1128 drawstring(pos, _("Rankings"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1129 pos_y += hud_fontsize_y + autocvar_scoreboard_border_thickness;
1132 tmp_y = 1.25 * hud_fontsize_y * RANKINGS_RECEIVED_CNT;
1135 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1137 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1138 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1141 for(i = 0; i<RANKINGS_RECEIVED_CNT; ++i)
1148 n = grecordholder[i];
1149 p = race_PlaceName(i+1);
1150 if(grecordholder[i] == GetPlayerName(player_localnum))
1151 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
1152 else if(!mod(i, 2) && scoreboard_highlight)
1153 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
1154 drawstring(pos, p, '1 1 0' * hud_fontsize_y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1155 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);
1156 drawcolorcodedstring(pos + '8 0 0' * hud_fontsize_y, n, '1 1 0' * hud_fontsize_y, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1157 pos_y += 1.25 * hud_fontsize_y;
1159 pos_y += autocvar_scoreboard_border_thickness;
1164 float hud_woulddrawscoreboard_prev;
1165 float hud_woulddrawscoreboard_change; // "time" at which HUD_WouldDrawScoreboard() changed
1166 void HUD_DrawScoreboard()
1168 float hud_woulddrawscoreboard;
1169 hud_woulddrawscoreboard = scoreboard_active;
1170 if(hud_woulddrawscoreboard != hud_woulddrawscoreboard_prev) {
1171 hud_woulddrawscoreboard_change = time;
1172 hud_woulddrawscoreboard_prev = hud_woulddrawscoreboard;
1175 if(hud_woulddrawscoreboard) {
1176 float scoreboard_fadeinspeed = autocvar_scoreboard_fadeinspeed;
1177 if (scoreboard_fadeinspeed)
1178 scoreboard_fade_alpha = bound (0, (time - hud_woulddrawscoreboard_change) * scoreboard_fadeinspeed, 1);
1180 scoreboard_fade_alpha = 1;
1183 float scoreboard_fadeoutspeed = autocvar_scoreboard_fadeoutspeed;
1184 if (scoreboard_fadeoutspeed)
1185 scoreboard_fade_alpha = bound (0, (1/scoreboard_fadeoutspeed - (time - hud_woulddrawscoreboard_change)) * scoreboard_fadeoutspeed, 1);
1187 scoreboard_fade_alpha = 0;
1190 if not(scoreboard_fade_alpha)
1193 HUD_UpdatePlayerTeams();
1195 scoreboard_alpha_bg = autocvar_scoreboard_alpha_bg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1196 scoreboard_alpha_fg = autocvar_scoreboard_alpha_fg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1197 scoreboard_highlight = autocvar_scoreboard_highlight;
1198 scoreboard_highlight_alpha = autocvar_scoreboard_highlight_alpha * scoreboard_alpha_fg;
1199 scoreboard_highlight_alpha_self = autocvar_scoreboard_highlight_alpha_self * scoreboard_alpha_fg;
1200 scoreboard_alpha_name = autocvar_scoreboard_alpha_name * scoreboard_alpha_fg;
1201 scoreboard_alpha_name_self = autocvar_scoreboard_alpha_name_self * scoreboard_alpha_fg;
1203 vector rgb, pos, tmp;
1207 xmin = (autocvar_scoreboard_offset_left * vid_conwidth);
1208 ymin = max((autocvar_con_notify * autocvar_con_notifysize), (autocvar_scoreboard_offset_vertical * vid_conwidth));
1210 xmax = ((1 - autocvar_scoreboard_offset_right) * vid_conwidth);
1211 ymax = (vid_conheight - ymin);
1213 sbwidth = xmax - xmin;
1215 // Initializes position
1221 vector sb_heading_fontsize;
1222 sb_heading_fontsize = hud_fontsize * 2;
1223 drawstring(pos, _("Scoreboard"), sb_heading_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1225 pos_y += sb_heading_fontsize_y + hud_fontsize_y * 0.25;
1227 // Draw the scoreboard
1228 vector bg_size = draw_getimagesize("gfx/scoreboard/scoreboard_bg") * autocvar_scoreboard_bg_scale;
1232 vector team_score_baseoffset;
1233 team_score_baseoffset = eY * (2 * autocvar_scoreboard_border_thickness + hud_fontsize_y) - eX * (autocvar_scoreboard_border_thickness + hud_fontsize_x * 0.25);
1234 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1236 if(tm.team == COLOR_SPECTATOR)
1239 rgb = GetTeamRGB(tm.team);
1240 str = ftos(tm.(teamscores[ts_primary]));
1241 drawstring(pos + team_score_baseoffset - eX * stringwidth(str, FALSE, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1243 if(ts_primary != ts_secondary)
1245 str = ftos(tm.(teamscores[ts_secondary]));
1246 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);
1248 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1253 rgb_x = autocvar_scoreboard_color_bg_r;
1254 rgb_y = autocvar_scoreboard_color_bg_g;
1255 rgb_z = autocvar_scoreboard_color_bg_b;
1257 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1259 if(tm.team == COLOR_SPECTATOR)
1262 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1266 if(gametype == GAME_CTS || gametype == GAME_RACE) {
1267 if(race_speedaward) {
1268 drawcolorcodedstring(pos, sprintf(_("Speed award: %d ^7(%s^7)"), race_speedaward, race_speedaward_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1269 pos_y += 1.25 * hud_fontsize_y;
1271 if(race_speedaward_alltimebest) {
1272 drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1273 pos_y += 1.25 * hud_fontsize_y;
1275 pos = HUD_DrawScoreboardRankings(pos, pl, rgb, bg_size);
1277 else if(autocvar_scoreboard_accuracy && spectatee_status != -1 && !warmup_stage) {
1279 pos = HUD_DrawScoreboardAccuracyStats(pos, GetTeamRGB(myteam), bg_size);
1281 pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size);
1286 pos = HUD_DrawMapStats(pos, GetTeamRGB(myteam), bg_size);
1288 pos = HUD_DrawMapStats(pos, rgb, bg_size);
1294 for(pl = players.sort_next; pl; pl = pl.sort_next)
1296 if(pl.team != COLOR_SPECTATOR)
1298 pos_y += 1.25 * hud_fontsize_y;
1299 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), specs);
1305 drawstring(tmp, _("Spectators"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1306 pos_y += 1.25 * hud_fontsize_y;
1309 // Print info string
1311 str = sprintf(_("playing on ^2%s^7"), shortmapname);
1312 tl = getstatf(STAT_TIMELIMIT);
1313 fl = getstatf(STAT_FRAGLIMIT);
1314 ll = getstatf(STAT_LEADLIMIT);
1315 if(gametype == GAME_LMS)
1318 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1323 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1327 str = strcat(str, _(" or"));
1330 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], fl),
1331 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1332 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1333 TranslateScoresLabel(teamscores_label[ts_primary])));
1337 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(scores_flags[ps_primary], fl),
1338 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1339 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1340 TranslateScoresLabel(scores_label[ps_primary])));
1345 if(tl > 0 || fl > 0)
1346 str = strcat(str, _(" or"));
1349 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], ll),
1350 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1351 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1352 TranslateScoresLabel(teamscores_label[ts_primary])));
1356 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(scores_flags[ps_primary], ll),
1357 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1358 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1359 TranslateScoresLabel(scores_label[ps_primary])));
1365 pos_y += 1.2 * hud_fontsize_y;
1366 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1368 scoreboard_bottom = pos_y + 2 * hud_fontsize_y;