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"));
57 void HUD_FinaleOverlay()
60 pos_x = (vid_conwidth - 1)/2;
64 //drawpic(pos, "gfx/finale", '0 0 0', '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
66 //drawstring(pos, "END", hud_fontsize, '1 1 1', 1, DRAWFLAG_NORMAL);
70 void Cmd_HUD_SetFields(float argc);
75 ps_primary = ps_secondary = ts_primary = ts_secondary = -1;
76 for(i = 0; i < MAX_SCORE; ++i)
78 f = (scores_flags[i] & SFL_SORT_PRIO_MASK);
79 if(f == SFL_SORT_PRIO_PRIMARY)
81 if(f == SFL_SORT_PRIO_SECONDARY)
84 if(ps_secondary == -1)
85 ps_secondary = ps_primary;
87 for(i = 0; i < MAX_TEAMSCORE; ++i)
89 f = (teamscores_flags[i] & SFL_SORT_PRIO_MASK);
90 if(f == SFL_SORT_PRIO_PRIMARY)
92 if(f == SFL_SORT_PRIO_SECONDARY)
95 if(ts_secondary == -1)
96 ts_secondary = ts_primary;
101 void HUD_UpdatePlayerPos(entity pl);
102 float SetTeam(entity pl, float Team);
104 void HUD_UpdatePlayerTeams()
111 for(pl = players.sort_next; pl; pl = pl.sort_next)
114 Team = GetPlayerColor(pl.sv_entnum);
115 if(SetTeam(pl, Team))
118 HUD_UpdatePlayerPos(pl);
122 pl = players.sort_next;
127 print(strcat("PNUM: ", ftos(num), "\n"));
132 float HUD_CompareScore(float vl, float vr, float f)
134 if(f & SFL_ZERO_IS_WORST)
136 if(vl == 0 && vr != 0)
138 if(vl != 0 && vr == 0)
142 return IS_INCREASING(f);
144 return IS_DECREASING(f);
148 float HUD_ComparePlayerScores(entity left, entity right)
151 vl = GetPlayerColor(left.sv_entnum);
152 vr = GetPlayerColor(right.sv_entnum);
164 if(vl == NUM_SPECTATOR)
166 // FIRST the one with scores (spectators), THEN the ones without (downloaders)
168 if(!left.gotscores && right.gotscores)
173 r = HUD_CompareScore(left.scores[ps_primary], right.scores[ps_primary], scores_flags[ps_primary]);
177 r = HUD_CompareScore(left.scores[ps_secondary], right.scores[ps_secondary], scores_flags[ps_secondary]);
181 for(i = 0; i < MAX_SCORE; ++i)
183 r = HUD_CompareScore(left.scores[i], right.scores[i], scores_flags[i]);
188 if (left.sv_entnum < right.sv_entnum)
194 void HUD_UpdatePlayerPos(entity player)
196 for(other = player.sort_next; other && HUD_ComparePlayerScores(player, other); other = player.sort_next)
198 SORT_SWAP(player, other);
200 for(other = player.sort_prev; other != players && HUD_ComparePlayerScores(other, player); other = player.sort_prev)
202 SORT_SWAP(other, player);
206 float HUD_CompareTeamScores(entity left, entity right)
210 if(left.team == NUM_SPECTATOR)
212 if(right.team == NUM_SPECTATOR)
215 r = HUD_CompareScore(left.teamscores[ts_primary], right.teamscores[ts_primary], teamscores_flags[ts_primary]);
219 r = HUD_CompareScore(left.teamscores[ts_secondary], right.teamscores[ts_secondary], teamscores_flags[ts_secondary]);
223 for(i = 0; i < MAX_SCORE; ++i)
225 r = HUD_CompareScore(left.teamscores[i], right.teamscores[i], teamscores_flags[i]);
230 if (left.team < right.team)
236 void HUD_UpdateTeamPos(entity Team)
238 for(other = Team.sort_next; other && HUD_CompareTeamScores(Team, other); other = Team.sort_next)
240 SORT_SWAP(Team, other);
242 for(other = Team.sort_prev; other != teams && HUD_CompareTeamScores(other, Team); other = Team.sort_prev)
244 SORT_SWAP(other, Team);
250 print(_("You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"));
251 print(_("^3|---------------------------------------------------------------|\n"));
252 print(_("Usage:\n"));
253 print(_("^2scoreboard_columns_set default\n"));
254 print(_("^2scoreboard_columns_set ^7field1 field2 ...\n"));
255 print(_("The following field names are recognized (case insensitive):\n"));
256 print(_("You can use a ^3|^7 to start the right-aligned fields.\n\n"));
258 print(_("^3name^7 or ^3nick^7 Name of a player\n"));
259 print(_("^3ping^7 Ping time\n"));
260 print(_("^3pl^7 Packet loss\n"));
261 print(_("^3kills^7 Number of kills\n"));
262 print(_("^3deaths^7 Number of deaths\n"));
263 print(_("^3suicides^7 Number of suicides\n"));
264 print(_("^3frags^7 kills - suicides\n"));
265 print(_("^3kd^7 The kill-death ratio\n"));
266 print(_("^3caps^7 How often a flag (CTF) or a key (KeyHunt) was captured\n"));
267 print(_("^3pickups^7 How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\n"));
268 print(_("^3captime^7 Time of fastest cap (CTF)\n"));
269 print(_("^3fckills^7 Number of flag carrier kills\n"));
270 print(_("^3returns^7 Number of flag returns\n"));
271 print(_("^3drops^7 Number of flag drops\n"));
272 print(_("^3lives^7 Number of lives (LMS)\n"));
273 print(_("^3rank^7 Player rank\n"));
274 print(_("^3pushes^7 Number of players pushed into void\n"));
275 print(_("^3destroyed^7 Number of keys destroyed by pushing them into void\n"));
276 print(_("^3kckills^7 Number of keys carrier kills\n"));
277 print(_("^3losses^7 Number of times a key was lost\n"));
278 print(_("^3laps^7 Number of laps finished (race/cts)\n"));
279 print(_("^3time^7 Total time raced (race/cts)\n"));
280 print(_("^3fastest^7 Time of fastest lap (race/cts)\n"));
281 print(_("^3ticks^7 Number of ticks (DOM)\n"));
282 print(_("^3takes^7 Number of domination points taken (DOM)\n"));
283 print(_("^3bckills^7 Number of ball carrier kills\n"));
284 print(_("^3bctime^7 Total amount of time holding the ball in Keepaway\n"));
285 print(_("^3score^7 Total score\n\n"));
287 print(_("Before a field you can put a + or - sign, then a comma separated list\n"
288 "of game types, then a slash, to make the field show up only in these\n"
289 "or in all but these game types. You can also specify 'all' as a\n"
290 "field to show all fields available for the current game mode.\n\n"));
292 print(_("The special game type names 'teams' and 'noteams' can be used to\n"
293 "include/exclude ALL teams/noteams game modes.\n\n"));
295 print(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"));
296 print(_("will display name, ping and pl aligned to the left, and the fields\n"
297 "right of the vertical bar aligned to the right.\n"));
298 print(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
299 "other gamemodes except DM.\n"));
302 string HUD_DefaultColumnLayout()
304 return strcat( // fteqcc sucks
306 "-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"
307 "+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns ",
308 "+lms/lives +lms/rank ",
309 "+kh/caps +kh/pushes +kh/destroyed ",
310 "?+race/laps ?+race/time ?+race/fastest ",
311 "+as/objectives +nexball/faults +nexball/goals +ka/pickups +ka/bckills +ka/bctime +freezetag/revivals ",
312 "-lms,race,nexball/score");
315 void Cmd_HUD_SetFields(float argc)
319 float have_name = 0, have_primary = 0, have_secondary = 0, have_separator = 0;
322 // TODO: re enable with gametype dependant cvars?
323 if(argc < 3) // no arguments provided
324 argc = tokenizebyseparator(strcat("0 1 ", autocvar_scoreboard_columns), " ");
327 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
331 if(argv(2) == "default")
332 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
333 else if(argv(2) == "all")
336 s = "ping pl name |";
337 for(i = 0; i < MAX_SCORE; ++i)
340 if(i != ps_secondary)
341 if(scores_label[i] != "")
342 s = strcat(s, " ", scores_label[i]);
344 if(ps_secondary != ps_primary)
345 s = strcat(s, " ", scores_label[ps_secondary]);
346 s = strcat(s, " ", scores_label[ps_primary]);
347 argc = tokenizebyseparator(strcat("0 1 ", s), " ");
354 hud_fontsize = HUD_GetFontsize("hud_fontsize");
356 draw_beginBoldFont();
357 for(i = 1; i < argc - 1; ++i)
363 if(substring(str, 0, 1) == "?")
366 str = substring(str, 1, strlen(str) - 1);
369 slash = strstrofs(str, "/", 0);
372 pattern = substring(str, 0, slash);
373 str = substring(str, slash + 1, strlen(str) - (slash + 1));
375 if not(isGametypeInFilter(gametype, teamplay, FALSE, pattern))
379 strunzone(hud_title[hud_num_fields]);
380 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(str));
381 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
382 str = strtolower(str);
385 hud_field[hud_num_fields] = SP_PING;
386 } else if(str == "pl") {
387 hud_field[hud_num_fields] = SP_PL;
388 } else if(str == "kd" || str == "kdr" || str == "kdratio" || str == "k/d") {
389 hud_field[hud_num_fields] = SP_KDRATIO;
390 } else if(str == "name" || str == "nick") {
391 hud_field[hud_num_fields] = SP_NAME;
393 } else if(str == "|") {
394 hud_field[hud_num_fields] = SP_SEPARATOR;
397 for(j = 0; j < MAX_SCORE; ++j)
398 if(str == strtolower(scores_label[j]))
399 goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
408 print(sprintf("^1Error:^7 Unknown score field: '%s'\n", str));
412 hud_field[hud_num_fields] = j;
415 if(j == ps_secondary)
419 if(hud_num_fields >= MAX_HUD_FIELDS)
423 if(scores_flags[ps_primary] & SFL_ALLOW_HIDE)
425 if(scores_flags[ps_secondary] & SFL_ALLOW_HIDE)
427 if(ps_primary == ps_secondary)
429 missing = (!have_primary) + (!have_secondary) + (!have_separator) + (!have_name);
431 if(hud_num_fields+missing < MAX_HUD_FIELDS)
435 strunzone(hud_title[hud_num_fields]);
436 for(i = hud_num_fields; i > 0; --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[0] = strzone(TranslateScoresLabel("name"));
443 hud_field[0] = SP_NAME;
445 print("fixed missing field 'name'\n");
449 strunzone(hud_title[hud_num_fields]);
450 for(i = hud_num_fields; i > 1; --i)
452 hud_title[i] = hud_title[i-1];
453 hud_size[i] = hud_size[i-1];
454 hud_field[i] = hud_field[i-1];
456 hud_title[1] = strzone("|");
457 hud_field[1] = SP_SEPARATOR;
458 hud_size[1] = stringwidth("|", FALSE, hud_fontsize);
460 print("fixed missing field '|'\n");
463 else if(!have_separator)
465 strunzone(hud_title[hud_num_fields]);
466 hud_title[hud_num_fields] = strzone("|");
467 hud_size[hud_num_fields] = stringwidth("|", FALSE, hud_fontsize);
468 hud_field[hud_num_fields] = SP_SEPARATOR;
470 print("fixed missing field '|'\n");
474 strunzone(hud_title[hud_num_fields]);
475 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_secondary]));
476 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
477 hud_field[hud_num_fields] = ps_secondary;
479 print(sprintf("fixed missing field '%s'\n", scores_label[ps_secondary]));
483 strunzone(hud_title[hud_num_fields]);
484 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_primary]));
485 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
486 hud_field[hud_num_fields] = ps_primary;
488 print(sprintf("fixed missing field '%s'\n", scores_label[ps_primary]));
492 hud_field[hud_num_fields] = SP_END;
497 vector hud_field_rgb;
498 string hud_field_icon0;
499 string hud_field_icon1;
500 string hud_field_icon2;
501 vector hud_field_icon0_rgb;
502 vector hud_field_icon1_rgb;
503 vector hud_field_icon2_rgb;
504 float hud_field_icon0_alpha;
505 float hud_field_icon1_alpha;
506 float hud_field_icon2_alpha;
507 string HUD_GetField(entity pl, float field)
509 float tmp, num, denom, f;
511 hud_field_rgb = '1 1 1';
512 hud_field_icon0 = "";
513 hud_field_icon1 = "";
514 hud_field_icon2 = "";
515 hud_field_icon0_rgb = '1 1 1';
516 hud_field_icon1_rgb = '1 1 1';
517 hud_field_icon2_rgb = '1 1 1';
518 hud_field_icon0_alpha = 1;
519 hud_field_icon1_alpha = 1;
520 hud_field_icon2_alpha = 1;
525 return "\xEE\x82\x8D\xEE\x82\x8D\xEE\x82\x8D"; // >>> sign
526 //str = getplayerkeyvalue(pl.sv_entnum, "ping");
530 tmp = max(0, min(220, f-80)) / 220;
531 hud_field_rgb = '1 1 1' - '0 1 1'*tmp;
537 f = pl.ping_packetloss;
538 tmp = pl.ping_movementloss;
539 if(f == 0 && tmp == 0)
541 str = ftos(ceil(f * 100));
543 str = strcat(str, "~", ftos(ceil(tmp * 100)));
544 tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
545 hud_field_rgb = '1 0.5 0.5' - '0 0.5 0.5'*tmp;
549 if(ready_waiting && pl.ready)
551 hud_field_icon0 = "gfx/scoreboard/player_ready";
555 f = stof(getplayerkeyvalue(pl.sv_entnum, "colors"));
557 hud_field_icon0 = "gfx/scoreboard/playercolor_base";
558 hud_field_icon1 = "gfx/scoreboard/playercolor_shirt";
559 hud_field_icon1_rgb = colormapPaletteColor(floor(f / 16), 0);
560 hud_field_icon2 = "gfx/scoreboard/playercolor_pants";
561 hud_field_icon2_rgb = colormapPaletteColor(mod(f, 16), 1);
564 return GetPlayerName(pl.sv_entnum);
567 f = pl.(scores[SP_KILLS]);
568 f -= pl.(scores[SP_SUICIDES]);
572 num = pl.(scores[SP_KILLS]);
573 denom = pl.(scores[SP_DEATHS]);
576 hud_field_rgb = '0 1 0';
577 str = sprintf("%d", num);
578 } else if(num <= 0) {
579 hud_field_rgb = '1 0 0';
580 str = sprintf("%.1f", num/denom);
582 str = sprintf("%.1f", num/denom);
586 tmp = pl.(scores[field]);
587 f = scores_flags[field];
588 if(field == ps_primary)
589 hud_field_rgb = '1 1 0';
590 else if(field == ps_secondary)
591 hud_field_rgb = '0 1 1';
593 hud_field_rgb = '1 1 1';
594 return ScoreString(f, tmp);
599 float xmin, xmax, ymin, ymax, sbwidth;
600 float hud_fixscoreboardcolumnwidth_len;
601 float hud_fixscoreboardcolumnwidth_iconlen;
602 float hud_fixscoreboardcolumnwidth_marginlen;
604 string HUD_FixScoreboardColumnWidth(float i, string str)
608 field = hud_field[i];
610 hud_fixscoreboardcolumnwidth_iconlen = 0;
612 if(hud_field_icon0 != "")
614 sz = draw_getimagesize(hud_field_icon0);
616 if(hud_fixscoreboardcolumnwidth_iconlen < f)
617 hud_fixscoreboardcolumnwidth_iconlen = f;
620 if(hud_field_icon1 != "")
622 sz = draw_getimagesize(hud_field_icon1);
624 if(hud_fixscoreboardcolumnwidth_iconlen < f)
625 hud_fixscoreboardcolumnwidth_iconlen = f;
628 if(hud_field_icon2 != "")
630 sz = draw_getimagesize(hud_field_icon2);
632 if(hud_fixscoreboardcolumnwidth_iconlen < f)
633 hud_fixscoreboardcolumnwidth_iconlen = f;
636 hud_fixscoreboardcolumnwidth_iconlen *= hud_fontsize_y / hud_fontsize_x; // fix icon aspect
638 if(hud_fixscoreboardcolumnwidth_iconlen != 0)
639 hud_fixscoreboardcolumnwidth_marginlen = stringwidth(" ", FALSE, hud_fontsize);
641 hud_fixscoreboardcolumnwidth_marginlen = 0;
643 if(field == SP_NAME) // name gets all remaining space
646 namesize = sbwidth;// / hud_fontsize_x;
647 for(j = 0; j < hud_num_fields; ++j)
649 if (hud_field[i] != SP_SEPARATOR)
650 namesize -= hud_size[j] + hud_fontsize_x;
651 namesize += hud_fontsize_x;
652 hud_size[i] = namesize;
654 if (hud_fixscoreboardcolumnwidth_iconlen != 0)
655 namesize -= hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
656 str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
657 hud_fixscoreboardcolumnwidth_len = stringwidth(str, TRUE, hud_fontsize);
660 hud_fixscoreboardcolumnwidth_len = stringwidth(str, FALSE, hud_fontsize);
662 f = hud_fixscoreboardcolumnwidth_len + hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
669 void HUD_PrintScoreboardItem(vector pos, entity pl, float is_self, float pl_number)
672 rgb = Team_ColorRGB(pl.team);
676 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
678 if((rgb == '1 1 1') && (!is_spec)) {
679 rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
680 rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
681 rgb_z = autocvar_scoreboard_color_bg_b + 0.5; }
685 tmp_y = hud_fontsize_y * 1.25;
688 // alternated rows highlighting
690 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
691 else if((scoreboard_highlight) && (!mod(pl_number,2)))
692 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
696 for(i = 0; i < hud_num_fields; ++i)
698 field = hud_field[i];
699 if(field == SP_SEPARATOR)
702 if(is_spec && field != SP_NAME && field != SP_PING) {
703 pos_x += hud_size[i] + hud_fontsize_x;
706 str = HUD_GetField(pl, field);
707 str = HUD_FixScoreboardColumnWidth(i, str);
709 pos_x += hud_size[i] + hud_fontsize_x;
711 if(field == SP_NAME) {
712 tmp_x = hud_size[i] - hud_fontsize_x*hud_fixscoreboardcolumnwidth_iconlen - hud_fixscoreboardcolumnwidth_marginlen + hud_fontsize_x;
714 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
716 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
718 tmp_x = hud_fixscoreboardcolumnwidth_len + hud_fontsize_x;
720 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
722 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
725 tmp_x = hud_size[i] + hud_fontsize_x;
726 if(hud_field_icon0 != "")
728 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);
730 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);
731 if(hud_field_icon1 != "")
733 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);
735 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);
736 if(hud_field_icon2 != "")
738 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);
740 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);
743 if(hud_field[i] == SP_SEPARATOR)
746 for(i = hud_num_fields-1; i > 0; --i)
748 field = hud_field[i];
749 if(field == SP_SEPARATOR)
752 if(is_spec && field != SP_NAME && field != SP_PING) {
753 pos_x -= hud_size[i] + hud_fontsize_x;
757 str = HUD_GetField(pl, field);
758 str = HUD_FixScoreboardColumnWidth(i, str);
760 if(field == SP_NAME) {
761 tmp_x = hud_fixscoreboardcolumnwidth_len; // left or right aligned? let's put it right...
763 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
765 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
767 tmp_x = hud_fixscoreboardcolumnwidth_len;
769 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
771 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
775 if(hud_field_icon0 != "")
777 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);
779 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);
780 if(hud_field_icon1 != "")
782 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);
784 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);
785 if(hud_field_icon2 != "")
787 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);
789 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);
790 pos_x -= hud_size[i] + hud_fontsize_x;
796 * HUD_Scoreboard_MakeTable
798 * Makes a table for a team (for all playing players in DM) and fills it
801 vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
803 float body_table_height, i;
804 vector tmp = '0 0 0', column_dim = '0 0 0';
807 body_table_height = 1.25 * hud_fontsize_y * max(1, tm.team_size); // no player? show 1 empty line
809 pos_y += autocvar_scoreboard_border_thickness;
813 tmp_y = 1.25 * hud_fontsize_y;
817 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, (rgb * autocvar_scoreboard_color_bg_team) + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
819 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
822 tmp_y += autocvar_scoreboard_border_thickness;
823 tmp_y += body_table_height;
824 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // more transparency for the scoreboard
826 // separator header/table
827 pos_y += 1.25 * hud_fontsize_y;
828 tmp_y = autocvar_scoreboard_border_thickness;
829 drawfill(pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
831 pos_y += autocvar_scoreboard_border_thickness;
834 tmp_y = body_table_height;
836 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
838 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
840 // anyway, apply some color
841 //drawfill(pos, tmp + '2 0 0', rgb, 0.1, DRAWFLAG_NORMAL);
843 // go back to the top to make alternated columns highlighting and to print the strings
844 pos_y -= 1.25 * hud_fontsize_y;
845 pos_y -= autocvar_scoreboard_border_thickness;
849 if (scoreboard_highlight)
851 column_dim_y = 1.25 * hud_fontsize_y; // header
852 column_dim_y += autocvar_scoreboard_border_thickness;
853 column_dim_y += body_table_height;
856 // print the strings of the columns headers and draw the columns
857 draw_beginBoldFont();
858 for(i = 0; i < hud_num_fields; ++i)
860 if(hud_field[i] == SP_SEPARATOR)
862 column_dim_x = hud_size[i] + hud_fontsize_x;
863 if (scoreboard_highlight)
866 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
868 drawstring(pos, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
869 pos_x += column_dim_x;
871 if(hud_field[i] == SP_SEPARATOR)
875 for(i = hud_num_fields-1; i > 0; --i)
877 if(hud_field[i] == SP_SEPARATOR)
880 pos_x -= hud_size[i];
882 if (scoreboard_highlight)
886 if (i == hud_num_fields-1)
887 column_dim_x = hud_size[i] + hud_fontsize_x / 2 + 1;
889 column_dim_x = hud_size[i] + hud_fontsize_x;
890 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
894 tmp_x = stringwidth(hud_title[i], FALSE, hud_fontsize);
895 tmp_x = (hud_size[i] - tmp_x);
896 drawstring(pos + tmp, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
897 pos_x -= hud_fontsize_x;
903 pos_y += 1.25 * hud_fontsize_y; // skip the header
904 pos_y += autocvar_scoreboard_border_thickness;
906 // fill the table and draw the rows
909 for(pl = players.sort_next; pl; pl = pl.sort_next)
911 if(pl.team != tm.team)
913 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
914 pos_y += 1.25 * hud_fontsize_y;
918 for(pl = players.sort_next; pl; pl = pl.sort_next)
920 if(pl.team == NUM_SPECTATOR)
922 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
923 pos_y += 1.25 * hud_fontsize_y;
928 pos_y += 1.25 * hud_fontsize_y; // move to the end of the table
929 pos_y += 1.25 * hud_fontsize_y; // move empty row (out of the table)
934 float HUD_WouldDrawScoreboard() {
935 if (autocvar__hud_configure)
937 else if (scoreboard_showscores)
939 else if (intermission == 1)
941 else if (intermission == 2)
943 else if (spectatee_status != -1 && getstati(STAT_HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS)
945 else if (scoreboard_showscores_force)
950 float average_accuracy;
951 vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
954 float weapon_cnt = WEP_COUNT - 3; // either minstanex/nex are hidden, no port-o-launch, no tuba
956 if(autocvar_scoreboard_accuracy_doublerows)
961 float fontsize = height * 1/3;
962 float weapon_height = height * 2/3;
963 float weapon_width = sbwidth / weapon_cnt;
964 float g_minstagib = 0;
966 drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
967 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
968 vector tmp = '0 0 0';
970 tmp_y = height * rows;
973 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
975 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
976 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
978 // column highlighting
979 for(i = 0; i < weapon_cnt/rows; ++i)
982 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);
986 for(i = 0; i < rows; ++i)
988 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);
991 average_accuracy = 0;
992 float weapons_with_stats;
993 weapons_with_stats = 0;
995 pos_x += weapon_width / 2;
997 if(switchweapon == WEP_MINSTANEX)
998 g_minstagib = 1; // TODO: real detection for minstagib?
1001 if(autocvar_scoreboard_accuracy_nocolors)
1004 Accuracy_LoadColors();
1006 for(i = WEP_FIRST; i <= WEP_LAST; ++i)
1008 self = get_weaponinfo(i);
1011 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
1013 weapon_stats = weapon_accuracy[i-WEP_FIRST];
1016 if(weapon_stats >= 0)
1017 weapon_alpha = scoreboard_alpha_fg;
1019 weapon_alpha = 0.2 * scoreboard_alpha_fg;
1022 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);
1024 if(weapon_stats >= 0) {
1025 weapons_with_stats += 1;
1026 average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
1029 s = sprintf(_("%d%%"), weapon_stats*100);
1032 padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
1034 if(!autocvar_scoreboard_accuracy_nocolors)
1035 rgb = Accuracy_GetColor(weapon_stats);
1037 drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1039 pos_x += weapon_width * rows;
1040 if(rows == 2 && i == 6) {
1046 if(weapons_with_stats)
1047 average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
1050 pos_x -= weapon_width / 2;
1054 pos_y += 1.25 * hud_fontsize_y;
1058 vector HUD_DrawKeyValue(vector pos, string key, string value) {
1060 pos_x += hud_fontsize_x * 0.25;
1061 drawstring(pos, key, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1062 pos_x = xmax - stringwidth(value, FALSE, hud_fontsize) - hud_fontsize_x * 0.25;
1063 drawstring(pos, value, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1065 pos_y+= hud_fontsize_y;
1070 vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
1071 float stat_secrets_found, stat_secrets_total;
1072 float stat_monsters_killed, stat_monsters_total;
1076 // get monster stats
1077 stat_monsters_killed = getstatf(STAT_MONSTERS_KILLED);
1078 stat_monsters_total = getstatf(STAT_MONSTERS_TOTAL);
1080 // get secrets stats
1081 stat_secrets_found = getstatf(STAT_SECRETS_FOUND);
1082 stat_secrets_total = getstatf(STAT_SECRETS_TOTAL);
1084 // get number of rows
1085 if(stat_secrets_total)
1089 if(stat_monsters_total)
1092 // if no rows, return
1096 // draw table header
1097 drawstring(pos, _("Map stats:"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1098 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
1101 vector tmp = '0 0 0';
1103 tmp_y = hud_fontsize_y * rows;
1106 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1108 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1109 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1112 if(stat_monsters_total)
1114 val = sprintf("%d/%d", stat_monsters_killed, stat_monsters_total);
1115 pos = HUD_DrawKeyValue(pos, _("Monsters killed:"), val);
1119 if(stat_secrets_total)
1121 val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
1122 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 not(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;