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"));
58 void HUD_FinaleOverlay()
61 pos_x = (vid_conwidth - 1)/2;
65 //drawpic(pos, "gfx/finale", '0 0 0', '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
67 //drawstring(pos, "END", hud_fontsize, '1 1 1', 1, DRAWFLAG_NORMAL);
71 void Cmd_HUD_SetFields(float argc);
76 ps_primary = ps_secondary = ts_primary = ts_secondary = -1;
77 for(i = 0; i < MAX_SCORE; ++i)
79 f = (scores_flags[i] & SFL_SORT_PRIO_MASK);
80 if(f == SFL_SORT_PRIO_PRIMARY)
82 if(f == SFL_SORT_PRIO_SECONDARY)
85 if(ps_secondary == -1)
86 ps_secondary = ps_primary;
88 for(i = 0; i < MAX_TEAMSCORE; ++i)
90 f = (teamscores_flags[i] & SFL_SORT_PRIO_MASK);
91 if(f == SFL_SORT_PRIO_PRIMARY)
93 if(f == SFL_SORT_PRIO_SECONDARY)
96 if(ts_secondary == -1)
97 ts_secondary = ts_primary;
102 void HUD_UpdatePlayerPos(entity pl);
103 float SetTeam(entity pl, float Team);
105 void HUD_UpdatePlayerTeams()
112 for(pl = players.sort_next; pl; pl = pl.sort_next)
115 Team = GetPlayerColor(pl.sv_entnum);
116 if(SetTeam(pl, Team))
119 HUD_UpdatePlayerPos(pl);
123 pl = players.sort_next;
128 print(strcat("PNUM: ", ftos(num), "\n"));
133 float HUD_CompareScore(float vl, float vr, float f)
135 if(f & SFL_ZERO_IS_WORST)
137 if(vl == 0 && vr != 0)
139 if(vl != 0 && vr == 0)
143 return IS_INCREASING(f);
145 return IS_DECREASING(f);
149 float HUD_ComparePlayerScores(entity left, entity right)
152 vl = GetPlayerColor(left.sv_entnum);
153 vr = GetPlayerColor(right.sv_entnum);
165 if(vl == NUM_SPECTATOR)
167 // FIRST the one with scores (spectators), THEN the ones without (downloaders)
169 if(!left.gotscores && right.gotscores)
174 r = HUD_CompareScore(left.scores[ps_primary], right.scores[ps_primary], scores_flags[ps_primary]);
178 r = HUD_CompareScore(left.scores[ps_secondary], right.scores[ps_secondary], scores_flags[ps_secondary]);
182 for(i = 0; i < MAX_SCORE; ++i)
184 r = HUD_CompareScore(left.scores[i], right.scores[i], scores_flags[i]);
189 if (left.sv_entnum < right.sv_entnum)
195 void HUD_UpdatePlayerPos(entity player)
197 for(other = player.sort_next; other && HUD_ComparePlayerScores(player, other); other = player.sort_next)
199 SORT_SWAP(player, other);
201 for(other = player.sort_prev; other != players && HUD_ComparePlayerScores(other, player); other = player.sort_prev)
203 SORT_SWAP(other, player);
207 float HUD_CompareTeamScores(entity left, entity right)
211 if(left.team == NUM_SPECTATOR)
213 if(right.team == NUM_SPECTATOR)
216 r = HUD_CompareScore(left.teamscores[ts_primary], right.teamscores[ts_primary], teamscores_flags[ts_primary]);
220 r = HUD_CompareScore(left.teamscores[ts_secondary], right.teamscores[ts_secondary], teamscores_flags[ts_secondary]);
224 for(i = 0; i < MAX_SCORE; ++i)
226 r = HUD_CompareScore(left.teamscores[i], right.teamscores[i], teamscores_flags[i]);
231 if (left.team < right.team)
237 void HUD_UpdateTeamPos(entity Team)
239 for(other = Team.sort_next; other && HUD_CompareTeamScores(Team, other); other = Team.sort_next)
241 SORT_SWAP(Team, other);
243 for(other = Team.sort_prev; other != teams && HUD_CompareTeamScores(other, Team); other = Team.sort_prev)
245 SORT_SWAP(other, Team);
251 print(_("You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"));
252 print(_("^3|---------------------------------------------------------------|\n"));
253 print(_("Usage:\n"));
254 print(_("^2scoreboard_columns_set default\n"));
255 print(_("^2scoreboard_columns_set ^7field1 field2 ...\n"));
256 print(_("The following field names are recognized (case insensitive):\n"));
257 print(_("You can use a ^3|^7 to start the right-aligned fields.\n\n"));
259 print(_("^3name^7 or ^3nick^7 Name of a player\n"));
260 print(_("^3ping^7 Ping time\n"));
261 print(_("^3pl^7 Packet loss\n"));
262 print(_("^3kills^7 Number of kills\n"));
263 print(_("^3deaths^7 Number of deaths\n"));
264 print(_("^3suicides^7 Number of suicides\n"));
265 print(_("^3frags^7 kills - suicides\n"));
266 print(_("^3kd^7 The kill-death ratio\n"));
267 print(_("^3sum^7 frags - deaths\n"));
268 print(_("^3caps^7 How often a flag (CTF) or a key (KeyHunt) was captured\n"));
269 print(_("^3pickups^7 How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\n"));
270 print(_("^3captime^7 Time of fastest cap (CTF)\n"));
271 print(_("^3fckills^7 Number of flag carrier kills\n"));
272 print(_("^3returns^7 Number of flag returns\n"));
273 print(_("^3drops^7 Number of flag drops\n"));
274 print(_("^3lives^7 Number of lives (LMS)\n"));
275 print(_("^3rank^7 Player rank\n"));
276 print(_("^3pushes^7 Number of players pushed into void\n"));
277 print(_("^3destroyed^7 Number of keys destroyed by pushing them into void\n"));
278 print(_("^3kckills^7 Number of keys carrier kills\n"));
279 print(_("^3losses^7 Number of times a key was lost\n"));
280 print(_("^3laps^7 Number of laps finished (race/cts)\n"));
281 print(_("^3time^7 Total time raced (race/cts)\n"));
282 print(_("^3fastest^7 Time of fastest lap (race/cts)\n"));
283 print(_("^3ticks^7 Number of ticks (DOM)\n"));
284 print(_("^3takes^7 Number of domination points taken (DOM)\n"));
285 print(_("^3bckills^7 Number of ball carrier kills\n"));
286 print(_("^3bctime^7 Total amount of time holding the ball in Keepaway\n"));
287 print(_("^3score^7 Total score\n\n"));
289 print(_("Before a field you can put a + or - sign, then a comma separated list\n"
290 "of game types, then a slash, to make the field show up only in these\n"
291 "or in all but these game types. You can also specify 'all' as a\n"
292 "field to show all fields available for the current game mode.\n\n"));
294 print(_("The special game type names 'teams' and 'noteams' can be used to\n"
295 "include/exclude ALL teams/noteams game modes.\n\n"));
297 print(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"));
298 print(_("will display name, ping and pl aligned to the left, and the fields\n"
299 "right of the vertical bar aligned to the right.\n"));
300 print(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
301 "other gamemodes except DM.\n"));
304 string HUD_DefaultColumnLayout()
306 return strcat( // fteqcc sucks
308 "-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"
309 "+tdm/kills +tdm/deaths +tdm/suicides ",
310 "+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns ",
311 "+lms/lives +lms/rank ",
312 "+kh/caps +kh/pushes +kh/destroyed ",
313 "?+race/laps ?+race/time ?+race/fastest ",
314 "+as/objectives +nexball/faults +nexball/goals +ka/pickups +ka/bckills +ka/bctime +freezetag/revivals ",
315 "-lms,race,nexball/score");
318 void Cmd_HUD_SetFields(float argc)
322 float have_name = 0, have_primary = 0, have_secondary = 0, have_separator = 0;
325 // TODO: re enable with gametype dependant cvars?
326 if(argc < 3) // no arguments provided
327 argc = tokenizebyseparator(strcat("0 1 ", autocvar_scoreboard_columns), " ");
330 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
334 if(argv(2) == "default")
335 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
336 else if(argv(2) == "all")
339 s = "ping pl name |";
340 for(i = 0; i < MAX_SCORE; ++i)
343 if(i != ps_secondary)
344 if(scores_label[i] != "")
345 s = strcat(s, " ", scores_label[i]);
347 if(ps_secondary != ps_primary)
348 s = strcat(s, " ", scores_label[ps_secondary]);
349 s = strcat(s, " ", scores_label[ps_primary]);
350 argc = tokenizebyseparator(strcat("0 1 ", s), " ");
357 hud_fontsize = HUD_GetFontsize("hud_fontsize");
359 draw_beginBoldFont();
360 for(i = 1; i < argc - 1; ++i)
366 if(substring(str, 0, 1) == "?")
369 str = substring(str, 1, strlen(str) - 1);
372 slash = strstrofs(str, "/", 0);
375 pattern = substring(str, 0, slash);
376 str = substring(str, slash + 1, strlen(str) - (slash + 1));
378 if (!isGametypeInFilter(gametype, teamplay, FALSE, pattern))
382 strunzone(hud_title[hud_num_fields]);
383 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(str));
384 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
385 str = strtolower(str);
388 hud_field[hud_num_fields] = SP_PING;
389 } else if(str == "pl") {
390 hud_field[hud_num_fields] = SP_PL;
391 } else if(str == "kd" || str == "kdr" || str == "kdratio" || str == "k/d") {
392 hud_field[hud_num_fields] = SP_KDRATIO;
393 } else if(str == "sum" || str == "diff" || str == "f-d") {
394 hud_field[hud_num_fields] = SP_SUM;
395 } else if(str == "name" || str == "nick") {
396 hud_field[hud_num_fields] = SP_NAME;
398 } else if(str == "|") {
399 hud_field[hud_num_fields] = SP_SEPARATOR;
402 for(j = 0; j < MAX_SCORE; ++j)
403 if(str == strtolower(scores_label[j]))
404 goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
413 printf("^1Error:^7 Unknown score field: '%s'\n", str);
417 hud_field[hud_num_fields] = j;
420 if(j == ps_secondary)
424 if(hud_num_fields >= MAX_HUD_FIELDS)
428 if(scores_flags[ps_primary] & SFL_ALLOW_HIDE)
430 if(scores_flags[ps_secondary] & SFL_ALLOW_HIDE)
432 if(ps_primary == ps_secondary)
434 missing = (!have_primary) + (!have_secondary) + (!have_separator) + (!have_name);
436 if(hud_num_fields+missing < MAX_HUD_FIELDS)
440 strunzone(hud_title[hud_num_fields]);
441 for(i = hud_num_fields; i > 0; --i)
443 hud_title[i] = hud_title[i-1];
444 hud_size[i] = hud_size[i-1];
445 hud_field[i] = hud_field[i-1];
447 hud_title[0] = strzone(TranslateScoresLabel("name"));
448 hud_field[0] = SP_NAME;
450 print("fixed missing field 'name'\n");
454 strunzone(hud_title[hud_num_fields]);
455 for(i = hud_num_fields; i > 1; --i)
457 hud_title[i] = hud_title[i-1];
458 hud_size[i] = hud_size[i-1];
459 hud_field[i] = hud_field[i-1];
461 hud_title[1] = strzone("|");
462 hud_field[1] = SP_SEPARATOR;
463 hud_size[1] = stringwidth("|", FALSE, hud_fontsize);
465 print("fixed missing field '|'\n");
468 else if(!have_separator)
470 strunzone(hud_title[hud_num_fields]);
471 hud_title[hud_num_fields] = strzone("|");
472 hud_size[hud_num_fields] = stringwidth("|", FALSE, hud_fontsize);
473 hud_field[hud_num_fields] = SP_SEPARATOR;
475 print("fixed missing field '|'\n");
479 strunzone(hud_title[hud_num_fields]);
480 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_secondary]));
481 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
482 hud_field[hud_num_fields] = ps_secondary;
484 printf("fixed missing field '%s'\n", scores_label[ps_secondary]);
488 strunzone(hud_title[hud_num_fields]);
489 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_primary]));
490 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
491 hud_field[hud_num_fields] = ps_primary;
493 printf("fixed missing field '%s'\n", scores_label[ps_primary]);
497 hud_field[hud_num_fields] = SP_END;
502 vector hud_field_rgb;
503 string hud_field_icon0;
504 string hud_field_icon1;
505 string hud_field_icon2;
506 vector hud_field_icon0_rgb;
507 vector hud_field_icon1_rgb;
508 vector hud_field_icon2_rgb;
509 float hud_field_icon0_alpha;
510 float hud_field_icon1_alpha;
511 float hud_field_icon2_alpha;
512 string HUD_GetField(entity pl, float field)
514 float tmp, num, denom, f;
516 hud_field_rgb = '1 1 1';
517 hud_field_icon0 = "";
518 hud_field_icon1 = "";
519 hud_field_icon2 = "";
520 hud_field_icon0_rgb = '1 1 1';
521 hud_field_icon1_rgb = '1 1 1';
522 hud_field_icon2_rgb = '1 1 1';
523 hud_field_icon0_alpha = 1;
524 hud_field_icon1_alpha = 1;
525 hud_field_icon2_alpha = 1;
530 return "\xEE\x82\x8D\xEE\x82\x8D\xEE\x82\x8D"; // >>> sign
531 //str = getplayerkeyvalue(pl.sv_entnum, "ping");
535 tmp = max(0, min(220, f-80)) / 220;
536 hud_field_rgb = '1 1 1' - '0 1 1'*tmp;
542 f = pl.ping_packetloss;
543 tmp = pl.ping_movementloss;
544 if(f == 0 && tmp == 0)
546 str = ftos(ceil(f * 100));
548 str = strcat(str, "~", ftos(ceil(tmp * 100)));
549 tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
550 hud_field_rgb = '1 0.5 0.5' - '0 0.5 0.5'*tmp;
554 if(ready_waiting && pl.ready)
556 hud_field_icon0 = "gfx/scoreboard/player_ready";
560 f = stof(getplayerkeyvalue(pl.sv_entnum, "colors"));
562 hud_field_icon0 = "gfx/scoreboard/playercolor_base";
563 hud_field_icon1 = "gfx/scoreboard/playercolor_shirt";
564 hud_field_icon1_rgb = colormapPaletteColor(floor(f / 16), 0);
565 hud_field_icon2 = "gfx/scoreboard/playercolor_pants";
566 hud_field_icon2_rgb = colormapPaletteColor(mod(f, 16), 1);
569 return GetPlayerName(pl.sv_entnum);
572 f = pl.(scores[SP_KILLS]);
573 f -= pl.(scores[SP_SUICIDES]);
577 num = pl.(scores[SP_KILLS]);
578 denom = pl.(scores[SP_DEATHS]);
581 hud_field_rgb = '0 1 0';
582 str = sprintf("%d", num);
583 } else if(num <= 0) {
584 hud_field_rgb = '1 0 0';
585 str = sprintf("%.1f", num/denom);
587 str = sprintf("%.1f", num/denom);
591 f = pl.(scores[SP_KILLS]);
592 f -= pl.(scores[SP_DEATHS]);
595 hud_field_rgb = '0 1 0';
597 hud_field_rgb = '1 1 1';
599 hud_field_rgb = '1 0 0';
604 tmp = pl.(scores[field]);
605 f = scores_flags[field];
606 if(field == ps_primary)
607 hud_field_rgb = '1 1 0';
608 else if(field == ps_secondary)
609 hud_field_rgb = '0 1 1';
611 hud_field_rgb = '1 1 1';
612 return ScoreString(f, tmp);
617 float xmin, xmax, ymin, ymax, sbwidth;
618 float hud_fixscoreboardcolumnwidth_len;
619 float hud_fixscoreboardcolumnwidth_iconlen;
620 float hud_fixscoreboardcolumnwidth_marginlen;
622 string HUD_FixScoreboardColumnWidth(float i, string str)
626 field = hud_field[i];
628 hud_fixscoreboardcolumnwidth_iconlen = 0;
630 if(hud_field_icon0 != "")
632 sz = draw_getimagesize(hud_field_icon0);
634 if(hud_fixscoreboardcolumnwidth_iconlen < f)
635 hud_fixscoreboardcolumnwidth_iconlen = f;
638 if(hud_field_icon1 != "")
640 sz = draw_getimagesize(hud_field_icon1);
642 if(hud_fixscoreboardcolumnwidth_iconlen < f)
643 hud_fixscoreboardcolumnwidth_iconlen = f;
646 if(hud_field_icon2 != "")
648 sz = draw_getimagesize(hud_field_icon2);
650 if(hud_fixscoreboardcolumnwidth_iconlen < f)
651 hud_fixscoreboardcolumnwidth_iconlen = f;
654 hud_fixscoreboardcolumnwidth_iconlen *= hud_fontsize_y / hud_fontsize_x; // fix icon aspect
656 if(hud_fixscoreboardcolumnwidth_iconlen != 0)
657 hud_fixscoreboardcolumnwidth_marginlen = stringwidth(" ", FALSE, hud_fontsize);
659 hud_fixscoreboardcolumnwidth_marginlen = 0;
661 if(field == SP_NAME) // name gets all remaining space
664 namesize = sbwidth;// / hud_fontsize_x;
665 for(j = 0; j < hud_num_fields; ++j)
667 if (hud_field[i] != SP_SEPARATOR)
668 namesize -= hud_size[j] + hud_fontsize_x;
669 namesize += hud_fontsize_x;
670 hud_size[i] = namesize;
672 if (hud_fixscoreboardcolumnwidth_iconlen != 0)
673 namesize -= hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
674 str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
675 hud_fixscoreboardcolumnwidth_len = stringwidth(str, TRUE, hud_fontsize);
678 hud_fixscoreboardcolumnwidth_len = stringwidth(str, FALSE, hud_fontsize);
680 f = hud_fixscoreboardcolumnwidth_len + hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
687 void HUD_PrintScoreboardItem(vector pos, entity pl, float is_self, float pl_number)
690 rgb = Team_ColorRGB(pl.team);
694 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
696 if((rgb == '1 1 1') && (!is_spec)) {
697 rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
698 rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
699 rgb_z = autocvar_scoreboard_color_bg_b + 0.5; }
703 tmp_y = hud_fontsize_y * 1.25;
706 // alternated rows highlighting
708 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
709 else if((scoreboard_highlight) && (!mod(pl_number,2)))
710 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
714 for(i = 0; i < hud_num_fields; ++i)
716 field = hud_field[i];
717 if(field == SP_SEPARATOR)
720 if(is_spec && field != SP_NAME && field != SP_PING) {
721 pos_x += hud_size[i] + hud_fontsize_x;
724 str = HUD_GetField(pl, field);
725 str = HUD_FixScoreboardColumnWidth(i, str);
727 pos_x += hud_size[i] + hud_fontsize_x;
729 if(field == SP_NAME) {
730 tmp_x = hud_size[i] - hud_fontsize_x*hud_fixscoreboardcolumnwidth_iconlen - hud_fixscoreboardcolumnwidth_marginlen + hud_fontsize_x;
732 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
734 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
736 tmp_x = hud_fixscoreboardcolumnwidth_len + hud_fontsize_x;
738 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
740 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
743 tmp_x = hud_size[i] + hud_fontsize_x;
744 if(hud_field_icon0 != "")
746 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);
748 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);
749 if(hud_field_icon1 != "")
751 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);
753 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);
754 if(hud_field_icon2 != "")
756 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);
758 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);
761 if(hud_field[i] == SP_SEPARATOR)
764 for(i = hud_num_fields-1; i > 0; --i)
766 field = hud_field[i];
767 if(field == SP_SEPARATOR)
770 if(is_spec && field != SP_NAME && field != SP_PING) {
771 pos_x -= hud_size[i] + hud_fontsize_x;
775 str = HUD_GetField(pl, field);
776 str = HUD_FixScoreboardColumnWidth(i, str);
778 if(field == SP_NAME) {
779 tmp_x = hud_fixscoreboardcolumnwidth_len; // left or right aligned? let's put it right...
781 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
783 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
785 tmp_x = hud_fixscoreboardcolumnwidth_len;
787 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
789 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
793 if(hud_field_icon0 != "")
795 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);
797 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);
798 if(hud_field_icon1 != "")
800 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);
802 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);
803 if(hud_field_icon2 != "")
805 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);
807 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);
808 pos_x -= hud_size[i] + hud_fontsize_x;
814 * HUD_Scoreboard_MakeTable
816 * Makes a table for a team (for all playing players in DM) and fills it
819 vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
821 float body_table_height, i;
822 vector tmp = '0 0 0', column_dim = '0 0 0';
825 body_table_height = 1.25 * hud_fontsize_y * max(1, tm.team_size); // no player? show 1 empty line
827 pos_y += autocvar_scoreboard_border_thickness;
831 tmp_y = 1.25 * hud_fontsize_y;
835 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, (rgb * autocvar_scoreboard_color_bg_team) + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
837 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
840 tmp_y += autocvar_scoreboard_border_thickness;
841 tmp_y += body_table_height;
842 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // more transparency for the scoreboard
844 // separator header/table
845 pos_y += 1.25 * hud_fontsize_y;
846 tmp_y = autocvar_scoreboard_border_thickness;
847 drawfill(pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
849 pos_y += autocvar_scoreboard_border_thickness;
852 tmp_y = body_table_height;
854 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
856 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
858 // anyway, apply some color
859 //drawfill(pos, tmp + '2 0 0', rgb, 0.1, DRAWFLAG_NORMAL);
861 // go back to the top to make alternated columns highlighting and to print the strings
862 pos_y -= 1.25 * hud_fontsize_y;
863 pos_y -= autocvar_scoreboard_border_thickness;
867 if (scoreboard_highlight)
869 column_dim_y = 1.25 * hud_fontsize_y; // header
870 column_dim_y += autocvar_scoreboard_border_thickness;
871 column_dim_y += body_table_height;
874 // print the strings of the columns headers and draw the columns
875 draw_beginBoldFont();
876 for(i = 0; i < hud_num_fields; ++i)
878 if(hud_field[i] == SP_SEPARATOR)
880 column_dim_x = hud_size[i] + hud_fontsize_x;
881 if (scoreboard_highlight)
884 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
886 drawstring(pos, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
887 pos_x += column_dim_x;
889 if(hud_field[i] == SP_SEPARATOR)
893 for(i = hud_num_fields-1; i > 0; --i)
895 if(hud_field[i] == SP_SEPARATOR)
898 pos_x -= hud_size[i];
900 if (scoreboard_highlight)
904 if (i == hud_num_fields-1)
905 column_dim_x = hud_size[i] + hud_fontsize_x / 2 + 1;
907 column_dim_x = hud_size[i] + hud_fontsize_x;
908 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
912 tmp_x = stringwidth(hud_title[i], FALSE, hud_fontsize);
913 tmp_x = (hud_size[i] - tmp_x);
914 drawstring(pos + tmp, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
915 pos_x -= hud_fontsize_x;
921 pos_y += 1.25 * hud_fontsize_y; // skip the header
922 pos_y += autocvar_scoreboard_border_thickness;
924 // fill the table and draw the rows
927 for(pl = players.sort_next; pl; pl = pl.sort_next)
929 if(pl.team != tm.team)
931 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
932 pos_y += 1.25 * hud_fontsize_y;
936 for(pl = players.sort_next; pl; pl = pl.sort_next)
938 if(pl.team == NUM_SPECTATOR)
940 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
941 pos_y += 1.25 * hud_fontsize_y;
946 pos_y += 1.25 * hud_fontsize_y; // move to the end of the table
947 pos_y += 1.25 * hud_fontsize_y; // move empty row (out of the table)
952 float HUD_WouldDrawScoreboard() {
953 if (autocvar__hud_configure)
955 else if (HUD_QuickMenu_IsOpened())
957 else if (scoreboard_showscores)
959 else if (intermission == 1)
961 else if (intermission == 2)
963 else if (spectatee_status != -1 && getstati(STAT_HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS)
965 else if (scoreboard_showscores_force)
970 float average_accuracy;
971 vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
974 float weapon_cnt = WEP_COUNT - 3; // either minstanex/nex are hidden, no port-o-launch, no tuba
976 if(autocvar_scoreboard_accuracy_doublerows)
981 float fontsize = height * 1/3;
982 float weapon_height = height * 2/3;
983 float weapon_width = sbwidth / weapon_cnt;
984 float g_minstagib = 0;
986 drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
987 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
988 vector tmp = '0 0 0';
990 tmp_y = height * rows;
993 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
995 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
996 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
998 // column highlighting
999 for(i = 0; i < weapon_cnt/rows; ++i)
1002 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);
1006 for(i = 0; i < rows; ++i)
1008 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);
1011 average_accuracy = 0;
1012 float weapons_with_stats;
1013 weapons_with_stats = 0;
1015 pos_x += weapon_width / 2;
1017 if(switchweapon == WEP_MINSTANEX)
1018 g_minstagib = 1; // TODO: real detection for minstagib?
1021 if(autocvar_scoreboard_accuracy_nocolors)
1024 Accuracy_LoadColors();
1026 for(i = WEP_FIRST; i <= WEP_LAST; ++i)
1028 self = get_weaponinfo(i);
1031 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
1033 weapon_stats = weapon_accuracy[i-WEP_FIRST];
1036 if(weapon_stats >= 0)
1037 weapon_alpha = scoreboard_alpha_fg;
1039 weapon_alpha = 0.2 * scoreboard_alpha_fg;
1042 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);
1044 if(weapon_stats >= 0) {
1045 weapons_with_stats += 1;
1046 average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
1049 s = sprintf(_("%d%%"), weapon_stats*100);
1052 padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
1054 if(!autocvar_scoreboard_accuracy_nocolors)
1055 rgb = Accuracy_GetColor(weapon_stats);
1057 drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1059 pos_x += weapon_width * rows;
1060 if(rows == 2 && i == 6) {
1066 if(weapons_with_stats)
1067 average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
1070 pos_x -= weapon_width / 2;
1074 pos_y += 1.25 * hud_fontsize_y;
1078 vector HUD_DrawKeyValue(vector pos, string key, string value) {
1080 pos_x += hud_fontsize_x * 0.25;
1081 drawstring(pos, key, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1082 pos_x = xmax - stringwidth(value, FALSE, hud_fontsize) - hud_fontsize_x * 0.25;
1083 drawstring(pos, value, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1085 pos_y+= hud_fontsize_y;
1090 vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
1091 float stat_secrets_found, stat_secrets_total;
1095 // get secrets stats
1096 stat_secrets_found = getstatf(STAT_SECRETS_FOUND);
1097 stat_secrets_total = getstatf(STAT_SECRETS_TOTAL);
1099 // get number of rows
1100 rows = (stat_secrets_total ? 1 : 0);
1102 // if no rows, return
1106 // draw table header
1107 drawstring(pos, _("Map stats:"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1108 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
1111 vector tmp = '0 0 0';
1113 tmp_y = hud_fontsize_y * rows;
1116 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1118 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1119 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1122 val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
1123 pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val);
1126 pos_y += 1.25 * hud_fontsize_y;
1131 vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_size)
1134 RANKINGS_RECEIVED_CNT = 0;
1135 for (i=RANKINGS_CNT-1; i>=0; --i)
1137 ++RANKINGS_RECEIVED_CNT;
1139 if (RANKINGS_RECEIVED_CNT == 0)
1143 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
1145 hl_rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
1146 hl_rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
1147 hl_rgb_z = autocvar_scoreboard_color_bg_b + 0.5;
1149 pos_y += hud_fontsize_y;
1150 drawstring(pos, _("Rankings"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1151 pos_y += hud_fontsize_y + autocvar_scoreboard_border_thickness;
1152 vector tmp = '0 0 0';
1154 tmp_y = 1.25 * hud_fontsize_y * RANKINGS_RECEIVED_CNT;
1157 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1159 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1160 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1163 for(i = 0; i<RANKINGS_RECEIVED_CNT; ++i)
1170 n = grecordholder[i];
1171 p = count_ordinal(i+1);
1172 if(grecordholder[i] == GetPlayerName(player_localnum))
1173 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
1174 else if(!mod(i, 2) && scoreboard_highlight)
1175 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
1176 drawstring(pos, p, '1 1 0' * hud_fontsize_y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1177 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);
1178 drawcolorcodedstring(pos + '8 0 0' * hud_fontsize_y, n, '1 1 0' * hud_fontsize_y, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1179 pos_y += 1.25 * hud_fontsize_y;
1181 pos_y += autocvar_scoreboard_border_thickness;
1186 float hud_woulddrawscoreboard_prev;
1187 float hud_woulddrawscoreboard_change; // "time" at which HUD_WouldDrawScoreboard() changed
1188 void HUD_DrawScoreboard()
1190 float hud_woulddrawscoreboard;
1191 hud_woulddrawscoreboard = scoreboard_active;
1192 if(hud_woulddrawscoreboard != hud_woulddrawscoreboard_prev) {
1193 hud_woulddrawscoreboard_change = time;
1194 hud_woulddrawscoreboard_prev = hud_woulddrawscoreboard;
1197 if(hud_woulddrawscoreboard) {
1198 float scoreboard_fadeinspeed = autocvar_scoreboard_fadeinspeed;
1199 if (scoreboard_fadeinspeed)
1200 scoreboard_fade_alpha = bound (0, (time - hud_woulddrawscoreboard_change) * scoreboard_fadeinspeed, 1);
1202 scoreboard_fade_alpha = 1;
1205 float scoreboard_fadeoutspeed = autocvar_scoreboard_fadeoutspeed;
1206 if (scoreboard_fadeoutspeed)
1207 scoreboard_fade_alpha = bound (0, (1/scoreboard_fadeoutspeed - (time - hud_woulddrawscoreboard_change)) * scoreboard_fadeoutspeed, 1);
1209 scoreboard_fade_alpha = 0;
1212 if (!scoreboard_fade_alpha)
1215 HUD_UpdatePlayerTeams();
1217 scoreboard_alpha_bg = autocvar_scoreboard_alpha_bg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1218 scoreboard_alpha_fg = autocvar_scoreboard_alpha_fg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1219 scoreboard_highlight = autocvar_scoreboard_highlight;
1220 scoreboard_highlight_alpha = autocvar_scoreboard_highlight_alpha * scoreboard_alpha_fg;
1221 scoreboard_highlight_alpha_self = autocvar_scoreboard_highlight_alpha_self * scoreboard_alpha_fg;
1222 scoreboard_alpha_name = autocvar_scoreboard_alpha_name * scoreboard_alpha_fg;
1223 scoreboard_alpha_name_self = autocvar_scoreboard_alpha_name_self * scoreboard_alpha_fg;
1225 vector rgb, pos, tmp;
1229 xmin = (autocvar_scoreboard_offset_left * vid_conwidth);
1230 ymin = max((autocvar_con_notify * autocvar_con_notifysize), (autocvar_scoreboard_offset_vertical * vid_conwidth));
1232 xmax = ((1 - autocvar_scoreboard_offset_right) * vid_conwidth);
1233 ymax = (vid_conheight - ymin);
1235 sbwidth = xmax - xmin;
1237 // Initializes position
1243 vector sb_heading_fontsize;
1244 sb_heading_fontsize = hud_fontsize * 2;
1245 draw_beginBoldFont();
1246 drawstring(pos, _("Scoreboard"), sb_heading_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1249 pos_y += sb_heading_fontsize_y + hud_fontsize_y * 0.25;
1251 // Draw the scoreboard
1252 vector bg_size = draw_getimagesize("gfx/scoreboard/scoreboard_bg") * autocvar_scoreboard_bg_scale;
1256 vector team_score_baseoffset;
1257 team_score_baseoffset = eY * (2 * autocvar_scoreboard_border_thickness + hud_fontsize_y) - eX * (autocvar_scoreboard_border_thickness + hud_fontsize_x * 0.25);
1258 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1260 if(tm.team == NUM_SPECTATOR)
1263 draw_beginBoldFont();
1264 rgb = Team_ColorRGB(tm.team);
1265 str = ftos(tm.(teamscores[ts_primary]));
1266 drawstring(pos + team_score_baseoffset - eX * stringwidth(str, FALSE, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1268 if(ts_primary != ts_secondary)
1270 str = ftos(tm.(teamscores[ts_secondary]));
1271 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);
1275 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1281 rgb_x = autocvar_scoreboard_color_bg_r;
1282 rgb_y = autocvar_scoreboard_color_bg_g;
1283 rgb_z = autocvar_scoreboard_color_bg_b;
1290 rgb_x = autocvar_scoreboard_color_bg_r;
1291 rgb_y = autocvar_scoreboard_color_bg_g;
1292 rgb_z = autocvar_scoreboard_color_bg_b;
1294 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1296 if(tm.team == NUM_SPECTATOR)
1299 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1303 if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE) {
1304 if(race_speedaward) {
1305 drawcolorcodedstring(pos, sprintf(_("Speed award: %d ^7(%s^7)"), race_speedaward, race_speedaward_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1306 pos_y += 1.25 * hud_fontsize_y;
1308 if(race_speedaward_alltimebest) {
1309 drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1310 pos_y += 1.25 * hud_fontsize_y;
1312 pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
1314 else if(autocvar_scoreboard_accuracy && spectatee_status != -1 && !warmup_stage) {
1316 pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size);
1318 pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size);
1323 pos = HUD_DrawMapStats(pos, Team_ColorRGB(myteam), bg_size);
1325 pos = HUD_DrawMapStats(pos, rgb, bg_size);
1331 for(pl = players.sort_next; pl; pl = pl.sort_next)
1333 if(pl.team != NUM_SPECTATOR)
1335 pos_y += 1.25 * hud_fontsize_y;
1336 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), specs);
1342 draw_beginBoldFont();
1343 drawstring(tmp, _("Spectators"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1345 pos_y += 1.25 * hud_fontsize_y;
1348 // Print info string
1350 str = sprintf(_("playing on ^2%s^7"), shortmapname);
1351 tl = getstatf(STAT_TIMELIMIT);
1352 fl = getstatf(STAT_FRAGLIMIT);
1353 ll = getstatf(STAT_LEADLIMIT);
1354 if(gametype == MAPINFO_TYPE_LMS)
1357 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1362 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1366 str = strcat(str, _(" or"));
1369 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], fl),
1370 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1371 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1372 TranslateScoresLabel(teamscores_label[ts_primary])));
1376 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(scores_flags[ps_primary], fl),
1377 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1378 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1379 TranslateScoresLabel(scores_label[ps_primary])));
1384 if(tl > 0 || fl > 0)
1385 str = strcat(str, _(" or"));
1388 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], ll),
1389 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1390 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1391 TranslateScoresLabel(teamscores_label[ts_primary])));
1395 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(scores_flags[ps_primary], ll),
1396 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1397 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1398 TranslateScoresLabel(scores_label[ps_primary])));
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);
1406 // print information about respawn status
1407 float respawn_time = getstatf(STAT_RESPAWN_TIME);
1410 if(respawn_time < 0)
1412 // a negative number means we are awaiting respawn, time value is still the same
1413 respawn_time *= -1; // remove mark now that we checked it
1414 respawn_time = max(time, respawn_time); // don't show a negative value while the server is respawning the player (lag)
1416 str = sprintf(_("^1Respawning in ^3%s^1..."),
1417 (autocvar_scoreboard_respawntime_decimals ?
1418 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1420 count_seconds(respawn_time - time)
1424 else if(time < respawn_time)
1426 str = sprintf(_("You are dead, wait ^3%s^7 before respawning"),
1427 (autocvar_scoreboard_respawntime_decimals ?
1428 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1430 count_seconds(respawn_time - time)
1434 else if(time >= respawn_time)
1435 str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
1437 pos_y += 1.2 * hud_fontsize_y;
1438 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1441 scoreboard_bottom = pos_y + 2 * hud_fontsize_y;