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 print(sprintf("^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 print(sprintf("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 print(sprintf("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 (scoreboard_showscores)
957 else if (intermission == 1)
959 else if (intermission == 2)
961 else if (spectatee_status != -1 && getstati(STAT_HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS)
963 else if (scoreboard_showscores_force)
968 float average_accuracy;
969 vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
972 float weapon_cnt = WEP_COUNT - 3; // either minstanex/nex are hidden, no port-o-launch, no tuba
974 if(autocvar_scoreboard_accuracy_doublerows)
979 float fontsize = height * 1/3;
980 float weapon_height = height * 2/3;
981 float weapon_width = sbwidth / weapon_cnt;
982 float g_minstagib = 0;
984 drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
985 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
986 vector tmp = '0 0 0';
988 tmp_y = height * rows;
991 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
993 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
994 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
996 // column highlighting
997 for(i = 0; i < weapon_cnt/rows; ++i)
1000 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);
1004 for(i = 0; i < rows; ++i)
1006 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);
1009 average_accuracy = 0;
1010 float weapons_with_stats;
1011 weapons_with_stats = 0;
1013 pos_x += weapon_width / 2;
1015 if(switchweapon == WEP_MINSTANEX)
1016 g_minstagib = 1; // TODO: real detection for minstagib?
1019 if(autocvar_scoreboard_accuracy_nocolors)
1022 Accuracy_LoadColors();
1024 for(i = WEP_FIRST; i <= WEP_LAST; ++i)
1026 self = get_weaponinfo(i);
1029 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
1031 weapon_stats = weapon_accuracy[i-WEP_FIRST];
1034 if(weapon_stats >= 0)
1035 weapon_alpha = scoreboard_alpha_fg;
1037 weapon_alpha = 0.2 * scoreboard_alpha_fg;
1040 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);
1042 if(weapon_stats >= 0) {
1043 weapons_with_stats += 1;
1044 average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
1047 s = sprintf(_("%d%%"), weapon_stats*100);
1050 padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
1052 if(!autocvar_scoreboard_accuracy_nocolors)
1053 rgb = Accuracy_GetColor(weapon_stats);
1055 drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1057 pos_x += weapon_width * rows;
1058 if(rows == 2 && i == 6) {
1064 if(weapons_with_stats)
1065 average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
1068 pos_x -= weapon_width / 2;
1072 pos_y += 1.25 * hud_fontsize_y;
1076 vector HUD_DrawKeyValue(vector pos, string key, string value) {
1078 pos_x += hud_fontsize_x * 0.25;
1079 drawstring(pos, key, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1080 pos_x = xmax - stringwidth(value, FALSE, hud_fontsize) - hud_fontsize_x * 0.25;
1081 drawstring(pos, value, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1083 pos_y+= hud_fontsize_y;
1088 vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
1089 float stat_secrets_found, stat_secrets_total;
1090 float stat_monsters_killed, stat_monsters_total;
1094 // get monster stats
1095 stat_monsters_killed = getstatf(STAT_MONSTERS_KILLED);
1096 stat_monsters_total = getstatf(STAT_MONSTERS_TOTAL);
1098 // get secrets stats
1099 stat_secrets_found = getstatf(STAT_SECRETS_FOUND);
1100 stat_secrets_total = getstatf(STAT_SECRETS_TOTAL);
1102 // get number of rows
1103 if(stat_secrets_total)
1105 if(stat_monsters_total)
1108 // if no rows, return
1112 // draw table header
1113 drawstring(pos, _("Map stats:"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1114 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
1117 vector tmp = '0 0 0';
1119 tmp_y = hud_fontsize_y * rows;
1122 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1124 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1125 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1128 if(stat_monsters_total)
1130 val = sprintf("%d/%d", stat_monsters_killed, stat_monsters_total);
1131 pos = HUD_DrawKeyValue(pos, _("Monsters killed:"), val);
1135 if(stat_secrets_total)
1137 val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
1138 pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val);
1142 pos_y += 1.25 * hud_fontsize_y;
1147 vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_size)
1150 RANKINGS_RECEIVED_CNT = 0;
1151 for (i=RANKINGS_CNT-1; i>=0; --i)
1153 ++RANKINGS_RECEIVED_CNT;
1155 if (RANKINGS_RECEIVED_CNT == 0)
1159 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
1161 hl_rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
1162 hl_rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
1163 hl_rgb_z = autocvar_scoreboard_color_bg_b + 0.5;
1165 pos_y += hud_fontsize_y;
1166 drawstring(pos, _("Rankings"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1167 pos_y += hud_fontsize_y + autocvar_scoreboard_border_thickness;
1168 vector tmp = '0 0 0';
1170 tmp_y = 1.25 * hud_fontsize_y * RANKINGS_RECEIVED_CNT;
1173 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1175 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1176 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1179 for(i = 0; i<RANKINGS_RECEIVED_CNT; ++i)
1186 n = grecordholder[i];
1187 p = count_ordinal(i+1);
1188 if(grecordholder[i] == GetPlayerName(player_localnum))
1189 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
1190 else if(!mod(i, 2) && scoreboard_highlight)
1191 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
1192 drawstring(pos, p, '1 1 0' * hud_fontsize_y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1193 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);
1194 drawcolorcodedstring(pos + '8 0 0' * hud_fontsize_y, n, '1 1 0' * hud_fontsize_y, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1195 pos_y += 1.25 * hud_fontsize_y;
1197 pos_y += autocvar_scoreboard_border_thickness;
1202 float hud_woulddrawscoreboard_prev;
1203 float hud_woulddrawscoreboard_change; // "time" at which HUD_WouldDrawScoreboard() changed
1204 void HUD_DrawScoreboard()
1206 float hud_woulddrawscoreboard;
1207 hud_woulddrawscoreboard = scoreboard_active;
1208 if(hud_woulddrawscoreboard != hud_woulddrawscoreboard_prev) {
1209 hud_woulddrawscoreboard_change = time;
1210 hud_woulddrawscoreboard_prev = hud_woulddrawscoreboard;
1213 if(hud_woulddrawscoreboard) {
1214 float scoreboard_fadeinspeed = autocvar_scoreboard_fadeinspeed;
1215 if (scoreboard_fadeinspeed)
1216 scoreboard_fade_alpha = bound (0, (time - hud_woulddrawscoreboard_change) * scoreboard_fadeinspeed, 1);
1218 scoreboard_fade_alpha = 1;
1221 float scoreboard_fadeoutspeed = autocvar_scoreboard_fadeoutspeed;
1222 if (scoreboard_fadeoutspeed)
1223 scoreboard_fade_alpha = bound (0, (1/scoreboard_fadeoutspeed - (time - hud_woulddrawscoreboard_change)) * scoreboard_fadeoutspeed, 1);
1225 scoreboard_fade_alpha = 0;
1228 if (!scoreboard_fade_alpha)
1231 HUD_UpdatePlayerTeams();
1233 scoreboard_alpha_bg = autocvar_scoreboard_alpha_bg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1234 scoreboard_alpha_fg = autocvar_scoreboard_alpha_fg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1235 scoreboard_highlight = autocvar_scoreboard_highlight;
1236 scoreboard_highlight_alpha = autocvar_scoreboard_highlight_alpha * scoreboard_alpha_fg;
1237 scoreboard_highlight_alpha_self = autocvar_scoreboard_highlight_alpha_self * scoreboard_alpha_fg;
1238 scoreboard_alpha_name = autocvar_scoreboard_alpha_name * scoreboard_alpha_fg;
1239 scoreboard_alpha_name_self = autocvar_scoreboard_alpha_name_self * scoreboard_alpha_fg;
1241 vector rgb, pos, tmp;
1245 xmin = (autocvar_scoreboard_offset_left * vid_conwidth);
1246 ymin = max((autocvar_con_notify * autocvar_con_notifysize), (autocvar_scoreboard_offset_vertical * vid_conwidth));
1248 xmax = ((1 - autocvar_scoreboard_offset_right) * vid_conwidth);
1249 ymax = (vid_conheight - ymin);
1251 sbwidth = xmax - xmin;
1253 // Initializes position
1259 vector sb_heading_fontsize;
1260 sb_heading_fontsize = hud_fontsize * 2;
1261 draw_beginBoldFont();
1262 drawstring(pos, _("Scoreboard"), sb_heading_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1265 pos_y += sb_heading_fontsize_y + hud_fontsize_y * 0.25;
1267 // Draw the scoreboard
1268 vector bg_size = draw_getimagesize("gfx/scoreboard/scoreboard_bg") * autocvar_scoreboard_bg_scale;
1272 vector team_score_baseoffset;
1273 team_score_baseoffset = eY * (2 * autocvar_scoreboard_border_thickness + hud_fontsize_y) - eX * (autocvar_scoreboard_border_thickness + hud_fontsize_x * 0.25);
1274 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1276 if(tm.team == NUM_SPECTATOR)
1279 draw_beginBoldFont();
1280 rgb = Team_ColorRGB(tm.team);
1281 str = ftos(tm.(teamscores[ts_primary]));
1282 drawstring(pos + team_score_baseoffset - eX * stringwidth(str, FALSE, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1284 if(ts_primary != ts_secondary)
1286 str = ftos(tm.(teamscores[ts_secondary]));
1287 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);
1291 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1297 rgb_x = autocvar_scoreboard_color_bg_r;
1298 rgb_y = autocvar_scoreboard_color_bg_g;
1299 rgb_z = autocvar_scoreboard_color_bg_b;
1306 rgb_x = autocvar_scoreboard_color_bg_r;
1307 rgb_y = autocvar_scoreboard_color_bg_g;
1308 rgb_z = autocvar_scoreboard_color_bg_b;
1310 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1312 if(tm.team == NUM_SPECTATOR)
1315 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1319 if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE) {
1320 if(race_speedaward) {
1321 drawcolorcodedstring(pos, sprintf(_("Speed award: %d ^7(%s^7)"), race_speedaward, race_speedaward_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1322 pos_y += 1.25 * hud_fontsize_y;
1324 if(race_speedaward_alltimebest) {
1325 drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1326 pos_y += 1.25 * hud_fontsize_y;
1328 pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
1330 else if(autocvar_scoreboard_accuracy && spectatee_status != -1 && !warmup_stage) {
1332 pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size);
1334 pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size);
1339 pos = HUD_DrawMapStats(pos, Team_ColorRGB(myteam), bg_size);
1341 pos = HUD_DrawMapStats(pos, rgb, bg_size);
1347 for(pl = players.sort_next; pl; pl = pl.sort_next)
1349 if(pl.team != NUM_SPECTATOR)
1351 pos_y += 1.25 * hud_fontsize_y;
1352 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), specs);
1358 draw_beginBoldFont();
1359 drawstring(tmp, _("Spectators"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1361 pos_y += 1.25 * hud_fontsize_y;
1364 // Print info string
1366 str = sprintf(_("playing on ^2%s^7"), shortmapname);
1367 tl = getstatf(STAT_TIMELIMIT);
1368 fl = getstatf(STAT_FRAGLIMIT);
1369 ll = getstatf(STAT_LEADLIMIT);
1370 if(gametype == MAPINFO_TYPE_LMS)
1373 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1378 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1382 str = strcat(str, _(" or"));
1385 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], fl),
1386 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1387 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1388 TranslateScoresLabel(teamscores_label[ts_primary])));
1392 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(scores_flags[ps_primary], fl),
1393 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1394 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1395 TranslateScoresLabel(scores_label[ps_primary])));
1400 if(tl > 0 || fl > 0)
1401 str = strcat(str, _(" or"));
1404 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], ll),
1405 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1406 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1407 TranslateScoresLabel(teamscores_label[ts_primary])));
1411 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(scores_flags[ps_primary], ll),
1412 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1413 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1414 TranslateScoresLabel(scores_label[ps_primary])));
1419 pos_y += 1.2 * hud_fontsize_y;
1420 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1422 // print information about respawn status
1423 float respawn_time = getstatf(STAT_RESPAWN_TIME);
1426 if(respawn_time < 0)
1428 // a negative number means we are awaiting respawn, time value is still the same
1429 respawn_time *= -1; // remove mark now that we checked it
1430 respawn_time = max(time, respawn_time); // don't show a negative value while the server is respawning the player (lag)
1432 str = sprintf(_("^1Respawning in ^3%s^1..."),
1433 (autocvar_scoreboard_respawntime_decimals ?
1434 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1436 count_seconds(respawn_time - time)
1440 else if(time < respawn_time)
1442 str = sprintf(_("You are dead, wait ^3%s^7 before respawning"),
1443 (autocvar_scoreboard_respawntime_decimals ?
1444 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1446 count_seconds(respawn_time - time)
1450 else if(time >= respawn_time)
1451 str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
1453 pos_y += 1.2 * hud_fontsize_y;
1454 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1457 scoreboard_bottom = pos_y + 2 * hud_fontsize_y;