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 "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 "nick": return CTX(_("SCO^nick"));
40 case "objectives": return CTX(_("SCO^objectives"));
41 case "pickups": return CTX(_("SCO^pickups"));
42 case "ping": return CTX(_("SCO^ping"));
43 case "pl": return CTX(_("SCO^pl"));
44 case "pushes": return CTX(_("SCO^pushes"));
45 case "rank": return CTX(_("SCO^rank"));
46 case "returns": return CTX(_("SCO^returns"));
47 case "revivals": return CTX(_("SCO^revivals"));
48 case "score": return CTX(_("SCO^score"));
49 case "suicides": return CTX(_("SCO^suicides"));
50 case "takes": return CTX(_("SCO^takes"));
51 case "ticks": return CTX(_("SCO^ticks"));
56 void Cmd_HUD_SetFields(float argc);
61 ps_primary = ps_secondary = ts_primary = ts_secondary = -1;
62 for(i = 0; i < MAX_SCORE; ++i)
64 f = (scores_flags[i] & SFL_SORT_PRIO_MASK);
65 if(f == SFL_SORT_PRIO_PRIMARY)
67 if(f == SFL_SORT_PRIO_SECONDARY)
70 if(ps_secondary == -1)
71 ps_secondary = ps_primary;
73 for(i = 0; i < MAX_TEAMSCORE; ++i)
75 f = (teamscores_flags[i] & SFL_SORT_PRIO_MASK);
76 if(f == SFL_SORT_PRIO_PRIMARY)
78 if(f == SFL_SORT_PRIO_SECONDARY)
81 if(ts_secondary == -1)
82 ts_secondary = ts_primary;
87 void HUD_UpdatePlayerPos(entity pl);
88 float SetTeam(entity pl, float Team);
90 void HUD_UpdatePlayerTeams()
97 for(pl = players.sort_next; pl; pl = pl.sort_next)
100 Team = GetPlayerColor(pl.sv_entnum);
101 if(SetTeam(pl, Team))
104 HUD_UpdatePlayerPos(pl);
108 pl = players.sort_next;
113 print(strcat("PNUM: ", ftos(num), "\n"));
118 float HUD_CompareScore(float vl, float vr, float f)
120 if(f & SFL_ZERO_IS_WORST)
122 if(vl == 0 && vr != 0)
124 if(vl != 0 && vr == 0)
128 return IS_INCREASING(f);
130 return IS_DECREASING(f);
134 float HUD_ComparePlayerScores(entity left, entity right)
137 vl = GetPlayerColor(left.sv_entnum);
138 vr = GetPlayerColor(right.sv_entnum);
150 if(vl == NUM_SPECTATOR)
152 // FIRST the one with scores (spectators), THEN the ones without (downloaders)
154 if(!left.gotscores && right.gotscores)
159 r = HUD_CompareScore(left.scores[ps_primary], right.scores[ps_primary], scores_flags[ps_primary]);
163 r = HUD_CompareScore(left.scores[ps_secondary], right.scores[ps_secondary], scores_flags[ps_secondary]);
167 for(i = 0; i < MAX_SCORE; ++i)
169 r = HUD_CompareScore(left.scores[i], right.scores[i], scores_flags[i]);
174 if (left.sv_entnum < right.sv_entnum)
180 void HUD_UpdatePlayerPos(entity player)
182 for(other = player.sort_next; other && HUD_ComparePlayerScores(player, other); other = player.sort_next)
184 SORT_SWAP(player, other);
186 for(other = player.sort_prev; other != players && HUD_ComparePlayerScores(other, player); other = player.sort_prev)
188 SORT_SWAP(other, player);
192 float HUD_CompareTeamScores(entity left, entity right)
196 if(left.team == NUM_SPECTATOR)
198 if(right.team == NUM_SPECTATOR)
201 r = HUD_CompareScore(left.teamscores[ts_primary], right.teamscores[ts_primary], teamscores_flags[ts_primary]);
205 r = HUD_CompareScore(left.teamscores[ts_secondary], right.teamscores[ts_secondary], teamscores_flags[ts_secondary]);
209 for(i = 0; i < MAX_SCORE; ++i)
211 r = HUD_CompareScore(left.teamscores[i], right.teamscores[i], teamscores_flags[i]);
216 if (left.team < right.team)
222 void HUD_UpdateTeamPos(entity Team)
224 for(other = Team.sort_next; other && HUD_CompareTeamScores(Team, other); other = Team.sort_next)
226 SORT_SWAP(Team, other);
228 for(other = Team.sort_prev; other != teams && HUD_CompareTeamScores(other, Team); other = Team.sort_prev)
230 SORT_SWAP(other, Team);
236 print(_("You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"));
237 print(_("^3|---------------------------------------------------------------|\n"));
238 print(_("Usage:\n"));
239 print(_("^2scoreboard_columns_set default\n"));
240 print(_("^2scoreboard_columns_set ^7field1 field2 ...\n"));
241 print(_("The following field names are recognized (case insensitive):\n"));
242 print(_("You can use a ^3|^7 to start the right-aligned fields.\n\n"));
244 print(_("^3name^7 or ^3nick^7 Name of a player\n"));
245 print(_("^3ping^7 Ping time\n"));
246 print(_("^3pl^7 Packet loss\n"));
247 print(_("^3kills^7 Number of kills\n"));
248 print(_("^3deaths^7 Number of deaths\n"));
249 print(_("^3suicides^7 Number of suicides\n"));
250 print(_("^3frags^7 kills - suicides\n"));
251 print(_("^3kd^7 The kill-death ratio\n"));
252 print(_("^3caps^7 How often a flag (CTF) or a key (KeyHunt) was captured\n"));
253 print(_("^3pickups^7 How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\n"));
254 print(_("^3captime^7 Time of fastest cap (CTF)\n"));
255 print(_("^3fckills^7 Number of flag carrier kills\n"));
256 print(_("^3returns^7 Number of flag returns\n"));
257 print(_("^3drops^7 Number of flag drops\n"));
258 print(_("^3lives^7 Number of lives (LMS)\n"));
259 print(_("^3rank^7 Player rank\n"));
260 print(_("^3pushes^7 Number of players pushed into void\n"));
261 print(_("^3destroyed^7 Number of keys destroyed by pushing them into void\n"));
262 print(_("^3kckills^7 Number of keys carrier kills\n"));
263 print(_("^3losses^7 Number of times a key was lost\n"));
264 print(_("^3laps^7 Number of laps finished (race/cts)\n"));
265 print(_("^3time^7 Total time raced (race/cts)\n"));
266 print(_("^3fastest^7 Time of fastest lap (race/cts)\n"));
267 print(_("^3ticks^7 Number of ticks (DOM)\n"));
268 print(_("^3takes^7 Number of domination points taken (DOM)\n"));
269 print(_("^3bckills^7 Number of ball carrier kills\n"));
270 print(_("^3bctime^7 Total amount of time holding the ball in Keepaway\n"));
271 print(_("^3score^7 Total score\n\n"));
273 print(_("Before a field you can put a + or - sign, then a comma separated list\n"
274 "of game types, then a slash, to make the field show up only in these\n"
275 "or in all but these game types. You can also specify 'all' as a\n"
276 "field to show all fields available for the current game mode.\n\n"));
278 print(_("The special game type names 'teams' and 'noteams' can be used to\n"
279 "include/exclude ALL teams/noteams game modes.\n\n"));
281 print(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"));
282 print(_("will display name, ping and pl aligned to the left, and the fields\n"
283 "right of the vertical bar aligned to the right.\n"));
284 print(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
285 "other gamemodes except DM.\n"));
288 string HUD_DefaultColumnLayout()
290 return strcat( // fteqcc sucks
292 "-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"
293 "+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns ",
294 "+lms/lives +lms/rank ",
295 "+kh/caps +kh/pushes +kh/destroyed ",
296 "?+race/laps ?+race/time ?+race/fastest ",
297 "+as/objectives +nexball/faults +nexball/goals +ka/pickups +ka/bckills +ka/bctime +freezetag/revivals ",
298 "-lms,race,nexball/score");
301 void Cmd_HUD_SetFields(float argc)
305 float have_name = 0, have_primary = 0, have_secondary = 0, have_separator = 0;
308 // TODO: re enable with gametype dependant cvars?
309 if(argc < 3) // no arguments provided
310 argc = tokenizebyseparator(strcat("0 1 ", autocvar_scoreboard_columns), " ");
313 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
317 if(argv(2) == "default")
318 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
319 else if(argv(2) == "all")
322 s = "ping pl name |";
323 for(i = 0; i < MAX_SCORE; ++i)
326 if(i != ps_secondary)
327 if(scores_label[i] != "")
328 s = strcat(s, " ", scores_label[i]);
330 if(ps_secondary != ps_primary)
331 s = strcat(s, " ", scores_label[ps_secondary]);
332 s = strcat(s, " ", scores_label[ps_primary]);
333 argc = tokenizebyseparator(strcat("0 1 ", s), " ");
340 hud_fontsize = HUD_GetFontsize("hud_fontsize");
342 draw_beginBoldFont();
343 for(i = 1; i < argc - 1; ++i)
349 if(substring(str, 0, 1) == "?")
352 str = substring(str, 1, strlen(str) - 1);
355 slash = strstrofs(str, "/", 0);
358 pattern = substring(str, 0, slash);
359 str = substring(str, slash + 1, strlen(str) - (slash + 1));
361 if not(isGametypeInFilter(gametype, teamplay, FALSE, pattern))
365 strunzone(hud_title[hud_num_fields]);
366 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(str));
367 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
368 str = strtolower(str);
371 hud_field[hud_num_fields] = SP_PING;
372 } else if(str == "pl") {
373 hud_field[hud_num_fields] = SP_PL;
374 } else if(str == "kd" || str == "kdr" || str == "kdratio" || str == "k/d") {
375 hud_field[hud_num_fields] = SP_KDRATIO;
376 } else if(str == "name" || str == "nick") {
377 hud_field[hud_num_fields] = SP_NAME;
379 } else if(str == "|") {
380 hud_field[hud_num_fields] = SP_SEPARATOR;
383 for(j = 0; j < MAX_SCORE; ++j)
384 if(str == strtolower(scores_label[j]))
385 goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
394 print(sprintf("^1Error:^7 Unknown score field: '%s'\n", str));
398 hud_field[hud_num_fields] = j;
401 if(j == ps_secondary)
405 if(hud_num_fields >= MAX_HUD_FIELDS)
409 if(scores_flags[ps_primary] & SFL_ALLOW_HIDE)
411 if(scores_flags[ps_secondary] & SFL_ALLOW_HIDE)
413 if(ps_primary == ps_secondary)
415 missing = (!have_primary) + (!have_secondary) + (!have_separator) + (!have_name);
417 if(hud_num_fields+missing < MAX_HUD_FIELDS)
421 strunzone(hud_title[hud_num_fields]);
422 for(i = hud_num_fields; i > 0; --i)
424 hud_title[i] = hud_title[i-1];
425 hud_size[i] = hud_size[i-1];
426 hud_field[i] = hud_field[i-1];
428 hud_title[0] = strzone(TranslateScoresLabel("name"));
429 hud_field[0] = SP_NAME;
431 print(sprintf(_("fixed missing field '%s'\n"), "name"));
435 strunzone(hud_title[hud_num_fields]);
436 for(i = hud_num_fields; i > 1; --i)
438 hud_title[i] = hud_title[i-1];
439 hud_size[i] = hud_size[i-1];
440 hud_field[i] = hud_field[i-1];
442 hud_title[1] = strzone("|");
443 hud_field[1] = SP_SEPARATOR;
444 hud_size[1] = stringwidth("|", FALSE, hud_fontsize);
446 print(sprintf(_("fixed missing field '%s'\n"), "|"));
449 else if(!have_separator)
451 strunzone(hud_title[hud_num_fields]);
452 hud_title[hud_num_fields] = strzone("|");
453 hud_size[hud_num_fields] = stringwidth("|", FALSE, hud_fontsize);
454 hud_field[hud_num_fields] = SP_SEPARATOR;
456 print(sprintf(_("fixed missing field '%s'\n"), "|"));
460 strunzone(hud_title[hud_num_fields]);
461 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_secondary]));
462 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
463 hud_field[hud_num_fields] = ps_secondary;
465 print(sprintf(_("fixed missing field '%s'\n"), scores_label[ps_secondary]));
469 strunzone(hud_title[hud_num_fields]);
470 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_primary]));
471 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
472 hud_field[hud_num_fields] = ps_primary;
474 print(sprintf(_("fixed missing field '%s'\n"), scores_label[ps_primary]));
478 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 = Team_ColorRGB(pl.team);
662 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_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 = '0 0 0', column_dim = '0 0 0';
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 draw_beginBoldFont();
844 for(i = 0; i < hud_num_fields; ++i)
846 if(hud_field[i] == SP_SEPARATOR)
848 column_dim_x = hud_size[i] + hud_fontsize_x;
849 if (scoreboard_highlight)
852 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
854 drawstring(pos, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
855 pos_x += column_dim_x;
857 if(hud_field[i] == SP_SEPARATOR)
861 for(i = hud_num_fields-1; i > 0; --i)
863 if(hud_field[i] == SP_SEPARATOR)
866 pos_x -= hud_size[i];
868 if (scoreboard_highlight)
872 if (i == hud_num_fields-1)
873 column_dim_x = hud_size[i] + hud_fontsize_x / 2 + 1;
875 column_dim_x = hud_size[i] + hud_fontsize_x;
876 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
880 tmp_x = stringwidth(hud_title[i], FALSE, hud_fontsize);
881 tmp_x = (hud_size[i] - tmp_x);
882 drawstring(pos + tmp, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
883 pos_x -= hud_fontsize_x;
889 pos_y += 1.25 * hud_fontsize_y; // skip the header
890 pos_y += autocvar_scoreboard_border_thickness;
892 // fill the table and draw the rows
895 for(pl = players.sort_next; pl; pl = pl.sort_next)
897 if(pl.team != tm.team)
899 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
900 pos_y += 1.25 * hud_fontsize_y;
904 for(pl = players.sort_next; pl; pl = pl.sort_next)
906 if(pl.team == NUM_SPECTATOR)
908 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
909 pos_y += 1.25 * hud_fontsize_y;
914 pos_y += 1.25 * hud_fontsize_y; // move to the end of the table
915 pos_y += 1.25 * hud_fontsize_y; // move empty row (out of the table)
920 float HUD_WouldDrawScoreboard() {
921 if (autocvar__hud_configure)
923 else if (scoreboard_showscores)
925 else if (intermission == 1)
927 else if (intermission == 2)
929 else if (spectatee_status != -1 && getstati(STAT_HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS)
931 else if (scoreboard_showscores_force)
936 float average_accuracy;
937 vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
940 float weapon_cnt = WEP_COUNT - 3; // either minstanex/nex are hidden, no port-o-launch, no tuba
942 if(autocvar_scoreboard_accuracy_doublerows)
947 float fontsize = height * 1/3;
948 float weapon_height = height * 2/3;
949 float weapon_width = sbwidth / weapon_cnt;
950 float g_minstagib = 0;
952 drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
953 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
954 vector tmp = '0 0 0';
956 tmp_y = height * rows;
959 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
961 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
962 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
964 // column highlighting
965 for(i = 0; i < weapon_cnt/rows; ++i)
968 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);
972 for(i = 0; i < rows; ++i)
974 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);
977 average_accuracy = 0;
978 float weapons_with_stats;
979 weapons_with_stats = 0;
981 pos_x += weapon_width / 2;
983 if(switchweapon == WEP_MINSTANEX)
984 g_minstagib = 1; // TODO: real detection for minstagib?
987 if(autocvar_scoreboard_accuracy_nocolors)
990 Accuracy_LoadColors();
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
1020 if(!autocvar_scoreboard_accuracy_nocolors)
1021 rgb = Accuracy_GetColor(weapon_stats);
1023 drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1025 pos_x += weapon_width * rows;
1026 if(rows == 2 && i == 6) {
1032 if(weapons_with_stats)
1033 average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
1036 pos_x -= weapon_width / 2;
1040 pos_y += 1.25 * hud_fontsize_y;
1044 vector HUD_DrawKeyValue(vector pos, string key, string value) {
1046 pos_x += hud_fontsize_x * 0.25;
1047 drawstring(pos, key, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1048 pos_x = xmax - stringwidth(value, FALSE, hud_fontsize) - hud_fontsize_x * 0.25;
1049 drawstring(pos, value, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1051 pos_y+= hud_fontsize_y;
1056 vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
1057 float stat_secrets_found, stat_secrets_total;
1061 // get secrets stats
1062 stat_secrets_found = getstatf(STAT_SECRETS_FOUND);
1063 stat_secrets_total = getstatf(STAT_SECRETS_TOTAL);
1065 // get number of rows
1066 rows = (stat_secrets_total ? 1 : 0);
1068 // if no rows, return
1072 // draw table header
1073 drawstring(pos, _("Map stats:"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1074 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
1077 vector tmp = '0 0 0';
1079 tmp_y = hud_fontsize_y * rows;
1082 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1084 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1085 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1088 val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
1089 pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val);
1092 pos_y += 1.25 * hud_fontsize_y;
1097 vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_size)
1100 RANKINGS_RECEIVED_CNT = 0;
1101 for (i=RANKINGS_CNT-1; i>=0; --i)
1103 ++RANKINGS_RECEIVED_CNT;
1105 if (RANKINGS_RECEIVED_CNT == 0)
1109 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
1111 hl_rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
1112 hl_rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
1113 hl_rgb_z = autocvar_scoreboard_color_bg_b + 0.5;
1115 pos_y += hud_fontsize_y;
1116 drawstring(pos, _("Rankings"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1117 pos_y += hud_fontsize_y + autocvar_scoreboard_border_thickness;
1118 vector tmp = '0 0 0';
1120 tmp_y = 1.25 * hud_fontsize_y * RANKINGS_RECEIVED_CNT;
1123 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1125 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1126 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1129 for(i = 0; i<RANKINGS_RECEIVED_CNT; ++i)
1136 n = grecordholder[i];
1137 p = count_ordinal(i+1);
1138 if(grecordholder[i] == GetPlayerName(player_localnum))
1139 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
1140 else if(!mod(i, 2) && scoreboard_highlight)
1141 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
1142 drawstring(pos, p, '1 1 0' * hud_fontsize_y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1143 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);
1144 drawcolorcodedstring(pos + '8 0 0' * hud_fontsize_y, n, '1 1 0' * hud_fontsize_y, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1145 pos_y += 1.25 * hud_fontsize_y;
1147 pos_y += autocvar_scoreboard_border_thickness;
1152 float hud_woulddrawscoreboard_prev;
1153 float hud_woulddrawscoreboard_change; // "time" at which HUD_WouldDrawScoreboard() changed
1154 void HUD_DrawScoreboard()
1156 float hud_woulddrawscoreboard;
1157 hud_woulddrawscoreboard = scoreboard_active;
1158 if(hud_woulddrawscoreboard != hud_woulddrawscoreboard_prev) {
1159 hud_woulddrawscoreboard_change = time;
1160 hud_woulddrawscoreboard_prev = hud_woulddrawscoreboard;
1163 if(hud_woulddrawscoreboard) {
1164 float scoreboard_fadeinspeed = autocvar_scoreboard_fadeinspeed;
1165 if (scoreboard_fadeinspeed)
1166 scoreboard_fade_alpha = bound (0, (time - hud_woulddrawscoreboard_change) * scoreboard_fadeinspeed, 1);
1168 scoreboard_fade_alpha = 1;
1171 float scoreboard_fadeoutspeed = autocvar_scoreboard_fadeoutspeed;
1172 if (scoreboard_fadeoutspeed)
1173 scoreboard_fade_alpha = bound (0, (1/scoreboard_fadeoutspeed - (time - hud_woulddrawscoreboard_change)) * scoreboard_fadeoutspeed, 1);
1175 scoreboard_fade_alpha = 0;
1178 if not(scoreboard_fade_alpha)
1181 HUD_UpdatePlayerTeams();
1183 scoreboard_alpha_bg = autocvar_scoreboard_alpha_bg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1184 scoreboard_alpha_fg = autocvar_scoreboard_alpha_fg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1185 scoreboard_highlight = autocvar_scoreboard_highlight;
1186 scoreboard_highlight_alpha = autocvar_scoreboard_highlight_alpha * scoreboard_alpha_fg;
1187 scoreboard_highlight_alpha_self = autocvar_scoreboard_highlight_alpha_self * scoreboard_alpha_fg;
1188 scoreboard_alpha_name = autocvar_scoreboard_alpha_name * scoreboard_alpha_fg;
1189 scoreboard_alpha_name_self = autocvar_scoreboard_alpha_name_self * scoreboard_alpha_fg;
1191 vector rgb, pos, tmp;
1195 xmin = (autocvar_scoreboard_offset_left * vid_conwidth);
1196 ymin = max((autocvar_con_notify * autocvar_con_notifysize), (autocvar_scoreboard_offset_vertical * vid_conwidth));
1198 xmax = ((1 - autocvar_scoreboard_offset_right) * vid_conwidth);
1199 ymax = (vid_conheight - ymin);
1201 sbwidth = xmax - xmin;
1203 // Initializes position
1209 vector sb_heading_fontsize;
1210 sb_heading_fontsize = hud_fontsize * 2;
1211 draw_beginBoldFont();
1212 drawstring(pos, _("Scoreboard"), sb_heading_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1215 pos_y += sb_heading_fontsize_y + hud_fontsize_y * 0.25;
1217 // Draw the scoreboard
1218 vector bg_size = draw_getimagesize("gfx/scoreboard/scoreboard_bg") * autocvar_scoreboard_bg_scale;
1222 vector team_score_baseoffset;
1223 team_score_baseoffset = eY * (2 * autocvar_scoreboard_border_thickness + hud_fontsize_y) - eX * (autocvar_scoreboard_border_thickness + hud_fontsize_x * 0.25);
1224 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1226 if(tm.team == NUM_SPECTATOR)
1229 draw_beginBoldFont();
1230 rgb = Team_ColorRGB(tm.team);
1231 str = ftos(tm.(teamscores[ts_primary]));
1232 drawstring(pos + team_score_baseoffset - eX * stringwidth(str, FALSE, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1234 if(ts_primary != ts_secondary)
1236 str = ftos(tm.(teamscores[ts_secondary]));
1237 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);
1241 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1247 rgb_x = autocvar_scoreboard_color_bg_r;
1248 rgb_y = autocvar_scoreboard_color_bg_g;
1249 rgb_z = autocvar_scoreboard_color_bg_b;
1256 rgb_x = autocvar_scoreboard_color_bg_r;
1257 rgb_y = autocvar_scoreboard_color_bg_g;
1258 rgb_z = autocvar_scoreboard_color_bg_b;
1260 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1262 if(tm.team == NUM_SPECTATOR)
1265 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1269 if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE) {
1270 if(race_speedaward) {
1271 drawcolorcodedstring(pos, sprintf(_("Speed award: %d ^7(%s^7)"), race_speedaward, race_speedaward_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1272 pos_y += 1.25 * hud_fontsize_y;
1274 if(race_speedaward_alltimebest) {
1275 drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1276 pos_y += 1.25 * hud_fontsize_y;
1278 pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
1280 else if(autocvar_scoreboard_accuracy && spectatee_status != -1 && !warmup_stage) {
1282 pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size);
1284 pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size);
1289 pos = HUD_DrawMapStats(pos, Team_ColorRGB(myteam), bg_size);
1291 pos = HUD_DrawMapStats(pos, rgb, bg_size);
1297 for(pl = players.sort_next; pl; pl = pl.sort_next)
1299 if(pl.team != NUM_SPECTATOR)
1301 pos_y += 1.25 * hud_fontsize_y;
1302 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), specs);
1308 draw_beginBoldFont();
1309 drawstring(tmp, _("Spectators"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1311 pos_y += 1.25 * hud_fontsize_y;
1314 // Print info string
1316 str = sprintf(_("playing on ^2%s^7"), shortmapname);
1317 tl = getstatf(STAT_TIMELIMIT);
1318 fl = getstatf(STAT_FRAGLIMIT);
1319 ll = getstatf(STAT_LEADLIMIT);
1320 if(gametype == MAPINFO_TYPE_LMS)
1323 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1328 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1332 str = strcat(str, _(" or"));
1335 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], fl),
1336 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1337 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1338 TranslateScoresLabel(teamscores_label[ts_primary])));
1342 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(scores_flags[ps_primary], fl),
1343 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1344 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1345 TranslateScoresLabel(scores_label[ps_primary])));
1350 if(tl > 0 || fl > 0)
1351 str = strcat(str, _(" or"));
1354 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], ll),
1355 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1356 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1357 TranslateScoresLabel(teamscores_label[ts_primary])));
1361 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(scores_flags[ps_primary], ll),
1362 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1363 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1364 TranslateScoresLabel(scores_label[ps_primary])));
1369 pos_y += 1.2 * hud_fontsize_y;
1370 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1372 // print information about respawn status
1373 float respawn_time = getstatf(STAT_RESPAWN_TIME);
1376 if(respawn_time < 0)
1378 // a negative number means we are awaiting respawn, time value is still the same
1379 respawn_time *= -1; // remove mark now that we checked it
1380 respawn_time = max(time, respawn_time); // don't show a negative value while the server is respawning the player (lag)
1382 str = sprintf(_("^1Respawning in ^3%s^1..."),
1383 (autocvar_scoreboard_respawntime_decimals ?
1384 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1386 count_seconds(respawn_time - time)
1390 else if(time < respawn_time)
1392 str = sprintf(_("You are dead, wait ^3%s^7 before respawning"),
1393 (autocvar_scoreboard_respawntime_decimals ?
1394 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1396 count_seconds(respawn_time - time)
1400 else if(time >= respawn_time)
1401 str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
1403 pos_y += 1.2 * hud_fontsize_y;
1404 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1407 scoreboard_bottom = pos_y + 2 * hud_fontsize_y;