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 f = stof(getplayerkeyvalue(pl.sv_entnum, "colors"));
548 hud_field_icon0 = "gfx/scoreboard/playercolor_base";
549 hud_field_icon1 = "gfx/scoreboard/playercolor_shirt";
550 hud_field_icon1_rgb = colormapPaletteColor(floor(f / 16), 0);
551 hud_field_icon2 = "gfx/scoreboard/playercolor_pants";
552 hud_field_icon2_rgb = colormapPaletteColor(mod(f, 16), 1);
555 return GetPlayerName(pl.sv_entnum);
558 f = pl.(scores[SP_KILLS]);
559 f -= pl.(scores[SP_SUICIDES]);
563 num = pl.(scores[SP_KILLS]);
564 denom = pl.(scores[SP_DEATHS]);
567 hud_field_rgb = '0 1 0';
568 str = sprintf("%d", num);
569 } else if(num <= 0) {
570 hud_field_rgb = '1 0 0';
571 str = sprintf("%.1f", num/denom);
573 str = sprintf("%.1f", num/denom);
577 f = pl.(scores[SP_KILLS]);
578 f -= pl.(scores[SP_DEATHS]);
581 hud_field_rgb = '0 1 0';
583 hud_field_rgb = '1 1 1';
585 hud_field_rgb = '1 0 0';
590 tmp = pl.(scores[field]);
591 f = scores_flags[field];
592 if(field == ps_primary)
593 hud_field_rgb = '1 1 0';
594 else if(field == ps_secondary)
595 hud_field_rgb = '0 1 1';
597 hud_field_rgb = '1 1 1';
598 return ScoreString(f, tmp);
603 float xmin, xmax, ymin, ymax, sbwidth;
604 float hud_fixscoreboardcolumnwidth_len;
605 float hud_fixscoreboardcolumnwidth_iconlen;
606 float hud_fixscoreboardcolumnwidth_marginlen;
608 string HUD_FixScoreboardColumnWidth(float i, string str)
612 field = hud_field[i];
614 hud_fixscoreboardcolumnwidth_iconlen = 0;
616 if(hud_field_icon0 != "")
618 sz = draw_getimagesize(hud_field_icon0);
620 if(hud_fixscoreboardcolumnwidth_iconlen < f)
621 hud_fixscoreboardcolumnwidth_iconlen = f;
624 if(hud_field_icon1 != "")
626 sz = draw_getimagesize(hud_field_icon1);
628 if(hud_fixscoreboardcolumnwidth_iconlen < f)
629 hud_fixscoreboardcolumnwidth_iconlen = f;
632 if(hud_field_icon2 != "")
634 sz = draw_getimagesize(hud_field_icon2);
636 if(hud_fixscoreboardcolumnwidth_iconlen < f)
637 hud_fixscoreboardcolumnwidth_iconlen = f;
640 hud_fixscoreboardcolumnwidth_iconlen *= hud_fontsize_y / hud_fontsize_x; // fix icon aspect
642 if(hud_fixscoreboardcolumnwidth_iconlen != 0)
643 hud_fixscoreboardcolumnwidth_marginlen = stringwidth(" ", FALSE, hud_fontsize);
645 hud_fixscoreboardcolumnwidth_marginlen = 0;
647 if(field == SP_NAME) // name gets all remaining space
650 namesize = sbwidth;// / hud_fontsize_x;
651 for(j = 0; j < hud_num_fields; ++j)
653 if (hud_field[i] != SP_SEPARATOR)
654 namesize -= hud_size[j] + hud_fontsize_x;
655 namesize += hud_fontsize_x;
656 hud_size[i] = namesize;
658 if (hud_fixscoreboardcolumnwidth_iconlen != 0)
659 namesize -= hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
660 str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
661 hud_fixscoreboardcolumnwidth_len = stringwidth(str, TRUE, hud_fontsize);
664 hud_fixscoreboardcolumnwidth_len = stringwidth(str, FALSE, hud_fontsize);
666 f = hud_fixscoreboardcolumnwidth_len + hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
673 void HUD_PrintScoreboardItem(vector pos, vector item_size, entity pl, float is_self, float pl_number)
676 rgb = Team_ColorRGB(pl.team);
680 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
682 if((rgb == '1 1 1') && (!is_spec)) {
683 rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
684 rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
685 rgb_z = autocvar_scoreboard_color_bg_b + 0.5; }
687 vector h_pos = pos - '1 1 0';
688 vector h_size = item_size + '2 0 0';
689 // alternated rows highlighting
691 drawfill(h_pos, h_size, rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
692 else if((scoreboard_highlight) && (!mod(pl_number,2)))
693 drawfill(h_pos, h_size, rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
699 for(i = 0; i < hud_num_fields; ++i)
701 field = hud_field[i];
702 if(field == SP_SEPARATOR)
705 if(is_spec && field != SP_NAME && field != SP_PING) {
706 pos_x += hud_size[i] + hud_fontsize_x;
709 str = HUD_GetField(pl, field);
710 str = HUD_FixScoreboardColumnWidth(i, str);
712 pos_x += hud_size[i] + hud_fontsize_x;
714 if(field == SP_NAME) {
715 tmp_x = hud_size[i] - hud_fontsize_x*hud_fixscoreboardcolumnwidth_iconlen - hud_fixscoreboardcolumnwidth_marginlen + hud_fontsize_x;
717 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
719 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
721 tmp_x = hud_fixscoreboardcolumnwidth_len + hud_fontsize_x;
723 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
725 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
728 tmp_x = hud_size[i] + hud_fontsize_x;
729 if(hud_field_icon0 != "")
731 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);
733 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);
734 if(hud_field_icon1 != "")
736 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);
738 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);
739 if(hud_field_icon2 != "")
741 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);
743 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);
746 if(hud_field[i] == SP_SEPARATOR)
749 for(i = hud_num_fields-1; i > 0; --i)
751 field = hud_field[i];
752 if(field == SP_SEPARATOR)
755 if(is_spec && field != SP_NAME && field != SP_PING) {
756 pos_x -= hud_size[i] + hud_fontsize_x;
760 str = HUD_GetField(pl, field);
761 str = HUD_FixScoreboardColumnWidth(i, str);
763 if(field == SP_NAME) {
764 tmp_x = hud_fixscoreboardcolumnwidth_len; // left or right aligned? let's put it right...
766 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
768 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
770 tmp_x = hud_fixscoreboardcolumnwidth_len;
772 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
774 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
778 if(hud_field_icon0 != "")
780 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);
782 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);
783 if(hud_field_icon1 != "")
785 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);
787 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);
788 if(hud_field_icon2 != "")
790 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);
792 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);
793 pos_x -= hud_size[i] + hud_fontsize_x;
798 drawfill(h_pos, h_size, '0 0 0', 0.5, DRAWFLAG_NORMAL);
802 * HUD_Scoreboard_MakeTable
804 * Makes a table for a team (for all playing players in DM) and fills it
807 vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
809 float body_table_height, i;
810 vector tmp = '0 0 0', column_dim = '0 0 0';
813 body_table_height = 1.25 * hud_fontsize_y * max(1, tm.team_size); // no player? show 1 empty line
815 pos_y += autocvar_scoreboard_border_thickness;
819 tmp_y = 1.25 * hud_fontsize_y;
823 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, (rgb * autocvar_scoreboard_color_bg_team) + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
825 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
828 tmp_y += autocvar_scoreboard_border_thickness;
829 tmp_y += body_table_height;
830 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // more transparency for the scoreboard
832 // separator header/table
833 pos_y += 1.25 * hud_fontsize_y;
834 tmp_y = autocvar_scoreboard_border_thickness;
835 drawfill(pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
837 pos_y += autocvar_scoreboard_border_thickness;
840 tmp_y = body_table_height;
842 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
844 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
846 // anyway, apply some color
847 //drawfill(pos, tmp + '2 0 0', rgb, 0.1, DRAWFLAG_NORMAL);
849 // go back to the top to make alternated columns highlighting and to print the strings
850 pos_y -= 1.25 * hud_fontsize_y;
851 pos_y -= autocvar_scoreboard_border_thickness;
855 if (scoreboard_highlight)
857 column_dim_y = 1.25 * hud_fontsize_y; // header
858 column_dim_y += autocvar_scoreboard_border_thickness;
859 column_dim_y += body_table_height;
862 // print the strings of the columns headers and draw the columns
863 draw_beginBoldFont();
864 for(i = 0; i < hud_num_fields; ++i)
866 if(hud_field[i] == SP_SEPARATOR)
868 column_dim_x = hud_size[i] + hud_fontsize_x;
869 if (scoreboard_highlight)
872 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
874 drawstring(pos, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
875 pos_x += column_dim_x;
877 if(hud_field[i] == SP_SEPARATOR)
881 for(i = hud_num_fields-1; i > 0; --i)
883 if(hud_field[i] == SP_SEPARATOR)
886 pos_x -= hud_size[i];
888 if (scoreboard_highlight)
892 if (i == hud_num_fields-1)
893 column_dim_x = hud_size[i] + hud_fontsize_x / 2 + 1;
895 column_dim_x = hud_size[i] + hud_fontsize_x;
896 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
900 tmp_x = stringwidth(hud_title[i], FALSE, hud_fontsize);
901 tmp_x = (hud_size[i] - tmp_x);
902 drawstring(pos + tmp, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
903 pos_x -= hud_fontsize_x;
909 pos_y += 1.25 * hud_fontsize_y; // skip the header
910 pos_y += autocvar_scoreboard_border_thickness;
914 tmp_y = hud_fontsize_y * 1.25;
916 // fill the table and draw the rows
919 for(pl = players.sort_next; pl; pl = pl.sort_next)
921 if(pl.team != tm.team)
923 HUD_PrintScoreboardItem(pos, tmp, pl, (pl.sv_entnum == player_localnum), i);
924 pos_y += 1.25 * hud_fontsize_y;
928 for(pl = players.sort_next; pl; pl = pl.sort_next)
930 if(pl.team == NUM_SPECTATOR)
932 HUD_PrintScoreboardItem(pos, tmp, pl, (pl.sv_entnum == player_localnum), i);
933 pos_y += 1.25 * hud_fontsize_y;
938 pos_y += 1.25 * hud_fontsize_y; // move to the end of the table
939 pos_y += 1.25 * hud_fontsize_y; // move empty row (out of the table)
944 float HUD_WouldDrawScoreboard() {
945 if (autocvar__hud_configure)
947 else if (scoreboard_showscores)
949 else if (intermission == 1)
951 else if (intermission == 2)
953 else if (spectatee_status != -1 && getstati(STAT_HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS)
955 else if (scoreboard_showscores_force)
960 float average_accuracy;
961 vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
964 float weapon_cnt = WEP_COUNT - 3; // either minstanex/nex are hidden, no port-o-launch, no tuba
966 if(autocvar_scoreboard_accuracy_doublerows)
971 float fontsize = height * 1/3;
972 float weapon_height = height * 2/3;
973 float weapon_width = sbwidth / weapon_cnt;
974 float g_minstagib = 0;
976 drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
977 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
978 vector tmp = '0 0 0';
980 tmp_y = height * rows;
983 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
985 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
986 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
988 // column highlighting
989 for(i = 0; i < weapon_cnt/rows; ++i)
992 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);
996 for(i = 0; i < rows; ++i)
998 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);
1001 average_accuracy = 0;
1002 float weapons_with_stats;
1003 weapons_with_stats = 0;
1005 pos_x += weapon_width / 2;
1007 if(switchweapon == WEP_MINSTANEX)
1008 g_minstagib = 1; // TODO: real detection for minstagib?
1011 if(autocvar_scoreboard_accuracy_nocolors)
1014 Accuracy_LoadColors();
1016 for(i = WEP_FIRST; i <= WEP_LAST; ++i)
1018 self = get_weaponinfo(i);
1021 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
1023 weapon_stats = weapon_accuracy[i-WEP_FIRST];
1026 if(weapon_stats >= 0)
1027 weapon_alpha = scoreboard_alpha_fg;
1029 weapon_alpha = 0.2 * scoreboard_alpha_fg;
1032 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);
1034 if(weapon_stats >= 0) {
1035 weapons_with_stats += 1;
1036 average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
1039 s = sprintf(_("%d%%"), weapon_stats*100);
1042 padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
1044 if(!autocvar_scoreboard_accuracy_nocolors)
1045 rgb = Accuracy_GetColor(weapon_stats);
1047 drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1049 pos_x += weapon_width * rows;
1050 if(rows == 2 && i == 6) {
1056 if(weapons_with_stats)
1057 average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
1060 pos_x -= weapon_width / 2;
1064 pos_y += 1.25 * hud_fontsize_y;
1068 vector HUD_DrawKeyValue(vector pos, string key, string value) {
1070 pos_x += hud_fontsize_x * 0.25;
1071 drawstring(pos, key, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1072 pos_x = xmax - stringwidth(value, FALSE, hud_fontsize) - hud_fontsize_x * 0.25;
1073 drawstring(pos, value, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1075 pos_y+= hud_fontsize_y;
1080 vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
1081 float stat_secrets_found, stat_secrets_total;
1082 float stat_monsters_killed, stat_monsters_total;
1086 // get monster stats
1087 stat_monsters_killed = getstatf(STAT_MONSTERS_KILLED);
1088 stat_monsters_total = getstatf(STAT_MONSTERS_TOTAL);
1090 // get secrets stats
1091 stat_secrets_found = getstatf(STAT_SECRETS_FOUND);
1092 stat_secrets_total = getstatf(STAT_SECRETS_TOTAL);
1094 // get number of rows
1095 if(stat_secrets_total)
1097 if(stat_monsters_total)
1100 // if no rows, return
1104 // draw table header
1105 drawstring(pos, _("Map stats:"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1106 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
1109 vector tmp = '0 0 0';
1111 tmp_y = hud_fontsize_y * rows;
1114 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1116 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1117 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1120 if(stat_monsters_total)
1122 val = sprintf("%d/%d", stat_monsters_killed, stat_monsters_total);
1123 pos = HUD_DrawKeyValue(pos, _("Monsters killed:"), val);
1127 if(stat_secrets_total)
1129 val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
1130 pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val);
1134 pos_y += 1.25 * hud_fontsize_y;
1139 vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_size)
1142 RANKINGS_RECEIVED_CNT = 0;
1143 for (i=RANKINGS_CNT-1; i>=0; --i)
1145 ++RANKINGS_RECEIVED_CNT;
1147 if (RANKINGS_RECEIVED_CNT == 0)
1151 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
1153 hl_rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
1154 hl_rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
1155 hl_rgb_z = autocvar_scoreboard_color_bg_b + 0.5;
1157 pos_y += hud_fontsize_y;
1158 drawstring(pos, _("Rankings"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1159 pos_y += hud_fontsize_y + autocvar_scoreboard_border_thickness;
1160 vector tmp = '0 0 0';
1162 tmp_y = 1.25 * hud_fontsize_y * RANKINGS_RECEIVED_CNT;
1165 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1167 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1168 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1171 for(i = 0; i<RANKINGS_RECEIVED_CNT; ++i)
1178 n = grecordholder[i];
1179 p = count_ordinal(i+1);
1180 if(grecordholder[i] == GetPlayerName(player_localnum))
1181 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
1182 else if(!mod(i, 2) && scoreboard_highlight)
1183 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
1184 drawstring(pos, p, '1 1 0' * hud_fontsize_y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1185 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);
1186 drawcolorcodedstring(pos + '8 0 0' * hud_fontsize_y, n, '1 1 0' * hud_fontsize_y, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1187 pos_y += 1.25 * hud_fontsize_y;
1189 pos_y += autocvar_scoreboard_border_thickness;
1194 float hud_woulddrawscoreboard_prev;
1195 float hud_woulddrawscoreboard_change; // "time" at which HUD_WouldDrawScoreboard() changed
1196 void HUD_DrawScoreboard()
1198 float hud_woulddrawscoreboard;
1199 hud_woulddrawscoreboard = scoreboard_active;
1200 if(hud_woulddrawscoreboard != hud_woulddrawscoreboard_prev) {
1201 hud_woulddrawscoreboard_change = time;
1202 hud_woulddrawscoreboard_prev = hud_woulddrawscoreboard;
1205 if(hud_woulddrawscoreboard) {
1206 float scoreboard_fadeinspeed = autocvar_scoreboard_fadeinspeed;
1207 if (scoreboard_fadeinspeed)
1208 scoreboard_fade_alpha = bound (0, (time - hud_woulddrawscoreboard_change) * scoreboard_fadeinspeed, 1);
1210 scoreboard_fade_alpha = 1;
1213 float scoreboard_fadeoutspeed = autocvar_scoreboard_fadeoutspeed;
1214 if (scoreboard_fadeoutspeed)
1215 scoreboard_fade_alpha = bound (0, (1/scoreboard_fadeoutspeed - (time - hud_woulddrawscoreboard_change)) * scoreboard_fadeoutspeed, 1);
1217 scoreboard_fade_alpha = 0;
1220 if (!scoreboard_fade_alpha)
1223 HUD_UpdatePlayerTeams();
1225 scoreboard_alpha_bg = autocvar_scoreboard_alpha_bg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1226 scoreboard_alpha_fg = autocvar_scoreboard_alpha_fg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1227 scoreboard_highlight = autocvar_scoreboard_highlight;
1228 scoreboard_highlight_alpha = autocvar_scoreboard_highlight_alpha * scoreboard_alpha_fg;
1229 scoreboard_highlight_alpha_self = autocvar_scoreboard_highlight_alpha_self * scoreboard_alpha_fg;
1230 scoreboard_alpha_name = autocvar_scoreboard_alpha_name * scoreboard_alpha_fg;
1231 scoreboard_alpha_name_self = autocvar_scoreboard_alpha_name_self * scoreboard_alpha_fg;
1233 vector rgb, pos, tmp;
1237 xmin = (autocvar_scoreboard_offset_left * vid_conwidth);
1238 ymin = max((autocvar_con_notify * autocvar_con_notifysize), (autocvar_scoreboard_offset_vertical * vid_conwidth));
1240 xmax = ((1 - autocvar_scoreboard_offset_right) * vid_conwidth);
1241 ymax = (vid_conheight - ymin);
1243 sbwidth = xmax - xmin;
1245 // Initializes position
1251 vector sb_heading_fontsize;
1252 sb_heading_fontsize = hud_fontsize * 2;
1253 draw_beginBoldFont();
1254 drawstring(pos, _("Scoreboard"), sb_heading_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1257 pos_y += sb_heading_fontsize_y + hud_fontsize_y * 0.25;
1259 // Draw the scoreboard
1260 vector bg_size = draw_getimagesize("gfx/scoreboard/scoreboard_bg") * autocvar_scoreboard_bg_scale;
1264 vector team_score_baseoffset;
1265 team_score_baseoffset = eY * (2 * autocvar_scoreboard_border_thickness + hud_fontsize_y) - eX * (autocvar_scoreboard_border_thickness + hud_fontsize_x * 0.25);
1266 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1268 if(tm.team == NUM_SPECTATOR)
1271 draw_beginBoldFont();
1272 rgb = Team_ColorRGB(tm.team);
1273 str = ftos(tm.(teamscores[ts_primary]));
1274 drawstring(pos + team_score_baseoffset - eX * stringwidth(str, FALSE, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1276 if(ts_primary != ts_secondary)
1278 str = ftos(tm.(teamscores[ts_secondary]));
1279 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);
1283 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1289 rgb_x = autocvar_scoreboard_color_bg_r;
1290 rgb_y = autocvar_scoreboard_color_bg_g;
1291 rgb_z = autocvar_scoreboard_color_bg_b;
1298 rgb_x = autocvar_scoreboard_color_bg_r;
1299 rgb_y = autocvar_scoreboard_color_bg_g;
1300 rgb_z = autocvar_scoreboard_color_bg_b;
1302 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1304 if(tm.team == NUM_SPECTATOR)
1307 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1311 if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE) {
1312 if(race_speedaward) {
1313 drawcolorcodedstring(pos, sprintf(_("Speed award: %d ^7(%s^7)"), race_speedaward, race_speedaward_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1314 pos_y += 1.25 * hud_fontsize_y;
1316 if(race_speedaward_alltimebest) {
1317 drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1318 pos_y += 1.25 * hud_fontsize_y;
1320 pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
1322 else if(autocvar_scoreboard_accuracy && spectatee_status == 0 && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL) {
1324 pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size);
1326 pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size);
1331 pos = HUD_DrawMapStats(pos, Team_ColorRGB(myteam), bg_size);
1333 pos = HUD_DrawMapStats(pos, rgb, bg_size);
1340 item_size_x = sbwidth;
1341 item_size_y = hud_fontsize_y * 1.25;
1343 for(pl = players.sort_next; pl; pl = pl.sort_next)
1345 if(pl.team != NUM_SPECTATOR)
1347 pos_y += 1.25 * hud_fontsize_y;
1348 HUD_PrintScoreboardItem(pos, item_size, pl, (pl.sv_entnum == player_localnum), specs);
1354 draw_beginBoldFont();
1355 drawstring(tmp, _("Spectators"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1357 pos_y += 1.25 * hud_fontsize_y;
1360 // Print info string
1362 str = sprintf(_("playing ^3%s^7 on ^2%s^7"), MapInfo_Type_ToText(gametype), shortmapname);
1363 tl = getstatf(STAT_TIMELIMIT);
1364 fl = getstatf(STAT_FRAGLIMIT);
1365 ll = getstatf(STAT_LEADLIMIT);
1366 if(gametype == MAPINFO_TYPE_LMS)
1369 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1374 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1378 str = strcat(str, _(" or"));
1381 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], fl),
1382 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1383 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1384 TranslateScoresLabel(teamscores_label[ts_primary])));
1388 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(scores_flags[ps_primary], fl),
1389 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1390 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1391 TranslateScoresLabel(scores_label[ps_primary])));
1396 if(tl > 0 || fl > 0)
1397 str = strcat(str, _(" or"));
1400 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], ll),
1401 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1402 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1403 TranslateScoresLabel(teamscores_label[ts_primary])));
1407 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(scores_flags[ps_primary], ll),
1408 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1409 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1410 TranslateScoresLabel(scores_label[ps_primary])));
1415 pos_y += 1.2 * hud_fontsize_y;
1416 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1418 // print information about respawn status
1419 float respawn_time = getstatf(STAT_RESPAWN_TIME);
1423 if(respawn_time < 0)
1425 // a negative number means we are awaiting respawn, time value is still the same
1426 respawn_time *= -1; // remove mark now that we checked it
1427 respawn_time = max(time, respawn_time); // don't show a negative value while the server is respawning the player (lag)
1429 str = sprintf(_("^1Respawning in ^3%s^1..."),
1430 (autocvar_scoreboard_respawntime_decimals ?
1431 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1433 count_seconds(respawn_time - time)
1437 else if(time < respawn_time)
1439 str = sprintf(_("You are dead, wait ^3%s^7 before respawning"),
1440 (autocvar_scoreboard_respawntime_decimals ?
1441 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1443 count_seconds(respawn_time - time)
1447 else if(time >= respawn_time)
1448 str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
1450 pos_y += 1.2 * hud_fontsize_y;
1451 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1454 scoreboard_bottom = pos_y + 2 * hud_fontsize_y;