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 " \
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;
307 // TODO: re enable with gametype dependant cvars?
308 if(argc < 3) // no arguments provided
309 argc = tokenizebyseparator(strcat("0 1 ", autocvar_scoreboard_columns), " ");
312 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
316 if(argv(2) == "default")
317 argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
318 else if(argv(2) == "all")
321 s = "ping pl name |";
322 for(i = 0; i < MAX_SCORE; ++i)
325 if(i != ps_secondary)
326 if(scores_label[i] != "")
327 s = strcat(s, " ", scores_label[i]);
329 if(ps_secondary != ps_primary)
330 s = strcat(s, " ", scores_label[ps_secondary]);
331 s = strcat(s, " ", scores_label[ps_primary]);
332 argc = tokenizebyseparator(strcat("0 1 ", s), " ");
339 hud_fontsize = HUD_GetFontsize("hud_fontsize");
341 draw_beginBoldFont();
342 for(i = 1; i < argc - 1; ++i)
348 if(substring(str, 0, 1) == "?")
351 str = substring(str, 1, strlen(str) - 1);
354 slash = strstrofs(str, "/", 0);
357 pattern = substring(str, 0, slash);
358 str = substring(str, slash + 1, strlen(str) - (slash + 1));
360 if (!isGametypeInFilter(gametype, teamplay, FALSE, pattern))
364 strunzone(hud_title[hud_num_fields]);
365 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(str));
366 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
367 str = strtolower(str);
370 hud_field[hud_num_fields] = SP_PING;
371 } else if(str == "pl") {
372 hud_field[hud_num_fields] = SP_PL;
373 } else if(str == "kd" || str == "kdr" || str == "kdratio" || str == "k/d") {
374 hud_field[hud_num_fields] = SP_KDRATIO;
375 } else if(str == "sum" || str == "diff" || str == "k-d") {
376 hud_field[hud_num_fields] = SP_SUM;
377 } else if(str == "name" || str == "nick") {
378 hud_field[hud_num_fields] = SP_NAME;
380 } else if(str == "|") {
381 hud_field[hud_num_fields] = SP_SEPARATOR;
384 for(j = 0; j < MAX_SCORE; ++j)
385 if(str == strtolower(scores_label[j]))
386 goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
395 printf("^1Error:^7 Unknown score field: '%s'\n", str);
399 hud_field[hud_num_fields] = j;
402 if(j == ps_secondary)
406 if(hud_num_fields >= MAX_HUD_FIELDS)
410 if(scores_flags[ps_primary] & SFL_ALLOW_HIDE)
412 if(scores_flags[ps_secondary] & SFL_ALLOW_HIDE)
414 if(ps_primary == ps_secondary)
416 missing = (!have_primary) + (!have_secondary) + (!have_separator) + (!have_name);
418 if(hud_num_fields+missing < MAX_HUD_FIELDS)
422 strunzone(hud_title[hud_num_fields]);
423 for(i = hud_num_fields; i > 0; --i)
425 hud_title[i] = hud_title[i-1];
426 hud_size[i] = hud_size[i-1];
427 hud_field[i] = hud_field[i-1];
429 hud_title[0] = strzone(TranslateScoresLabel("name"));
430 hud_field[0] = SP_NAME;
432 print("fixed missing field 'name'\n");
436 strunzone(hud_title[hud_num_fields]);
437 for(i = hud_num_fields; i > 1; --i)
439 hud_title[i] = hud_title[i-1];
440 hud_size[i] = hud_size[i-1];
441 hud_field[i] = hud_field[i-1];
443 hud_title[1] = strzone("|");
444 hud_field[1] = SP_SEPARATOR;
445 hud_size[1] = stringwidth("|", FALSE, hud_fontsize);
447 print("fixed missing field '|'\n");
450 else if(!have_separator)
452 strunzone(hud_title[hud_num_fields]);
453 hud_title[hud_num_fields] = strzone("|");
454 hud_size[hud_num_fields] = stringwidth("|", FALSE, hud_fontsize);
455 hud_field[hud_num_fields] = SP_SEPARATOR;
457 print("fixed missing field '|'\n");
461 strunzone(hud_title[hud_num_fields]);
462 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_secondary]));
463 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
464 hud_field[hud_num_fields] = ps_secondary;
466 printf("fixed missing field '%s'\n", scores_label[ps_secondary]);
470 strunzone(hud_title[hud_num_fields]);
471 hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_primary]));
472 hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], FALSE, hud_fontsize);
473 hud_field[hud_num_fields] = ps_primary;
475 printf("fixed missing field '%s'\n", scores_label[ps_primary]);
479 hud_field[hud_num_fields] = SP_END;
484 vector hud_field_rgb;
485 string hud_field_icon0;
486 string hud_field_icon1;
487 string hud_field_icon2;
488 vector hud_field_icon0_rgb;
489 vector hud_field_icon1_rgb;
490 vector hud_field_icon2_rgb;
491 float hud_field_icon0_alpha;
492 float hud_field_icon1_alpha;
493 float hud_field_icon2_alpha;
494 string HUD_GetField(entity pl, float field)
496 float tmp, num, denom, f;
498 hud_field_rgb = '1 1 1';
499 hud_field_icon0 = "";
500 hud_field_icon1 = "";
501 hud_field_icon2 = "";
502 hud_field_icon0_rgb = '1 1 1';
503 hud_field_icon1_rgb = '1 1 1';
504 hud_field_icon2_rgb = '1 1 1';
505 hud_field_icon0_alpha = 1;
506 hud_field_icon1_alpha = 1;
507 hud_field_icon2_alpha = 1;
512 return "\xEE\x82\x8D\xEE\x82\x8D\xEE\x82\x8D"; // >>> sign
513 //str = getplayerkeyvalue(pl.sv_entnum, "ping");
517 tmp = max(0, min(220, f-80)) / 220;
518 hud_field_rgb = '1 1 1' - '0 1 1'*tmp;
524 f = pl.ping_packetloss;
525 tmp = pl.ping_movementloss;
526 if(f == 0 && tmp == 0)
528 str = ftos(ceil(f * 100));
530 str = strcat(str, "~", ftos(ceil(tmp * 100)));
531 tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
532 hud_field_rgb = '1 0.5 0.5' - '0 0.5 0.5'*tmp;
536 if(ready_waiting && pl.ready)
538 hud_field_icon0 = "gfx/scoreboard/player_ready";
542 f = stof(getplayerkeyvalue(pl.sv_entnum, "colors"));
544 hud_field_icon0 = "gfx/scoreboard/playercolor_base";
545 hud_field_icon1 = "gfx/scoreboard/playercolor_shirt";
546 hud_field_icon1_rgb = colormapPaletteColor(floor(f / 16), 0);
547 hud_field_icon2 = "gfx/scoreboard/playercolor_pants";
548 hud_field_icon2_rgb = colormapPaletteColor(mod(f, 16), 1);
551 return GetPlayerName(pl.sv_entnum);
554 f = pl.(scores[SP_KILLS]);
555 f -= pl.(scores[SP_SUICIDES]);
559 num = pl.(scores[SP_KILLS]);
560 denom = pl.(scores[SP_DEATHS]);
563 hud_field_rgb = '0 1 0';
564 str = sprintf("%d", num);
565 } else if(num <= 0) {
566 hud_field_rgb = '1 0 0';
567 str = sprintf("%.1f", num/denom);
569 str = sprintf("%.1f", num/denom);
573 f = pl.(scores[SP_KILLS]);
574 f -= pl.(scores[SP_DEATHS]);
577 hud_field_rgb = '0 1 0';
579 hud_field_rgb = '1 1 1';
581 hud_field_rgb = '1 0 0';
586 tmp = pl.(scores[field]);
587 f = scores_flags[field];
588 if(field == ps_primary)
589 hud_field_rgb = '1 1 0';
590 else if(field == ps_secondary)
591 hud_field_rgb = '0 1 1';
593 hud_field_rgb = '1 1 1';
594 return ScoreString(f, tmp);
599 float xmin, xmax, ymin, ymax, sbwidth;
600 float hud_fixscoreboardcolumnwidth_len;
601 float hud_fixscoreboardcolumnwidth_iconlen;
602 float hud_fixscoreboardcolumnwidth_marginlen;
604 string HUD_FixScoreboardColumnWidth(float i, string str)
608 field = hud_field[i];
610 hud_fixscoreboardcolumnwidth_iconlen = 0;
612 if(hud_field_icon0 != "")
614 sz = draw_getimagesize(hud_field_icon0);
616 if(hud_fixscoreboardcolumnwidth_iconlen < f)
617 hud_fixscoreboardcolumnwidth_iconlen = f;
620 if(hud_field_icon1 != "")
622 sz = draw_getimagesize(hud_field_icon1);
624 if(hud_fixscoreboardcolumnwidth_iconlen < f)
625 hud_fixscoreboardcolumnwidth_iconlen = f;
628 if(hud_field_icon2 != "")
630 sz = draw_getimagesize(hud_field_icon2);
632 if(hud_fixscoreboardcolumnwidth_iconlen < f)
633 hud_fixscoreboardcolumnwidth_iconlen = f;
636 hud_fixscoreboardcolumnwidth_iconlen *= hud_fontsize_y / hud_fontsize_x; // fix icon aspect
638 if(hud_fixscoreboardcolumnwidth_iconlen != 0)
639 hud_fixscoreboardcolumnwidth_marginlen = stringwidth(" ", FALSE, hud_fontsize);
641 hud_fixscoreboardcolumnwidth_marginlen = 0;
643 if(field == SP_NAME) // name gets all remaining space
646 namesize = sbwidth;// / hud_fontsize_x;
647 for(j = 0; j < hud_num_fields; ++j)
649 if (hud_field[i] != SP_SEPARATOR)
650 namesize -= hud_size[j] + hud_fontsize_x;
651 namesize += hud_fontsize_x;
652 hud_size[i] = namesize;
654 if (hud_fixscoreboardcolumnwidth_iconlen != 0)
655 namesize -= hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
656 str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
657 hud_fixscoreboardcolumnwidth_len = stringwidth(str, TRUE, hud_fontsize);
660 hud_fixscoreboardcolumnwidth_len = stringwidth(str, FALSE, hud_fontsize);
662 f = hud_fixscoreboardcolumnwidth_len + hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
669 void HUD_PrintScoreboardItem(vector pos, entity pl, float is_self, float pl_number)
672 rgb = Team_ColorRGB(pl.team);
676 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
678 if((rgb == '1 1 1') && (!is_spec)) {
679 rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
680 rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
681 rgb_z = autocvar_scoreboard_color_bg_b + 0.5; }
685 tmp_y = hud_fontsize_y * 1.25;
688 // alternated rows highlighting
690 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
691 else if((scoreboard_highlight) && (!mod(pl_number,2)))
692 drawfill(pos - '1 1 0', tmp + '2 0 0', rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
696 for(i = 0; i < hud_num_fields; ++i)
698 field = hud_field[i];
699 if(field == SP_SEPARATOR)
702 if(is_spec && field != SP_NAME && field != SP_PING) {
703 pos_x += hud_size[i] + hud_fontsize_x;
706 str = HUD_GetField(pl, field);
707 str = HUD_FixScoreboardColumnWidth(i, str);
709 pos_x += hud_size[i] + hud_fontsize_x;
711 if(field == SP_NAME) {
712 tmp_x = hud_size[i] - hud_fontsize_x*hud_fixscoreboardcolumnwidth_iconlen - hud_fixscoreboardcolumnwidth_marginlen + hud_fontsize_x;
714 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
716 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
718 tmp_x = hud_fixscoreboardcolumnwidth_len + hud_fontsize_x;
720 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
722 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
725 tmp_x = hud_size[i] + hud_fontsize_x;
726 if(hud_field_icon0 != "")
728 drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
730 drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
731 if(hud_field_icon1 != "")
733 drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
735 drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
736 if(hud_field_icon2 != "")
738 drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
740 drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
743 if(hud_field[i] == SP_SEPARATOR)
746 for(i = hud_num_fields-1; i > 0; --i)
748 field = hud_field[i];
749 if(field == SP_SEPARATOR)
752 if(is_spec && field != SP_NAME && field != SP_PING) {
753 pos_x -= hud_size[i] + hud_fontsize_x;
757 str = HUD_GetField(pl, field);
758 str = HUD_FixScoreboardColumnWidth(i, str);
760 if(field == SP_NAME) {
761 tmp_x = hud_fixscoreboardcolumnwidth_len; // left or right aligned? let's put it right...
763 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
765 drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
767 tmp_x = hud_fixscoreboardcolumnwidth_len;
769 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
771 drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
775 if(hud_field_icon0 != "")
777 drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
779 drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
780 if(hud_field_icon1 != "")
782 drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
784 drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
785 if(hud_field_icon2 != "")
787 drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
789 drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize_y + '1 0 0' * hud_fontsize_x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
790 pos_x -= hud_size[i] + hud_fontsize_x;
796 * HUD_Scoreboard_MakeTable
798 * Makes a table for a team (for all playing players in DM) and fills it
801 vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
803 float body_table_height, i;
804 vector tmp = '0 0 0', column_dim = '0 0 0';
807 body_table_height = 1.25 * hud_fontsize_y * max(1, tm.team_size); // no player? show 1 empty line
809 pos_y += autocvar_scoreboard_border_thickness;
813 tmp_y = 1.25 * hud_fontsize_y;
817 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, (rgb * autocvar_scoreboard_color_bg_team) + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
819 drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
822 tmp_y += autocvar_scoreboard_border_thickness;
823 tmp_y += body_table_height;
824 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // more transparency for the scoreboard
826 // separator header/table
827 pos_y += 1.25 * hud_fontsize_y;
828 tmp_y = autocvar_scoreboard_border_thickness;
829 drawfill(pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
831 pos_y += autocvar_scoreboard_border_thickness;
834 tmp_y = body_table_height;
836 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
838 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
840 // anyway, apply some color
841 //drawfill(pos, tmp + '2 0 0', rgb, 0.1, DRAWFLAG_NORMAL);
843 // go back to the top to make alternated columns highlighting and to print the strings
844 pos_y -= 1.25 * hud_fontsize_y;
845 pos_y -= autocvar_scoreboard_border_thickness;
849 if (scoreboard_highlight)
851 column_dim_y = 1.25 * hud_fontsize_y; // header
852 column_dim_y += autocvar_scoreboard_border_thickness;
853 column_dim_y += body_table_height;
856 // print the strings of the columns headers and draw the columns
857 draw_beginBoldFont();
858 for(i = 0; i < hud_num_fields; ++i)
860 if(hud_field[i] == SP_SEPARATOR)
862 column_dim_x = hud_size[i] + hud_fontsize_x;
863 if (scoreboard_highlight)
866 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
868 drawstring(pos, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
869 pos_x += column_dim_x;
871 if(hud_field[i] == SP_SEPARATOR)
875 for(i = hud_num_fields-1; i > 0; --i)
877 if(hud_field[i] == SP_SEPARATOR)
880 pos_x -= hud_size[i];
882 if (scoreboard_highlight)
886 if (i == hud_num_fields-1)
887 column_dim_x = hud_size[i] + hud_fontsize_x / 2 + 1;
889 column_dim_x = hud_size[i] + hud_fontsize_x;
890 drawfill(pos - '0 1 0' - hud_fontsize_x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
894 tmp_x = stringwidth(hud_title[i], FALSE, hud_fontsize);
895 tmp_x = (hud_size[i] - tmp_x);
896 drawstring(pos + tmp, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
897 pos_x -= hud_fontsize_x;
903 pos_y += 1.25 * hud_fontsize_y; // skip the header
904 pos_y += autocvar_scoreboard_border_thickness;
906 // fill the table and draw the rows
909 for(pl = players.sort_next; pl; pl = pl.sort_next)
911 if(pl.team != tm.team)
913 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
914 pos_y += 1.25 * hud_fontsize_y;
918 for(pl = players.sort_next; pl; pl = pl.sort_next)
920 if(pl.team == NUM_SPECTATOR)
922 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
923 pos_y += 1.25 * hud_fontsize_y;
928 pos_y += 1.25 * hud_fontsize_y; // move to the end of the table
929 pos_y += 1.25 * hud_fontsize_y; // move empty row (out of the table)
934 float HUD_WouldDrawScoreboard() {
935 if (autocvar__hud_configure)
937 else if (scoreboard_showscores)
939 else if (intermission == 1)
941 else if (intermission == 2)
943 else if (spectatee_status != -1 && getstati(STAT_HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS)
945 else if (scoreboard_showscores_force)
950 float average_accuracy;
951 vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
954 float weapon_cnt = WEP_COUNT - 3; // either minstanex/nex are hidden, no port-o-launch, no tuba
956 if(autocvar_scoreboard_accuracy_doublerows)
961 float fontsize = height * 1/3;
962 float weapon_height = height * 2/3;
963 float weapon_width = sbwidth / weapon_cnt;
964 float g_instagib = 0;
966 drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
967 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
968 vector tmp = '0 0 0';
970 tmp_y = height * rows;
973 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
975 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
976 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
978 // column highlighting
979 for(i = 0; i < weapon_cnt/rows; ++i)
982 drawfill(pos + '1 0 0' * weapon_width * rows * i, '0 1 0' * height * rows + '1 0 0' * weapon_width * rows, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
986 for(i = 0; i < rows; ++i)
988 drawfill(pos + '0 1 0' * weapon_height + '0 1 0' * height * i, '1 0 0' * sbwidth + '0 1 0' * fontsize, '1 1 1', scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
991 average_accuracy = 0;
992 float weapons_with_stats;
993 weapons_with_stats = 0;
995 pos_x += weapon_width / 2;
997 if(switchweapon == WEP_MINSTANEX)
998 g_instagib = 1; // TODO: real detection for instagib?
1001 if(autocvar_scoreboard_accuracy_nocolors)
1004 Accuracy_LoadColors();
1006 for(i = WEP_FIRST; i <= WEP_LAST; ++i)
1008 self = get_weaponinfo(i);
1011 if ((i == WEP_NEX && g_instagib) || i == WEP_PORTO || (i == WEP_MINSTANEX && !g_instagib) || i == WEP_TUBA) // skip port-o-launch, vortex || vaporizer and tuba
1013 weapon_stats = weapon_accuracy[i-WEP_FIRST];
1016 if(weapon_stats >= 0)
1017 weapon_alpha = scoreboard_alpha_fg;
1019 weapon_alpha = 0.2 * scoreboard_alpha_fg;
1022 drawpic_aspect_skin(pos, strcat("weapon", self.netname), '1 0 0' * weapon_width + '0 1 0' * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
1024 if(weapon_stats >= 0) {
1025 weapons_with_stats += 1;
1026 average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
1029 s = sprintf(_("%d%%"), weapon_stats*100);
1032 padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
1034 if(!autocvar_scoreboard_accuracy_nocolors)
1035 rgb = Accuracy_GetColor(weapon_stats);
1037 drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1039 pos_x += weapon_width * rows;
1040 if(rows == 2 && i == 6) {
1046 if(weapons_with_stats)
1047 average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
1050 pos_x -= weapon_width / 2;
1054 pos_y += 1.25 * hud_fontsize_y;
1058 vector HUD_DrawKeyValue(vector pos, string key, string value) {
1060 pos_x += hud_fontsize_x * 0.25;
1061 drawstring(pos, key, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1062 pos_x = xmax - stringwidth(value, FALSE, hud_fontsize) - hud_fontsize_x * 0.25;
1063 drawstring(pos, value, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1065 pos_y+= hud_fontsize_y;
1070 vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
1071 float stat_secrets_found, stat_secrets_total;
1072 float stat_monsters_killed, stat_monsters_total;
1076 // get monster stats
1077 stat_monsters_killed = getstatf(STAT_MONSTERS_KILLED);
1078 stat_monsters_total = getstatf(STAT_MONSTERS_TOTAL);
1080 // get secrets stats
1081 stat_secrets_found = getstatf(STAT_SECRETS_FOUND);
1082 stat_secrets_total = getstatf(STAT_SECRETS_TOTAL);
1084 // get number of rows
1085 if(stat_secrets_total)
1087 if(stat_monsters_total)
1090 // if no rows, return
1094 // draw table header
1095 drawstring(pos, _("Map stats:"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1096 pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
1099 vector tmp = '0 0 0';
1101 tmp_y = hud_fontsize_y * rows;
1104 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1106 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1107 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1110 if(stat_monsters_total)
1112 val = sprintf("%d/%d", stat_monsters_killed, stat_monsters_total);
1113 pos = HUD_DrawKeyValue(pos, _("Monsters killed:"), val);
1117 if(stat_secrets_total)
1119 val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
1120 pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val);
1124 pos_y += 1.25 * hud_fontsize_y;
1129 vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_size)
1132 RANKINGS_RECEIVED_CNT = 0;
1133 for (i=RANKINGS_CNT-1; i>=0; --i)
1135 ++RANKINGS_RECEIVED_CNT;
1137 if (RANKINGS_RECEIVED_CNT == 0)
1141 is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR);
1143 hl_rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
1144 hl_rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
1145 hl_rgb_z = autocvar_scoreboard_color_bg_b + 0.5;
1147 pos_y += hud_fontsize_y;
1148 drawstring(pos, _("Rankings"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1149 pos_y += hud_fontsize_y + autocvar_scoreboard_border_thickness;
1150 vector tmp = '0 0 0';
1152 tmp_y = 1.25 * hud_fontsize_y * RANKINGS_RECEIVED_CNT;
1155 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1157 drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
1158 drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
1161 for(i = 0; i<RANKINGS_RECEIVED_CNT; ++i)
1168 n = grecordholder[i];
1169 p = count_ordinal(i+1);
1170 if(grecordholder[i] == GetPlayerName(player_localnum))
1171 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
1172 else if(!mod(i, 2) && scoreboard_highlight)
1173 drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
1174 drawstring(pos, p, '1 1 0' * hud_fontsize_y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1175 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);
1176 drawcolorcodedstring(pos + '8 0 0' * hud_fontsize_y, n, '1 1 0' * hud_fontsize_y, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1177 pos_y += 1.25 * hud_fontsize_y;
1179 pos_y += autocvar_scoreboard_border_thickness;
1184 float hud_woulddrawscoreboard_prev;
1185 float hud_woulddrawscoreboard_change; // "time" at which HUD_WouldDrawScoreboard() changed
1186 void HUD_DrawScoreboard()
1188 float hud_woulddrawscoreboard;
1189 hud_woulddrawscoreboard = scoreboard_active;
1190 if(hud_woulddrawscoreboard != hud_woulddrawscoreboard_prev) {
1191 hud_woulddrawscoreboard_change = time;
1192 hud_woulddrawscoreboard_prev = hud_woulddrawscoreboard;
1195 if(hud_woulddrawscoreboard) {
1196 float scoreboard_fadeinspeed = autocvar_scoreboard_fadeinspeed;
1197 if (scoreboard_fadeinspeed)
1198 scoreboard_fade_alpha = bound (0, (time - hud_woulddrawscoreboard_change) * scoreboard_fadeinspeed, 1);
1200 scoreboard_fade_alpha = 1;
1203 float scoreboard_fadeoutspeed = autocvar_scoreboard_fadeoutspeed;
1204 if (scoreboard_fadeoutspeed)
1205 scoreboard_fade_alpha = bound (0, (1/scoreboard_fadeoutspeed - (time - hud_woulddrawscoreboard_change)) * scoreboard_fadeoutspeed, 1);
1207 scoreboard_fade_alpha = 0;
1210 if (!scoreboard_fade_alpha)
1213 HUD_UpdatePlayerTeams();
1215 scoreboard_alpha_bg = autocvar_scoreboard_alpha_bg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1216 scoreboard_alpha_fg = autocvar_scoreboard_alpha_fg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
1217 scoreboard_highlight = autocvar_scoreboard_highlight;
1218 scoreboard_highlight_alpha = autocvar_scoreboard_highlight_alpha * scoreboard_alpha_fg;
1219 scoreboard_highlight_alpha_self = autocvar_scoreboard_highlight_alpha_self * scoreboard_alpha_fg;
1220 scoreboard_alpha_name = autocvar_scoreboard_alpha_name * scoreboard_alpha_fg;
1221 scoreboard_alpha_name_self = autocvar_scoreboard_alpha_name_self * scoreboard_alpha_fg;
1223 vector rgb, pos, tmp;
1227 xmin = (autocvar_scoreboard_offset_left * vid_conwidth);
1228 ymin = max((autocvar_con_notify * autocvar_con_notifysize), (autocvar_scoreboard_offset_vertical * vid_conwidth));
1230 xmax = ((1 - autocvar_scoreboard_offset_right) * vid_conwidth);
1231 ymax = (vid_conheight - ymin);
1233 sbwidth = xmax - xmin;
1235 // Initializes position
1241 vector sb_heading_fontsize;
1242 sb_heading_fontsize = hud_fontsize * 2;
1243 draw_beginBoldFont();
1244 drawstring(pos, _("Scoreboard"), sb_heading_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1247 pos_y += sb_heading_fontsize_y + hud_fontsize_y * 0.25;
1249 // Draw the scoreboard
1250 vector bg_size = draw_getimagesize("gfx/scoreboard/scoreboard_bg") * autocvar_scoreboard_bg_scale;
1254 vector team_score_baseoffset;
1255 team_score_baseoffset = eY * (2 * autocvar_scoreboard_border_thickness + hud_fontsize_y) - eX * (autocvar_scoreboard_border_thickness + hud_fontsize_x * 0.25);
1256 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1258 if(tm.team == NUM_SPECTATOR)
1261 draw_beginBoldFont();
1262 rgb = Team_ColorRGB(tm.team);
1263 str = ftos(tm.(teamscores[ts_primary]));
1264 drawstring(pos + team_score_baseoffset - eX * stringwidth(str, FALSE, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1266 if(ts_primary != ts_secondary)
1268 str = ftos(tm.(teamscores[ts_secondary]));
1269 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);
1273 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1279 rgb_x = autocvar_scoreboard_color_bg_r;
1280 rgb_y = autocvar_scoreboard_color_bg_g;
1281 rgb_z = autocvar_scoreboard_color_bg_b;
1288 rgb_x = autocvar_scoreboard_color_bg_r;
1289 rgb_y = autocvar_scoreboard_color_bg_g;
1290 rgb_z = autocvar_scoreboard_color_bg_b;
1292 for(tm = teams.sort_next; tm; tm = tm.sort_next)
1294 if(tm.team == NUM_SPECTATOR)
1297 pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
1301 if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE) {
1302 if(race_speedaward) {
1303 drawcolorcodedstring(pos, sprintf(_("Speed award: %d ^7(%s^7)"), race_speedaward, race_speedaward_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1304 pos_y += 1.25 * hud_fontsize_y;
1306 if(race_speedaward_alltimebest) {
1307 drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1308 pos_y += 1.25 * hud_fontsize_y;
1310 pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
1312 else if(autocvar_scoreboard_accuracy && spectatee_status == 0 && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL) {
1314 pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size);
1316 pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size);
1321 pos = HUD_DrawMapStats(pos, Team_ColorRGB(myteam), bg_size);
1323 pos = HUD_DrawMapStats(pos, rgb, bg_size);
1329 for(pl = players.sort_next; pl; pl = pl.sort_next)
1331 if(pl.team != NUM_SPECTATOR)
1333 pos_y += 1.25 * hud_fontsize_y;
1334 HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), specs);
1340 draw_beginBoldFont();
1341 drawstring(tmp, _("Spectators"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1343 pos_y += 1.25 * hud_fontsize_y;
1346 // Print info string
1348 str = sprintf(_("playing ^3%s^7 on ^2%s^7"), MapInfo_Type_ToText(gametype), shortmapname);
1349 tl = getstatf(STAT_TIMELIMIT);
1350 fl = getstatf(STAT_FRAGLIMIT);
1351 ll = getstatf(STAT_LEADLIMIT);
1352 if(gametype == MAPINFO_TYPE_LMS)
1355 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1360 str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
1364 str = strcat(str, _(" or"));
1367 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], fl),
1368 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1369 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1370 TranslateScoresLabel(teamscores_label[ts_primary])));
1374 str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(scores_flags[ps_primary], fl),
1375 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1376 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1377 TranslateScoresLabel(scores_label[ps_primary])));
1382 if(tl > 0 || fl > 0)
1383 str = strcat(str, _(" or"));
1386 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], ll),
1387 (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
1388 (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1389 TranslateScoresLabel(teamscores_label[ts_primary])));
1393 str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(scores_flags[ps_primary], ll),
1394 (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
1395 (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
1396 TranslateScoresLabel(scores_label[ps_primary])));
1401 pos_y += 1.2 * hud_fontsize_y;
1402 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1404 // print information about respawn status
1405 float respawn_time = getstatf(STAT_RESPAWN_TIME);
1409 if(respawn_time < 0)
1411 // a negative number means we are awaiting respawn, time value is still the same
1412 respawn_time *= -1; // remove mark now that we checked it
1413 respawn_time = max(time, respawn_time); // don't show a negative value while the server is respawning the player (lag)
1415 str = sprintf(_("^1Respawning in ^3%s^1..."),
1416 (autocvar_scoreboard_respawntime_decimals ?
1417 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1419 count_seconds(respawn_time - time)
1423 else if(time < respawn_time)
1425 str = sprintf(_("You are dead, wait ^3%s^7 before respawning"),
1426 (autocvar_scoreboard_respawntime_decimals ?
1427 count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
1429 count_seconds(respawn_time - time)
1433 else if(time >= respawn_time)
1434 str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
1436 pos_y += 1.2 * hud_fontsize_y;
1437 drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
1440 scoreboard_bottom = pos_y + 2 * hud_fontsize_y;