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 #define HUD_DefaultColumnLayout() \
292 "-teams,race,lms/kills +ft,tdm/kills -teams,lms/deaths +ft,tdm/deaths -teams,lms,race,ka/suicides +ft,tdm/suicides -race,dm,tdm,ka,ft/frags " /* tdm already has this in "score" */ \
293 "+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns +ons/caps +ons/takes " \
294 "+lms/lives +lms/rank " \
295 "+kh/caps +kh/pushes +kh/destroyed " \
296 "?+race/laps ?+race/time ?+race/fastest " \
297 "+as/objectives +nb/faults +nb/goals +ka/pickups +ka/bckills +ka/bctime +ft/revivals " \
300 void Cmd_HUD_SetFields(float argc)
304 float have_name = 0, have_primary = 0, have_secondary = 0, have_separator = 0;
309 // set up a temporary scoreboard layout
310 // no layout can be properly set up until score_info data haven't been received
311 argc = tokenizebyseparator("0 1 ping pl name | score", " ");
313 scores_label[ps_primary] = strzone("score");
314 scores_flags[ps_primary] = SFL_ALLOW_HIDE;
317 // TODO: re enable with gametype dependant cvars?
318 if(argc < 3) // no arguments provided
319 argc = tokenizebyseparator(strcat("0 1 ", autocvar_scoreboard_columns), " ");
322 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
326 if(argv(2) == "default")
327 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
328 else if(argv(2) == "all")
331 s = "ping pl name |";
332 for(i = 0; i < MAX_SCORE; ++i)
335 if(i != ps_secondary)
336 if(scores_label[i] != "")
337 s = strcat(s, " ", scores_label[i]);
339 if(ps_secondary != ps_primary)
340 s = strcat(s, " ", scores_label[ps_secondary]);
341 s = strcat(s, " ", scores_label[ps_primary]);
342 argc = tokenizebyseparator(strcat("0 1 ", s), " ");
349 hud_fontsize = HUD_GetFontsize("hud_fontsize");
351 draw_beginBoldFont();
352 for(i = 1; i < argc - 1; ++i)
358 if(substring(str, 0, 1) == "?")
361 str = substring(str, 1, strlen(str) - 1);
364 slash = strstrofs(str, "/", 0);
367 pattern = substring(str, 0, slash);
368 str = substring(str, slash + 1, strlen(str) - (slash + 1));
370 if (!isGametypeInFilter(gametype, teamplay, FALSE, pattern))
374 strunzone(hud_title[hud_num_fields]);
375 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(str));
376 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
377 str = strtolower(str);
380 hud_field[hud_num_fields] = SP_PING;
381 } else if(str == "pl") {
382 hud_field[hud_num_fields] = SP_PL;
383 } else if(str == "kd" || str == "kdr" || str == "kdratio" || str == "k/d") {
384 hud_field[hud_num_fields] = SP_KDRATIO;
385 } else if(str == "sum" || str == "diff" || str == "k-d") {
386 hud_field[hud_num_fields] = SP_SUM;
387 } else if(str == "name" || str == "nick") {
388 hud_field[hud_num_fields] = SP_NAME;
390 } else if(str == "|") {
391 hud_field[hud_num_fields] = SP_SEPARATOR;
394 for(j = 0; j < MAX_SCORE; ++j)
395 if(str == strtolower(scores_label[j]))
396 goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
405 printf("^1Error:^7 Unknown score field: '%s'\n", str);
409 hud_field[hud_num_fields] = j;
412 if(j == ps_secondary)
416 if(hud_num_fields >= MAX_HUD_FIELDS)
420 if(scores_flags[ps_primary] & SFL_ALLOW_HIDE)
422 if(scores_flags[ps_secondary] & SFL_ALLOW_HIDE)
424 if(ps_primary == ps_secondary)
426 missing = (!have_primary) + (!have_secondary) + (!have_separator) + (!have_name);
428 if(hud_num_fields+missing < MAX_HUD_FIELDS)
432 strunzone(hud_title[hud_num_fields]);
433 for(i = hud_num_fields; i > 0; --i)
435 hud_title[i] = hud_title[i-1];
436 hud_size[i] = hud_size[i-1];
437 hud_field[i] = hud_field[i-1];
439 hud_title[0] = strzone(TranslateScoresLabel("name"));
440 hud_field[0] = SP_NAME;
442 print("fixed missing field 'name'\n");
446 strunzone(hud_title[hud_num_fields]);
447 for(i = hud_num_fields; i > 1; --i)
449 hud_title[i] = hud_title[i-1];
450 hud_size[i] = hud_size[i-1];
451 hud_field[i] = hud_field[i-1];
453 hud_title[1] = strzone("|");
454 hud_field[1] = SP_SEPARATOR;
455 hud_size[1] = stringwidth("|", FALSE, hud_fontsize);
457 print("fixed missing field '|'\n");
460 else if(!have_separator)
462 strunzone(hud_title[hud_num_fields]);
463 hud_title[hud_num_fields] = strzone("|");
464 hud_size[hud_num_fields] = stringwidth("|", FALSE, hud_fontsize);
465 hud_field[hud_num_fields] = SP_SEPARATOR;
467 print("fixed missing field '|'\n");
471 strunzone(hud_title[hud_num_fields]);
472 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_secondary]));
473 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
474 hud_field[hud_num_fields] = ps_secondary;
476 printf("fixed missing field '%s'\n", scores_label[ps_secondary]);
480 strunzone(hud_title[hud_num_fields]);
481 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_primary]));
482 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
483 hud_field[hud_num_fields] = ps_primary;
485 printf("fixed missing field '%s'\n", scores_label[ps_primary]);
489 hud_field[hud_num_fields] = SP_END;
494 vector hud_field_rgb;
495 string hud_field_icon0;
496 string hud_field_icon1;
497 string hud_field_icon2;
498 vector hud_field_icon0_rgb;
499 vector hud_field_icon1_rgb;
500 vector hud_field_icon2_rgb;
501 float hud_field_icon0_alpha;
502 float hud_field_icon1_alpha;
503 float hud_field_icon2_alpha;
504 string HUD_GetField(entity pl, float field)
506 float tmp, num, denom, f;
508 hud_field_rgb = '1 1 1';
509 hud_field_icon0 = "";
510 hud_field_icon1 = "";
511 hud_field_icon2 = "";
512 hud_field_icon0_rgb = '1 1 1';
513 hud_field_icon1_rgb = '1 1 1';
514 hud_field_icon2_rgb = '1 1 1';
515 hud_field_icon0_alpha = 1;
516 hud_field_icon1_alpha = 1;
517 hud_field_icon2_alpha = 1;
522 return "\xE2\x96\xB6\xE2\x96\xB6\xE2\x96\xB6"; // >>> sign using U+25B6
523 //str = getplayerkeyvalue(pl.sv_entnum, "ping");
527 tmp = max(0, min(220, f-80)) / 220;
528 hud_field_rgb = '1 1 1' - '0 1 1'*tmp;
534 f = pl.ping_packetloss;
535 tmp = pl.ping_movementloss;
536 if(f == 0 && tmp == 0)
538 str = ftos(ceil(f * 100));
540 str = strcat(str, "~", ftos(ceil(tmp * 100)));
541 tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
542 hud_field_rgb = '1 0.5 0.5' - '0 0.5 0.5'*tmp;
546 if(ready_waiting && pl.ready)
548 hud_field_icon0 = "gfx/scoreboard/player_ready";
552 f = stof(getplayerkeyvalue(pl.sv_entnum, "colors"));
554 hud_field_icon0 = "gfx/scoreboard/playercolor_base";
555 hud_field_icon1 = "gfx/scoreboard/playercolor_shirt";
556 hud_field_icon1_rgb = colormapPaletteColor(floor(f / 16), 0);
557 hud_field_icon2 = "gfx/scoreboard/playercolor_pants";
558 hud_field_icon2_rgb = colormapPaletteColor(f % 16, 1);
561 return GetPlayerName(pl.sv_entnum);
564 f = pl.(scores[SP_KILLS]);
565 f -= pl.(scores[SP_SUICIDES]);
569 num = pl.(scores[SP_KILLS]);
570 denom = pl.(scores[SP_DEATHS]);
573 hud_field_rgb = '0 1 0';
574 str = sprintf("%d", num);
575 } else if(num <= 0) {
576 hud_field_rgb = '1 0 0';
577 str = sprintf("%.1f", num/denom);
579 str = sprintf("%.1f", num/denom);
583 f = pl.(scores[SP_KILLS]);
584 f -= pl.(scores[SP_DEATHS]);
587 hud_field_rgb = '0 1 0';
589 hud_field_rgb = '1 1 1';
591 hud_field_rgb = '1 0 0';
596 tmp = pl.(scores[field]);
597 f = scores_flags[field];
598 if(field == ps_primary)
599 hud_field_rgb = '1 1 0';
600 else if(field == ps_secondary)
601 hud_field_rgb = '0 1 1';
603 hud_field_rgb = '1 1 1';
604 return ScoreString(f, tmp);
609 float xmin, xmax, ymin, ymax, sbwidth;
610 float hud_fixscoreboardcolumnwidth_len;
611 float hud_fixscoreboardcolumnwidth_iconlen;
612 float hud_fixscoreboardcolumnwidth_marginlen;
614 string HUD_FixScoreboardColumnWidth(float i, string str)
618 field = hud_field[i];
620 hud_fixscoreboardcolumnwidth_iconlen = 0;
622 if(hud_field_icon0 != "")
624 sz = draw_getimagesize(hud_field_icon0);
626 if(hud_fixscoreboardcolumnwidth_iconlen < f)
627 hud_fixscoreboardcolumnwidth_iconlen = f;
630 if(hud_field_icon1 != "")
632 sz = draw_getimagesize(hud_field_icon1);
634 if(hud_fixscoreboardcolumnwidth_iconlen < f)
635 hud_fixscoreboardcolumnwidth_iconlen = f;
638 if(hud_field_icon2 != "")
640 sz = draw_getimagesize(hud_field_icon2);
642 if(hud_fixscoreboardcolumnwidth_iconlen < f)
643 hud_fixscoreboardcolumnwidth_iconlen = f;
646 hud_fixscoreboardcolumnwidth_iconlen *= hud_fontsize_y / hud_fontsize_x; // fix icon aspect
648 if(hud_fixscoreboardcolumnwidth_iconlen != 0)
649 hud_fixscoreboardcolumnwidth_marginlen = stringwidth(" ", FALSE, hud_fontsize);
651 hud_fixscoreboardcolumnwidth_marginlen = 0;
653 if(field == SP_NAME) // name gets all remaining space
656 namesize = sbwidth;// / hud_fontsize_x;
657 for(j = 0; j < hud_num_fields; ++j)
659 if (hud_field[i] != SP_SEPARATOR)
660 namesize -= hud_size[j] + hud_fontsize_x;
661 namesize += hud_fontsize_x;
662 hud_size[i] = namesize;
664 if (hud_fixscoreboardcolumnwidth_iconlen != 0)
665 namesize -= hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
666 str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
667 hud_fixscoreboardcolumnwidth_len = stringwidth(str, TRUE, hud_fontsize);
670 hud_fixscoreboardcolumnwidth_len = stringwidth(str, FALSE, hud_fontsize);
672 f = hud_fixscoreboardcolumnwidth_len + hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
679 void HUD_PrintScoreboardItem(vector pos, vector item_size, entity pl, float is_self, float pl_number)
682 rgb = Team_ColorRGB(pl.team);
686 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
688 if((rgb == '1 1 1') && (!is_spec)) {
689 rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
690 rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
691 rgb_z = autocvar_scoreboard_color_bg_b + 0.5; }
693 vector h_pos = pos - '1 1 0';
694 vector h_size = item_size + '2 0 0';
695 // alternated rows highlighting
697 drawfill(h_pos, h_size, rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
698 else if((scoreboard_highlight) && (!(pl_number % 2)))
699 drawfill(h_pos, h_size, rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
705 for(i = 0; i < hud_num_fields; ++i)
707 field = hud_field[i];
708 if(field == SP_SEPARATOR)
711 if(is_spec && field != SP_NAME && field != SP_PING) {
712 pos_x += hud_size[i] + hud_fontsize_x;
715 str = HUD_GetField(pl, field);
716 str = HUD_FixScoreboardColumnWidth(i, str);
718 pos_x += hud_size[i] + hud_fontsize_x;
720 if(field == SP_NAME) {
721 tmp_x = hud_size[i] - hud_fontsize_x*hud_fixscoreboardcolumnwidth_iconlen - hud_fixscoreboardcolumnwidth_marginlen + hud_fontsize_x;
723 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
725 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
727 tmp_x = hud_fixscoreboardcolumnwidth_len + hud_fontsize_x;
729 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
731 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
734 tmp_x = hud_size[i] + hud_fontsize_x;
735 if(hud_field_icon0 != "")
737 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);
739 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);
740 if(hud_field_icon1 != "")
742 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);
744 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);
745 if(hud_field_icon2 != "")
747 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);
749 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);
752 if(hud_field[i] == SP_SEPARATOR)
755 for(i = hud_num_fields-1; i > 0; --i)
757 field = hud_field[i];
758 if(field == SP_SEPARATOR)
761 if(is_spec && field != SP_NAME && field != SP_PING) {
762 pos_x -= hud_size[i] + hud_fontsize_x;
766 str = HUD_GetField(pl, field);
767 str = HUD_FixScoreboardColumnWidth(i, str);
769 if(field == SP_NAME) {
770 tmp_x = hud_fixscoreboardcolumnwidth_len; // left or right aligned? let's put it right...
772 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
774 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
776 tmp_x = hud_fixscoreboardcolumnwidth_len;
778 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
780 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
784 if(hud_field_icon0 != "")
786 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);
788 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);
789 if(hud_field_icon1 != "")
791 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);
793 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);
794 if(hud_field_icon2 != "")
796 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);
798 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);
799 pos_x -= hud_size[i] + hud_fontsize_x;
804 drawfill(h_pos, h_size, '0 0 0', 0.5, DRAWFLAG_NORMAL);
808 * HUD_Scoreboard_MakeTable
810 * Makes a table for a team (for all playing players in DM) and fills it
813 vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
815 float body_table_height, i;
816 vector tmp = '0 0 0', column_dim = '0 0 0';
819 body_table_height = 1.25 * hud_fontsize_y * max(1, tm.team_size); // no player? show 1 empty line
821 pos_y += autocvar_scoreboard_border_thickness;
825 tmp_y = 1.25 * hud_fontsize_y;
829 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, (rgb * autocvar_scoreboard_color_bg_team) + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
831 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
834 tmp_y += autocvar_scoreboard_border_thickness;
835 tmp_y += body_table_height;
836 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // more transparency for the scoreboard
838 // separator header/table
839 pos_y += 1.25 * hud_fontsize_y;
840 tmp_y = autocvar_scoreboard_border_thickness;
841 drawfill(pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
843 pos_y += autocvar_scoreboard_border_thickness;
846 tmp_y = body_table_height;
848 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
850 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
852 // anyway, apply some color
853 //drawfill(pos, tmp + '2 0 0', rgb, 0.1, DRAWFLAG_NORMAL);
855 // go back to the top to make alternated columns highlighting and to print the strings
856 pos_y -= 1.25 * hud_fontsize_y;
857 pos_y -= autocvar_scoreboard_border_thickness;
861 if (scoreboard_highlight)
863 column_dim_y = 1.25 * hud_fontsize_y; // header
864 column_dim_y += autocvar_scoreboard_border_thickness;
865 column_dim_y += body_table_height;
868 // print the strings of the columns headers and draw the columns
869 draw_beginBoldFont();
870 for(i = 0; i < hud_num_fields; ++i)
872 if(hud_field[i] == SP_SEPARATOR)
874 column_dim_x = hud_size[i] + hud_fontsize_x;
875 if (scoreboard_highlight)
878 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
880 drawstring(pos, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
881 pos_x += column_dim_x;
883 if(hud_field[i] == SP_SEPARATOR)
887 for(i = hud_num_fields-1; i > 0; --i)
889 if(hud_field[i] == SP_SEPARATOR)
892 pos_x -= hud_size[i];
894 if (scoreboard_highlight)
898 if (i == hud_num_fields-1)
899 column_dim_x = hud_size[i] + hud_fontsize_x / 2 + 1;
901 column_dim_x = hud_size[i] + hud_fontsize_x;
902 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
906 tmp_x = stringwidth(hud_title[i], FALSE, hud_fontsize);
907 tmp_x = (hud_size[i] - tmp_x);
908 drawstring(pos + tmp, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
909 pos_x -= hud_fontsize_x;
915 pos_y += 1.25 * hud_fontsize_y; // skip the header
916 pos_y += autocvar_scoreboard_border_thickness;
920 tmp_y = hud_fontsize_y * 1.25;
922 // fill the table and draw the rows
925 for(pl = players.sort_next; pl; pl = pl.sort_next)
927 if(pl.team != tm.team)
929 HUD_PrintScoreboardItem(pos, tmp, pl, (pl.sv_entnum == player_localnum), i);
930 pos_y += 1.25 * hud_fontsize_y;
934 for(pl = players.sort_next; pl; pl = pl.sort_next)
936 if(pl.team == NUM_SPECTATOR)
938 HUD_PrintScoreboardItem(pos, tmp, pl, (pl.sv_entnum == player_localnum), i);
939 pos_y += 1.25 * hud_fontsize_y;
944 pos_y += 1.25 * hud_fontsize_y; // move to the end of the table
945 pos_y += 1.25 * hud_fontsize_y; // move empty row (out of the table)
950 float HUD_WouldDrawScoreboard() {
951 if (autocvar__hud_configure)
953 else if (HUD_Radar_Clickable())
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 vaporizer/vortex 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_instagib = 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_VAPORIZER)
1016 g_instagib = 1; // TODO: real detection for instagib?
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_VORTEX && g_instagib) || i == WEP_PORTO || (i == WEP_VAPORIZER && !g_instagib) || i == WEP_TUBA) // skip port-o-launch, vortex || vaporizer 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, self.model2, '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(!(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 == 0 && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL) {
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);
1348 item_size_x = sbwidth;
1349 item_size_y = hud_fontsize_y * 1.25;
1351 for(pl = players.sort_next; pl; pl = pl.sort_next)
1353 if(pl.team != NUM_SPECTATOR)
1355 pos_y += 1.25 * hud_fontsize_y;
1356 HUD_PrintScoreboardItem(pos, item_size, pl, (pl.sv_entnum == player_localnum), specs);
1362 draw_beginBoldFont();
1363 drawstring(tmp, _("Spectators"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1365 pos_y += 1.25 * hud_fontsize_y;
1368 // Print info string
1370 str = sprintf(_("playing ^3%s^7 on ^2%s^7"), MapInfo_Type_ToText(gametype), shortmapname);
1371 tl = getstatf(STAT_TIMELIMIT);
1372 fl = getstatf(STAT_FRAGLIMIT);
1373 ll = getstatf(STAT_LEADLIMIT);
1374 if(gametype == MAPINFO_TYPE_LMS)
1377 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1382 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1386 str = strcat(str, _(" or"));
1389 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], fl),
1390 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1391 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1392 TranslateScoresLabel(teamscores_label[ts_primary])));
1396 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(scores_flags[ps_primary], fl),
1397 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1398 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1399 TranslateScoresLabel(scores_label[ps_primary])));
1404 if(tl > 0 || fl > 0)
1405 str = strcat(str, _(" or"));
1408 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], ll),
1409 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1410 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1411 TranslateScoresLabel(teamscores_label[ts_primary])));
1415 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(scores_flags[ps_primary], ll),
1416 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1417 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1418 TranslateScoresLabel(scores_label[ps_primary])));
1423 pos_y += 1.2 * hud_fontsize_y;
1424 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1426 // print information about respawn status
1427 float respawn_time = getstatf(STAT_RESPAWN_TIME);
1431 if(respawn_time < 0)
1433 // a negative number means we are awaiting respawn, time value is still the same
1434 respawn_time *= -1; // remove mark now that we checked it
1435 respawn_time = max(time, respawn_time); // don't show a negative value while the server is respawning the player (lag)
1437 str = sprintf(_("^1Respawning in ^3%s^1..."),
1438 (autocvar_scoreboard_respawntime_decimals ?
1439 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1441 count_seconds(respawn_time - time)
1445 else if(time < respawn_time)
1447 str = sprintf(_("You are dead, wait ^3%s^7 before respawning"),
1448 (autocvar_scoreboard_respawntime_decimals ?
1449 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1451 count_seconds(respawn_time - time)
1455 else if(time >= respawn_time)
1456 str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
1458 pos_y += 1.2 * hud_fontsize_y;
1459 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1462 scoreboard_bottom = pos_y + 2 * hud_fontsize_y;