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"));
57 void Cmd_HUD_SetFields(float argc);
62 ps_primary = ps_secondary = ts_primary = ts_secondary = -1;
63 for(i = 0; i < MAX_SCORE; ++i)
65 f = (scores_flags[i] & SFL_SORT_PRIO_MASK);
66 if(f == SFL_SORT_PRIO_PRIMARY)
68 if(f == SFL_SORT_PRIO_SECONDARY)
71 if(ps_secondary == -1)
72 ps_secondary = ps_primary;
74 for(i = 0; i < MAX_TEAMSCORE; ++i)
76 f = (teamscores_flags[i] & SFL_SORT_PRIO_MASK);
77 if(f == SFL_SORT_PRIO_PRIMARY)
79 if(f == SFL_SORT_PRIO_SECONDARY)
82 if(ts_secondary == -1)
83 ts_secondary = ts_primary;
88 void HUD_UpdatePlayerPos(entity pl);
89 float SetTeam(entity pl, float Team);
91 void HUD_UpdatePlayerTeams()
98 for(pl = players.sort_next; pl; pl = pl.sort_next)
101 Team = GetPlayerColor(pl.sv_entnum);
102 if(SetTeam(pl, Team))
105 HUD_UpdatePlayerPos(pl);
109 pl = players.sort_next;
114 print(strcat("PNUM: ", ftos(num), "\n"));
119 float HUD_CompareScore(float vl, float vr, float f)
121 if(f & SFL_ZERO_IS_WORST)
123 if(vl == 0 && vr != 0)
125 if(vl != 0 && vr == 0)
129 return IS_INCREASING(f);
131 return IS_DECREASING(f);
135 float HUD_ComparePlayerScores(entity left, entity right)
138 vl = GetPlayerColor(left.sv_entnum);
139 vr = GetPlayerColor(right.sv_entnum);
151 if(vl == NUM_SPECTATOR)
153 // FIRST the one with scores (spectators), THEN the ones without (downloaders)
155 if(!left.gotscores && right.gotscores)
160 r = HUD_CompareScore(left.scores[ps_primary], right.scores[ps_primary], scores_flags[ps_primary]);
164 r = HUD_CompareScore(left.scores[ps_secondary], right.scores[ps_secondary], scores_flags[ps_secondary]);
168 for(i = 0; i < MAX_SCORE; ++i)
170 r = HUD_CompareScore(left.scores[i], right.scores[i], scores_flags[i]);
175 if (left.sv_entnum < right.sv_entnum)
181 void HUD_UpdatePlayerPos(entity player)
183 for(other = player.sort_next; other && HUD_ComparePlayerScores(player, other); other = player.sort_next)
185 SORT_SWAP(player, other);
187 for(other = player.sort_prev; other != players && HUD_ComparePlayerScores(other, player); other = player.sort_prev)
189 SORT_SWAP(other, player);
193 float HUD_CompareTeamScores(entity left, entity right)
197 if(left.team == NUM_SPECTATOR)
199 if(right.team == NUM_SPECTATOR)
202 r = HUD_CompareScore(left.teamscores[ts_primary], right.teamscores[ts_primary], teamscores_flags[ts_primary]);
206 r = HUD_CompareScore(left.teamscores[ts_secondary], right.teamscores[ts_secondary], teamscores_flags[ts_secondary]);
210 for(i = 0; i < MAX_SCORE; ++i)
212 r = HUD_CompareScore(left.teamscores[i], right.teamscores[i], teamscores_flags[i]);
217 if (left.team < right.team)
223 void HUD_UpdateTeamPos(entity Team)
225 for(other = Team.sort_next; other && HUD_CompareTeamScores(Team, other); other = Team.sort_next)
227 SORT_SWAP(Team, other);
229 for(other = Team.sort_prev; other != teams && HUD_CompareTeamScores(other, Team); other = Team.sort_prev)
231 SORT_SWAP(other, Team);
237 print(_("You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"));
238 print(_("^3|---------------------------------------------------------------|\n"));
239 print(_("Usage:\n"));
240 print(_("^2scoreboard_columns_set default\n"));
241 print(_("^2scoreboard_columns_set ^7field1 field2 ...\n"));
242 print(_("The following field names are recognized (case insensitive):\n"));
243 print(_("You can use a ^3|^7 to start the right-aligned fields.\n\n"));
245 print(_("^3name^7 or ^3nick^7 Name of a player\n"));
246 print(_("^3ping^7 Ping time\n"));
247 print(_("^3pl^7 Packet loss\n"));
248 print(_("^3kills^7 Number of kills\n"));
249 print(_("^3deaths^7 Number of deaths\n"));
250 print(_("^3suicides^7 Number of suicides\n"));
251 print(_("^3frags^7 kills - suicides\n"));
252 print(_("^3kd^7 The kill-death ratio\n"));
253 print(_("^3sum^7 frags - deaths\n"));
254 print(_("^3caps^7 How often a flag (CTF) or a key (KeyHunt) was captured\n"));
255 print(_("^3pickups^7 How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\n"));
256 print(_("^3captime^7 Time of fastest cap (CTF)\n"));
257 print(_("^3fckills^7 Number of flag carrier kills\n"));
258 print(_("^3returns^7 Number of flag returns\n"));
259 print(_("^3drops^7 Number of flag drops\n"));
260 print(_("^3lives^7 Number of lives (LMS)\n"));
261 print(_("^3rank^7 Player rank\n"));
262 print(_("^3pushes^7 Number of players pushed into void\n"));
263 print(_("^3destroyed^7 Number of keys destroyed by pushing them into void\n"));
264 print(_("^3kckills^7 Number of keys carrier kills\n"));
265 print(_("^3losses^7 Number of times a key was lost\n"));
266 print(_("^3laps^7 Number of laps finished (race/cts)\n"));
267 print(_("^3time^7 Total time raced (race/cts)\n"));
268 print(_("^3fastest^7 Time of fastest lap (race/cts)\n"));
269 print(_("^3ticks^7 Number of ticks (DOM)\n"));
270 print(_("^3takes^7 Number of domination points taken (DOM)\n"));
271 print(_("^3bckills^7 Number of ball carrier kills\n"));
272 print(_("^3bctime^7 Total amount of time holding the ball in Keepaway\n"));
273 print(_("^3score^7 Total score\n\n"));
275 print(_("Before a field you can put a + or - sign, then a comma separated list\n"
276 "of game types, then a slash, to make the field show up only in these\n"
277 "or in all but these game types. You can also specify 'all' as a\n"
278 "field to show all fields available for the current game mode.\n\n"));
280 print(_("The special game type names 'teams' and 'noteams' can be used to\n"
281 "include/exclude ALL teams/noteams game modes.\n\n"));
283 print(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"));
284 print(_("will display name, ping and pl aligned to the left, and the fields\n"
285 "right of the vertical bar aligned to the right.\n"));
286 print(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
287 "other gamemodes except DM.\n"));
290 string HUD_DefaultColumnLayout()
292 return strcat( // fteqcc sucks
294 "-teams,race,lms/kills +freezetag/kills -teams,lms/deaths +freezetag/deaths -teams,lms,race,ka/suicides +freezetag/suicides -race,dm,tdm,ka,freezetag/frags ", // tdm already has this in "score"
295 "+tdm/kills +tdm/deaths +tdm/suicides ",
296 "+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns ",
297 "+lms/lives +lms/rank ",
298 "+kh/caps +kh/pushes +kh/destroyed ",
299 "?+race/laps ?+race/time ?+race/fastest ",
300 "+as/objectives +nexball/faults +nexball/goals +ka/pickups +ka/bckills +ka/bctime +freezetag/revivals ",
301 "-lms,race,nexball/score");
304 void Cmd_HUD_SetFields(float argc)
308 float have_name = 0, have_primary = 0, have_secondary = 0, have_separator = 0;
311 // TODO: re enable with gametype dependant cvars?
312 if(argc < 3) // no arguments provided
313 argc = tokenizebyseparator(strcat("0 1 ", autocvar_scoreboard_columns), " ");
316 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
320 if(argv(2) == "default")
321 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
322 else if(argv(2) == "all")
325 s = "ping pl name |";
326 for(i = 0; i < MAX_SCORE; ++i)
329 if(i != ps_secondary)
330 if(scores_label[i] != "")
331 s = strcat(s, " ", scores_label[i]);
333 if(ps_secondary != ps_primary)
334 s = strcat(s, " ", scores_label[ps_secondary]);
335 s = strcat(s, " ", scores_label[ps_primary]);
336 argc = tokenizebyseparator(strcat("0 1 ", s), " ");
343 hud_fontsize = HUD_GetFontsize("hud_fontsize");
345 draw_beginBoldFont();
346 for(i = 1; i < argc - 1; ++i)
352 if(substring(str, 0, 1) == "?")
355 str = substring(str, 1, strlen(str) - 1);
358 slash = strstrofs(str, "/", 0);
361 pattern = substring(str, 0, slash);
362 str = substring(str, slash + 1, strlen(str) - (slash + 1));
364 if (!isGametypeInFilter(gametype, teamplay, FALSE, pattern))
368 strunzone(hud_title[hud_num_fields]);
369 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(str));
370 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
371 str = strtolower(str);
374 hud_field[hud_num_fields] = SP_PING;
375 } else if(str == "pl") {
376 hud_field[hud_num_fields] = SP_PL;
377 } else if(str == "kd" || str == "kdr" || str == "kdratio" || str == "k/d") {
378 hud_field[hud_num_fields] = SP_KDRATIO;
379 } else if(str == "sum" || str == "diff" || str == "k-d") {
380 hud_field[hud_num_fields] = SP_SUM;
381 } else if(str == "name" || str == "nick") {
382 hud_field[hud_num_fields] = SP_NAME;
384 } else if(str == "|") {
385 hud_field[hud_num_fields] = SP_SEPARATOR;
388 for(j = 0; j < MAX_SCORE; ++j)
389 if(str == strtolower(scores_label[j]))
390 goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
399 printf("^1Error:^7 Unknown score field: '%s'\n", str);
403 hud_field[hud_num_fields] = j;
406 if(j == ps_secondary)
410 if(hud_num_fields >= MAX_HUD_FIELDS)
414 if(scores_flags[ps_primary] & SFL_ALLOW_HIDE)
416 if(scores_flags[ps_secondary] & SFL_ALLOW_HIDE)
418 if(ps_primary == ps_secondary)
420 missing = (!have_primary) + (!have_secondary) + (!have_separator) + (!have_name);
422 if(hud_num_fields+missing < MAX_HUD_FIELDS)
426 strunzone(hud_title[hud_num_fields]);
427 for(i = hud_num_fields; i > 0; --i)
429 hud_title[i] = hud_title[i-1];
430 hud_size[i] = hud_size[i-1];
431 hud_field[i] = hud_field[i-1];
433 hud_title[0] = strzone(TranslateScoresLabel("name"));
434 hud_field[0] = SP_NAME;
436 print("fixed missing field 'name'\n");
440 strunzone(hud_title[hud_num_fields]);
441 for(i = hud_num_fields; i > 1; --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[1] = strzone("|");
448 hud_field[1] = SP_SEPARATOR;
449 hud_size[1] = stringwidth("|", FALSE, hud_fontsize);
451 print("fixed missing field '|'\n");
454 else if(!have_separator)
456 strunzone(hud_title[hud_num_fields]);
457 hud_title[hud_num_fields] = strzone("|");
458 hud_size[hud_num_fields] = stringwidth("|", FALSE, hud_fontsize);
459 hud_field[hud_num_fields] = SP_SEPARATOR;
461 print("fixed missing field '|'\n");
465 strunzone(hud_title[hud_num_fields]);
466 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_secondary]));
467 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
468 hud_field[hud_num_fields] = ps_secondary;
470 printf("fixed missing field '%s'\n", scores_label[ps_secondary]);
474 strunzone(hud_title[hud_num_fields]);
475 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_primary]));
476 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
477 hud_field[hud_num_fields] = ps_primary;
479 printf("fixed missing field '%s'\n", scores_label[ps_primary]);
483 hud_field[hud_num_fields] = SP_END;
488 vector hud_field_rgb;
489 string hud_field_icon0;
490 string hud_field_icon1;
491 string hud_field_icon2;
492 vector hud_field_icon0_rgb;
493 vector hud_field_icon1_rgb;
494 vector hud_field_icon2_rgb;
495 float hud_field_icon0_alpha;
496 float hud_field_icon1_alpha;
497 float hud_field_icon2_alpha;
498 string HUD_GetField(entity pl, float field)
500 float tmp, num, denom, f;
502 hud_field_rgb = '1 1 1';
503 hud_field_icon0 = "";
504 hud_field_icon1 = "";
505 hud_field_icon2 = "";
506 hud_field_icon0_rgb = '1 1 1';
507 hud_field_icon1_rgb = '1 1 1';
508 hud_field_icon2_rgb = '1 1 1';
509 hud_field_icon0_alpha = 1;
510 hud_field_icon1_alpha = 1;
511 hud_field_icon2_alpha = 1;
516 return "\xEE\x82\x8D\xEE\x82\x8D\xEE\x82\x8D"; // >>> sign
517 //str = getplayerkeyvalue(pl.sv_entnum, "ping");
521 tmp = max(0, min(220, f-80)) / 220;
522 hud_field_rgb = '1 1 1' - '0 1 1'*tmp;
528 f = pl.ping_packetloss;
529 tmp = pl.ping_movementloss;
530 if(f == 0 && tmp == 0)
532 str = ftos(ceil(f * 100));
534 str = strcat(str, "~", ftos(ceil(tmp * 100)));
535 tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
536 hud_field_rgb = '1 0.5 0.5' - '0 0.5 0.5'*tmp;
540 if(ready_waiting && pl.ready)
542 hud_field_icon0 = "gfx/scoreboard/player_ready";
546 hud_field_icon0 = "gfx/scoreboard/player_ready"; // TODO: different icon
550 f = stof(getplayerkeyvalue(pl.sv_entnum, "colors"));
552 hud_field_icon0 = "gfx/scoreboard/playercolor_base";
553 hud_field_icon1 = "gfx/scoreboard/playercolor_shirt";
554 hud_field_icon1_rgb = colormapPaletteColor(floor(f / 16), 0);
555 hud_field_icon2 = "gfx/scoreboard/playercolor_pants";
556 hud_field_icon2_rgb = colormapPaletteColor(mod(f, 16), 1);
559 return GetPlayerName(pl.sv_entnum);
562 f = pl.(scores[SP_KILLS]);
563 f -= pl.(scores[SP_SUICIDES]);
567 num = pl.(scores[SP_KILLS]);
568 denom = pl.(scores[SP_DEATHS]);
571 hud_field_rgb = '0 1 0';
572 str = sprintf("%d", num);
573 } else if(num <= 0) {
574 hud_field_rgb = '1 0 0';
575 str = sprintf("%.1f", num/denom);
577 str = sprintf("%.1f", num/denom);
581 f = pl.(scores[SP_KILLS]);
582 f -= pl.(scores[SP_DEATHS]);
585 hud_field_rgb = '0 1 0';
587 hud_field_rgb = '1 1 1';
589 hud_field_rgb = '1 0 0';
594 tmp = pl.(scores[field]);
595 f = scores_flags[field];
596 if(field == ps_primary)
597 hud_field_rgb = '1 1 0';
598 else if(field == ps_secondary)
599 hud_field_rgb = '0 1 1';
601 hud_field_rgb = '1 1 1';
602 return ScoreString(f, tmp);
607 float xmin, xmax, ymin, ymax, sbwidth;
608 float hud_fixscoreboardcolumnwidth_len;
609 float hud_fixscoreboardcolumnwidth_iconlen;
610 float hud_fixscoreboardcolumnwidth_marginlen;
612 string HUD_FixScoreboardColumnWidth(float i, string str)
616 field = hud_field[i];
618 hud_fixscoreboardcolumnwidth_iconlen = 0;
620 if(hud_field_icon0 != "")
622 sz = draw_getimagesize(hud_field_icon0);
624 if(hud_fixscoreboardcolumnwidth_iconlen < f)
625 hud_fixscoreboardcolumnwidth_iconlen = f;
628 if(hud_field_icon1 != "")
630 sz = draw_getimagesize(hud_field_icon1);
632 if(hud_fixscoreboardcolumnwidth_iconlen < f)
633 hud_fixscoreboardcolumnwidth_iconlen = f;
636 if(hud_field_icon2 != "")
638 sz = draw_getimagesize(hud_field_icon2);
640 if(hud_fixscoreboardcolumnwidth_iconlen < f)
641 hud_fixscoreboardcolumnwidth_iconlen = f;
644 hud_fixscoreboardcolumnwidth_iconlen *= hud_fontsize_y / hud_fontsize_x; // fix icon aspect
646 if(hud_fixscoreboardcolumnwidth_iconlen != 0)
647 hud_fixscoreboardcolumnwidth_marginlen = stringwidth(" ", FALSE, hud_fontsize);
649 hud_fixscoreboardcolumnwidth_marginlen = 0;
651 if(field == SP_NAME) // name gets all remaining space
654 namesize = sbwidth;// / hud_fontsize_x;
655 for(j = 0; j < hud_num_fields; ++j)
657 if (hud_field[i] != SP_SEPARATOR)
658 namesize -= hud_size[j] + hud_fontsize_x;
659 namesize += hud_fontsize_x;
660 hud_size[i] = namesize;
662 if (hud_fixscoreboardcolumnwidth_iconlen != 0)
663 namesize -= hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
664 str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
665 hud_fixscoreboardcolumnwidth_len = stringwidth(str, TRUE, hud_fontsize);
668 hud_fixscoreboardcolumnwidth_len = stringwidth(str, FALSE, hud_fontsize);
670 f = hud_fixscoreboardcolumnwidth_len + hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
677 void HUD_PrintScoreboardItem(vector pos, entity pl, float is_self, float pl_number)
680 rgb = Team_ColorRGB(pl.team);
684 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
686 if((rgb == '1 1 1') && (!is_spec)) {
687 rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
688 rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
689 rgb_z = autocvar_scoreboard_color_bg_b + 0.5; }
693 tmp_y = hud_fontsize_y * 1.25;
696 // alternated rows highlighting
698 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
699 else if((scoreboard_highlight) && (!mod(pl_number,2)))
700 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
704 for(i = 0; i < hud_num_fields; ++i)
706 field = hud_field[i];
707 if(field == SP_SEPARATOR)
710 if(is_spec && field != SP_NAME && field != SP_PING) {
711 pos_x += hud_size[i] + hud_fontsize_x;
714 str = HUD_GetField(pl, field);
715 str = HUD_FixScoreboardColumnWidth(i, str);
717 pos_x += hud_size[i] + hud_fontsize_x;
719 if(field == SP_NAME) {
720 tmp_x = hud_size[i] - hud_fontsize_x*hud_fixscoreboardcolumnwidth_iconlen - hud_fixscoreboardcolumnwidth_marginlen + hud_fontsize_x;
722 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
724 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
726 tmp_x = hud_fixscoreboardcolumnwidth_len + hud_fontsize_x;
728 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
730 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
733 tmp_x = hud_size[i] + hud_fontsize_x;
734 if(hud_field_icon0 != "")
736 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);
738 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);
739 if(hud_field_icon1 != "")
741 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);
743 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);
744 if(hud_field_icon2 != "")
746 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);
748 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);
751 if(hud_field[i] == SP_SEPARATOR)
754 for(i = hud_num_fields-1; i > 0; --i)
756 field = hud_field[i];
757 if(field == SP_SEPARATOR)
760 if(is_spec && field != SP_NAME && field != SP_PING) {
761 pos_x -= hud_size[i] + hud_fontsize_x;
765 str = HUD_GetField(pl, field);
766 str = HUD_FixScoreboardColumnWidth(i, str);
768 if(field == SP_NAME) {
769 tmp_x = hud_fixscoreboardcolumnwidth_len; // left or right aligned? let's put it right...
771 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
773 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
775 tmp_x = hud_fixscoreboardcolumnwidth_len;
777 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
779 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
783 if(hud_field_icon0 != "")
785 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);
787 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);
788 if(hud_field_icon1 != "")
790 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);
792 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);
793 if(hud_field_icon2 != "")
795 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);
797 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);
798 pos_x -= hud_size[i] + hud_fontsize_x;
804 * HUD_Scoreboard_MakeTable
806 * Makes a table for a team (for all playing players in DM) and fills it
809 vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
811 float body_table_height, i;
812 vector tmp = '0 0 0', column_dim = '0 0 0';
815 body_table_height = 1.25 * hud_fontsize_y * max(1, tm.team_size); // no player? show 1 empty line
817 pos_y += autocvar_scoreboard_border_thickness;
821 tmp_y = 1.25 * hud_fontsize_y;
825 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, (rgb * autocvar_scoreboard_color_bg_team) + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
827 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
830 tmp_y += autocvar_scoreboard_border_thickness;
831 tmp_y += body_table_height;
832 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // more transparency for the scoreboard
834 // separator header/table
835 pos_y += 1.25 * hud_fontsize_y;
836 tmp_y = autocvar_scoreboard_border_thickness;
837 drawfill(pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
839 pos_y += autocvar_scoreboard_border_thickness;
842 tmp_y = body_table_height;
844 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
846 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
848 // anyway, apply some color
849 //drawfill(pos, tmp + '2 0 0', rgb, 0.1, DRAWFLAG_NORMAL);
851 // go back to the top to make alternated columns highlighting and to print the strings
852 pos_y -= 1.25 * hud_fontsize_y;
853 pos_y -= autocvar_scoreboard_border_thickness;
857 if (scoreboard_highlight)
859 column_dim_y = 1.25 * hud_fontsize_y; // header
860 column_dim_y += autocvar_scoreboard_border_thickness;
861 column_dim_y += body_table_height;
864 // print the strings of the columns headers and draw the columns
865 draw_beginBoldFont();
866 for(i = 0; i < hud_num_fields; ++i)
868 if(hud_field[i] == SP_SEPARATOR)
870 column_dim_x = hud_size[i] + hud_fontsize_x;
871 if (scoreboard_highlight)
874 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
876 drawstring(pos, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
877 pos_x += column_dim_x;
879 if(hud_field[i] == SP_SEPARATOR)
883 for(i = hud_num_fields-1; i > 0; --i)
885 if(hud_field[i] == SP_SEPARATOR)
888 pos_x -= hud_size[i];
890 if (scoreboard_highlight)
894 if (i == hud_num_fields-1)
895 column_dim_x = hud_size[i] + hud_fontsize_x / 2 + 1;
897 column_dim_x = hud_size[i] + hud_fontsize_x;
898 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
902 tmp_x = stringwidth(hud_title[i], FALSE, hud_fontsize);
903 tmp_x = (hud_size[i] - tmp_x);
904 drawstring(pos + tmp, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
905 pos_x -= hud_fontsize_x;
911 pos_y += 1.25 * hud_fontsize_y; // skip the header
912 pos_y += autocvar_scoreboard_border_thickness;
914 // fill the table and draw the rows
917 for(pl = players.sort_next; pl; pl = pl.sort_next)
919 if(pl.team != tm.team)
921 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
922 pos_y += 1.25 * hud_fontsize_y;
926 for(pl = players.sort_next; pl; pl = pl.sort_next)
928 if(pl.team == NUM_SPECTATOR)
930 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
931 pos_y += 1.25 * hud_fontsize_y;
936 pos_y += 1.25 * hud_fontsize_y; // move to the end of the table
937 pos_y += 1.25 * hud_fontsize_y; // move empty row (out of the table)
942 float HUD_WouldDrawScoreboard() {
943 if (autocvar__hud_configure)
945 else if (scoreboard_showscores)
947 else if (intermission == 1)
949 else if (intermission == 2)
951 else if (spectatee_status != -1 && getstati(STAT_HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS)
953 else if (scoreboard_showscores_force)
958 float average_accuracy;
959 vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
962 float weapon_cnt = WEP_COUNT - 3; // either minstanex/nex are hidden, no port-o-launch, no tuba
964 if(autocvar_scoreboard_accuracy_doublerows)
969 float fontsize = height * 1/3;
970 float weapon_height = height * 2/3;
971 float weapon_width = sbwidth / weapon_cnt;
972 float g_minstagib = 0;
974 drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
975 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
976 vector tmp = '0 0 0';
978 tmp_y = height * rows;
981 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
983 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
984 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
986 // column highlighting
987 for(i = 0; i < weapon_cnt/rows; ++i)
990 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);
994 for(i = 0; i < rows; ++i)
996 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);
999 average_accuracy = 0;
1000 float weapons_with_stats;
1001 weapons_with_stats = 0;
1003 pos_x += weapon_width / 2;
1005 if(switchweapon == WEP_MINSTANEX)
1006 g_minstagib = 1; // TODO: real detection for minstagib?
1009 if(autocvar_scoreboard_accuracy_nocolors)
1012 Accuracy_LoadColors();
1014 for(i = WEP_FIRST; i <= WEP_LAST; ++i)
1016 self = get_weaponinfo(i);
1019 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
1021 weapon_stats = weapon_accuracy[i-WEP_FIRST];
1024 if(weapon_stats >= 0)
1025 weapon_alpha = scoreboard_alpha_fg;
1027 weapon_alpha = 0.2 * scoreboard_alpha_fg;
1030 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);
1032 if(weapon_stats >= 0) {
1033 weapons_with_stats += 1;
1034 average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
1037 s = sprintf(_("%d%%"), weapon_stats*100);
1040 padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
1042 if(!autocvar_scoreboard_accuracy_nocolors)
1043 rgb = Accuracy_GetColor(weapon_stats);
1045 drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1047 pos_x += weapon_width * rows;
1048 if(rows == 2 && i == 6) {
1054 if(weapons_with_stats)
1055 average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
1058 pos_x -= weapon_width / 2;
1062 pos_y += 1.25 * hud_fontsize_y;
1066 vector HUD_DrawKeyValue(vector pos, string key, string value) {
1068 pos_x += hud_fontsize_x * 0.25;
1069 drawstring(pos, key, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1070 pos_x = xmax - stringwidth(value, FALSE, hud_fontsize) - hud_fontsize_x * 0.25;
1071 drawstring(pos, value, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1073 pos_y+= hud_fontsize_y;
1078 vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
1079 float stat_secrets_found, stat_secrets_total;
1080 float stat_monsters_killed, stat_monsters_total;
1084 // get monster stats
1085 stat_monsters_killed = getstatf(STAT_MONSTERS_KILLED);
1086 stat_monsters_total = getstatf(STAT_MONSTERS_TOTAL);
1088 // get secrets stats
1089 stat_secrets_found = getstatf(STAT_SECRETS_FOUND);
1090 stat_secrets_total = getstatf(STAT_SECRETS_TOTAL);
1092 // get number of rows
1093 if(stat_secrets_total)
1095 if(stat_monsters_total)
1098 // if no rows, return
1102 // draw table header
1103 drawstring(pos, _("Map stats:"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1104 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
1107 vector tmp = '0 0 0';
1109 tmp_y = hud_fontsize_y * rows;
1112 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1114 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1115 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1118 if(stat_monsters_total)
1120 val = sprintf("%d/%d", stat_monsters_killed, stat_monsters_total);
1121 pos = HUD_DrawKeyValue(pos, _("Monsters killed:"), val);
1125 if(stat_secrets_total)
1127 val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
1128 pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val);
1132 pos_y += 1.25 * hud_fontsize_y;
1137 vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_size)
1140 RANKINGS_RECEIVED_CNT = 0;
1141 for (i=RANKINGS_CNT-1; i>=0; --i)
1143 ++RANKINGS_RECEIVED_CNT;
1145 if (RANKINGS_RECEIVED_CNT == 0)
1149 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
1151 hl_rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
1152 hl_rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
1153 hl_rgb_z = autocvar_scoreboard_color_bg_b + 0.5;
1155 pos_y += hud_fontsize_y;
1156 drawstring(pos, _("Rankings"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1157 pos_y += hud_fontsize_y + autocvar_scoreboard_border_thickness;
1158 vector tmp = '0 0 0';
1160 tmp_y = 1.25 * hud_fontsize_y * RANKINGS_RECEIVED_CNT;
1163 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1165 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1166 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1169 for(i = 0; i<RANKINGS_RECEIVED_CNT; ++i)
1176 n = grecordholder[i];
1177 p = count_ordinal(i+1);
1178 if(grecordholder[i] == GetPlayerName(player_localnum))
1179 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
1180 else if(!mod(i, 2) && scoreboard_highlight)
1181 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
1182 drawstring(pos, p, '1 1 0' * hud_fontsize_y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1183 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);
1184 drawcolorcodedstring(pos + '8 0 0' * hud_fontsize_y, n, '1 1 0' * hud_fontsize_y, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1185 pos_y += 1.25 * hud_fontsize_y;
1187 pos_y += autocvar_scoreboard_border_thickness;
1192 float hud_woulddrawscoreboard_prev;
1193 float hud_woulddrawscoreboard_change; // "time" at which HUD_WouldDrawScoreboard() changed
1194 void HUD_DrawScoreboard()
1196 float hud_woulddrawscoreboard;
1197 hud_woulddrawscoreboard = scoreboard_active;
1198 if(hud_woulddrawscoreboard != hud_woulddrawscoreboard_prev) {
1199 hud_woulddrawscoreboard_change = time;
1200 hud_woulddrawscoreboard_prev = hud_woulddrawscoreboard;
1203 if(hud_woulddrawscoreboard) {
1204 float scoreboard_fadeinspeed = autocvar_scoreboard_fadeinspeed;
1205 if (scoreboard_fadeinspeed)
1206 scoreboard_fade_alpha = bound (0, (time - hud_woulddrawscoreboard_change) * scoreboard_fadeinspeed, 1);
1208 scoreboard_fade_alpha = 1;
1211 float scoreboard_fadeoutspeed = autocvar_scoreboard_fadeoutspeed;
1212 if (scoreboard_fadeoutspeed)
1213 scoreboard_fade_alpha = bound (0, (1/scoreboard_fadeoutspeed - (time - hud_woulddrawscoreboard_change)) * scoreboard_fadeoutspeed, 1);
1215 scoreboard_fade_alpha = 0;
1218 if (!scoreboard_fade_alpha)
1221 HUD_UpdatePlayerTeams();
1223 scoreboard_alpha_bg = autocvar_scoreboard_alpha_bg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1224 scoreboard_alpha_fg = autocvar_scoreboard_alpha_fg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1225 scoreboard_highlight = autocvar_scoreboard_highlight;
1226 scoreboard_highlight_alpha = autocvar_scoreboard_highlight_alpha * scoreboard_alpha_fg;
1227 scoreboard_highlight_alpha_self = autocvar_scoreboard_highlight_alpha_self * scoreboard_alpha_fg;
1228 scoreboard_alpha_name = autocvar_scoreboard_alpha_name * scoreboard_alpha_fg;
1229 scoreboard_alpha_name_self = autocvar_scoreboard_alpha_name_self * scoreboard_alpha_fg;
1231 vector rgb, pos, tmp;
1235 xmin = (autocvar_scoreboard_offset_left * vid_conwidth);
1236 ymin = max((autocvar_con_notify * autocvar_con_notifysize), (autocvar_scoreboard_offset_vertical * vid_conwidth));
1238 xmax = ((1 - autocvar_scoreboard_offset_right) * vid_conwidth);
1239 ymax = (vid_conheight - ymin);
1241 sbwidth = xmax - xmin;
1243 // Initializes position
1249 vector sb_heading_fontsize;
1250 sb_heading_fontsize = hud_fontsize * 2;
1251 draw_beginBoldFont();
1252 drawstring(pos, _("Scoreboard"), sb_heading_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1255 pos_y += sb_heading_fontsize_y + hud_fontsize_y * 0.25;
1257 // Draw the scoreboard
1258 vector bg_size = draw_getimagesize("gfx/scoreboard/scoreboard_bg") * autocvar_scoreboard_bg_scale;
1262 vector team_score_baseoffset;
1263 team_score_baseoffset = eY * (2 * autocvar_scoreboard_border_thickness + hud_fontsize_y) - eX * (autocvar_scoreboard_border_thickness + hud_fontsize_x * 0.25);
1264 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1266 if(tm.team == NUM_SPECTATOR)
1269 draw_beginBoldFont();
1270 rgb = Team_ColorRGB(tm.team);
1271 str = ftos(tm.(teamscores[ts_primary]));
1272 drawstring(pos + team_score_baseoffset - eX * stringwidth(str, FALSE, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1274 if(ts_primary != ts_secondary)
1276 str = ftos(tm.(teamscores[ts_secondary]));
1277 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);
1281 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1287 rgb_x = autocvar_scoreboard_color_bg_r;
1288 rgb_y = autocvar_scoreboard_color_bg_g;
1289 rgb_z = autocvar_scoreboard_color_bg_b;
1296 rgb_x = autocvar_scoreboard_color_bg_r;
1297 rgb_y = autocvar_scoreboard_color_bg_g;
1298 rgb_z = autocvar_scoreboard_color_bg_b;
1300 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1302 if(tm.team == NUM_SPECTATOR)
1305 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1309 if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE) {
1310 if(race_speedaward) {
1311 drawcolorcodedstring(pos, sprintf(_("Speed award: %d ^7(%s^7)"), race_speedaward, race_speedaward_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1312 pos_y += 1.25 * hud_fontsize_y;
1314 if(race_speedaward_alltimebest) {
1315 drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1316 pos_y += 1.25 * hud_fontsize_y;
1318 pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
1320 else if(autocvar_scoreboard_accuracy && spectatee_status == 0 && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL) {
1322 pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size);
1324 pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size);
1329 pos = HUD_DrawMapStats(pos, Team_ColorRGB(myteam), bg_size);
1331 pos = HUD_DrawMapStats(pos, rgb, bg_size);
1337 for(pl = players.sort_next; pl; pl = pl.sort_next)
1339 if(pl.team != NUM_SPECTATOR)
1341 pos_y += 1.25 * hud_fontsize_y;
1342 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), specs);
1348 draw_beginBoldFont();
1349 drawstring(tmp, _("Spectators"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1351 pos_y += 1.25 * hud_fontsize_y;
1354 // Print info string
1356 str = sprintf(_("playing ^3%s^7 on ^2%s^7"), MapInfo_Type_ToText(gametype), shortmapname);
1357 tl = getstatf(STAT_TIMELIMIT);
1358 fl = getstatf(STAT_FRAGLIMIT);
1359 ll = getstatf(STAT_LEADLIMIT);
1360 if(gametype == MAPINFO_TYPE_LMS)
1363 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1368 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1372 str = strcat(str, _(" or"));
1375 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], fl),
1376 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1377 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1378 TranslateScoresLabel(teamscores_label[ts_primary])));
1382 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(scores_flags[ps_primary], fl),
1383 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1384 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1385 TranslateScoresLabel(scores_label[ps_primary])));
1390 if(tl > 0 || fl > 0)
1391 str = strcat(str, _(" or"));
1394 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], ll),
1395 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1396 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1397 TranslateScoresLabel(teamscores_label[ts_primary])));
1401 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(scores_flags[ps_primary], ll),
1402 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1403 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1404 TranslateScoresLabel(scores_label[ps_primary])));
1409 pos_y += 1.2 * hud_fontsize_y;
1410 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1412 // print information about respawn status
1413 float respawn_time = getstatf(STAT_RESPAWN_TIME);
1417 if(respawn_time < 0)
1419 // a negative number means we are awaiting respawn, time value is still the same
1420 respawn_time *= -1; // remove mark now that we checked it
1421 respawn_time = max(time, respawn_time); // don't show a negative value while the server is respawning the player (lag)
1423 str = sprintf(_("^1Respawning in ^3%s^1..."),
1424 (autocvar_scoreboard_respawntime_decimals ?
1425 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1427 count_seconds(respawn_time - time)
1431 else if(time < respawn_time)
1433 str = sprintf(_("You are dead, wait ^3%s^7 before respawning"),
1434 (autocvar_scoreboard_respawntime_decimals ?
1435 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1437 count_seconds(respawn_time - time)
1441 else if(time >= respawn_time)
1442 str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
1444 pos_y += 1.2 * hud_fontsize_y;
1445 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1448 scoreboard_bottom = pos_y + 2 * hud_fontsize_y;