Xonotic
scoreboard.qc
Go to the documentation of this file.
1 #include "scoreboard.qh"
2 
3 #include <client/draw.qh>
9 #include <common/constants.qh>
10 #include <common/ent_cs.qh>
11 #include <common/mapinfo.qh>
13 #include <common/net_linked.qh>
14 #include <common/scores.qh>
15 #include <common/stats.qh>
16 #include <common/teams.qh>
18 
19 // Scoreboard (#24)
20 
22 {
23  // allow saving cvars that aesthetically change the panel into hud skin files
24  HUD_Write_Cvar("hud_panel_scoreboard_fadeinspeed");
25  HUD_Write_Cvar("hud_panel_scoreboard_fadeoutspeed");
26  HUD_Write_Cvar("hud_panel_scoreboard_respawntime_decimals");
27  HUD_Write_Cvar("hud_panel_scoreboard_table_bg_alpha");
28  HUD_Write_Cvar("hud_panel_scoreboard_table_bg_scale");
29  HUD_Write_Cvar("hud_panel_scoreboard_table_fg_alpha");
30  HUD_Write_Cvar("hud_panel_scoreboard_table_fg_alpha_self");
31  HUD_Write_Cvar("hud_panel_scoreboard_table_highlight");
32  HUD_Write_Cvar("hud_panel_scoreboard_table_highlight_alpha");
33  HUD_Write_Cvar("hud_panel_scoreboard_table_highlight_alpha_self");
34  HUD_Write_Cvar("hud_panel_scoreboard_table_highlight_alpha_eliminated");
35  HUD_Write_Cvar("hud_panel_scoreboard_bg_teams_color_team");
36  HUD_Write_Cvar("hud_panel_scoreboard_accuracy_doublerows");
37  HUD_Write_Cvar("hud_panel_scoreboard_accuracy_nocolors");
38  HUD_Write_Cvar("hud_panel_scoreboard_spectators_position");
39 }
40 
42 
47 
51 
59 
60 // provide basic panel cvars to old clients
61 // TODO remove them after a future release (0.8.2+)
62 noref string autocvar_hud_panel_scoreboard_pos = "0.150000 0.150000";
63 noref string autocvar_hud_panel_scoreboard_size = "0.700000 0.700000";
64 noref string autocvar_hud_panel_scoreboard_bg = "border_default";
65 noref string autocvar_hud_panel_scoreboard_bg_color = "0 0.3 0.5";
70 
86 
92 
97 float autocvar_hud_panel_scoreboard_itemstats_showdelay = 2.2; // slightly more delayed than accuracy
99 
101 
110 
111 // mode 0: returns translated label
112 // mode 1: prints name and description of all the labels
113 string Label_getInfo(string label, int mode)
114 {
115  if (mode == 1)
116  label = "bckills"; // first case in the switch
117 
118  switch(label)
119  {
120  case "bckills": if (!mode) return CTX(_("SCO^bckills")); else LOG_HELP(strcat("^3", "bckills", " ^7", _("Number of ball carrier kills")));
121  case "bctime": if (!mode) return CTX(_("SCO^bctime")); else LOG_HELP(strcat("^3", "bctime", " ^7", _("Total amount of time holding the ball in Keepaway")));
122  case "caps": if (!mode) return CTX(_("SCO^caps")); else LOG_HELP(strcat("^3", "caps", " ^7", _("How often a flag (CTF) or a key (KeyHunt) was captured")));
123  case "captime": if (!mode) return CTX(_("SCO^captime")); else LOG_HELP(strcat("^3", "captime", " ^7", _("Time of fastest capture (CTF)")));
124  case "deaths": if (!mode) return CTX(_("SCO^deaths")); else LOG_HELP(strcat("^3", "deaths", " ^7", _("Number of deaths")));
125  case "destroyed": if (!mode) return CTX(_("SCO^destroyed")); else LOG_HELP(strcat("^3", "destroyed", " ^7", _("Number of keys destroyed by pushing them into void")));
126  case "dmg": if (!mode) return CTX(_("SCO^damage")); else LOG_HELP(strcat("^3", "dmg", " ^7", _("The total damage done")));
127  case "dmgtaken": if (!mode) return CTX(_("SCO^dmgtaken")); else LOG_HELP(strcat("^3", "dmgtaken", " ^7", _("The total damage taken")));
128  case "drops": if (!mode) return CTX(_("SCO^drops")); else LOG_HELP(strcat("^3", "drops", " ^7", _("Number of flag drops")));
129  case "elo": if (!mode) return CTX(_("SCO^elo")); else LOG_HELP(strcat("^3", "elo", " ^7", _("Player ELO")));
130  case "fastest": if (!mode) return CTX(_("SCO^fastest")); else LOG_HELP(strcat("^3", "fastest", " ^7", _("Time of fastest lap (Race/CTS)")));
131  case "faults": if (!mode) return CTX(_("SCO^faults")); else LOG_HELP(strcat("^3", "faults", " ^7", _("Number of faults committed")));
132  case "fckills": if (!mode) return CTX(_("SCO^fckills")); else LOG_HELP(strcat("^3", "fckills", " ^7", _("Number of flag carrier kills")));
133  case "fps": if (!mode) return CTX(_("SCO^fps")); else LOG_HELP(strcat("^3", "fps", " ^7", _("FPS")));
134  case "frags": if (!mode) return CTX(_("SCO^frags")); else LOG_HELP(strcat("^3", "frags", " ^7", _("Number of kills minus suicides")));
135  case "goals": if (!mode) return CTX(_("SCO^goals")); else LOG_HELP(strcat("^3", "goals", " ^7", _("Number of goals scored")));
136  case "kckills": if (!mode) return CTX(_("SCO^kckills")); else LOG_HELP(strcat("^3", "kckills", " ^7", _("Number of keys carrier kills")));
137  case "kd": if (!mode) return CTX(_("SCO^k/d")); else LOG_HELP(strcat("^3", "kd", " ^7", _("The kill-death ratio")));
138  case "kdr": if (!mode) return CTX(_("SCO^kdr")); else LOG_HELP(strcat("^3", "kdr", " ^7", _("The kill-death ratio")));
139  case "kdratio": if (!mode) return CTX(_("SCO^kdratio")); else LOG_HELP(strcat("^3", "kdratio", " ^7", _("The kill-death ratio")));
140  case "kills": if (!mode) return CTX(_("SCO^kills")); else LOG_HELP(strcat("^3", "kills", " ^7", _("Number of kills")));
141  case "laps": if (!mode) return CTX(_("SCO^laps")); else LOG_HELP(strcat("^3", "laps", " ^7", _("Number of laps finished (Race/CTS)")));
142  case "lives": if (!mode) return CTX(_("SCO^lives")); else LOG_HELP(strcat("^3", "lives", " ^7", _("Number of lives (LMS)")));
143  case "losses": if (!mode) return CTX(_("SCO^losses")); else LOG_HELP(strcat("^3", "losses", " ^7", _("Number of times a key was lost")));
144  case "name": if (!mode) return CTX(_("SCO^name")); else LOG_HELP(strcat("^3", "name", " ^7", _("Player name")));
145  case "nick": if (!mode) return CTX(_("SCO^nick")); else LOG_HELP(strcat("^3", "nick", " ^7", _("Player name")));
146  case "objectives": if (!mode) return CTX(_("SCO^objectives")); else LOG_HELP(strcat("^3", "objectives", " ^7", _("Number of objectives destroyed")));
147  case "pickups": if (!mode) return CTX(_("SCO^pickups")); else LOG_HELP(strcat("^3", "pickups", " ^7", _("How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up")));
148  case "ping": if (!mode) return CTX(_("SCO^ping")); else LOG_HELP(strcat("^3", "ping", " ^7", _("Ping time")));
149  case "pl": if (!mode) return CTX(_("SCO^pl")); else LOG_HELP(strcat("^3", "pl", " ^7", _("Packet loss")));
150  case "pushes": if (!mode) return CTX(_("SCO^pushes")); else LOG_HELP(strcat("^3", "pushes", " ^7", _("Number of players pushed into void")));
151  case "rank": if (!mode) return CTX(_("SCO^rank")); else LOG_HELP(strcat("^3", "rank", " ^7", _("Player rank")));
152  case "returns": if (!mode) return CTX(_("SCO^returns")); else LOG_HELP(strcat("^3", "returns", " ^7", _("Number of flag returns")));
153  case "revivals": if (!mode) return CTX(_("SCO^revivals")); else LOG_HELP(strcat("^3", "revivals", " ^7", _("Number of revivals")));
154  case "rounds": if (!mode) return CTX(_("SCO^rounds won")); else LOG_HELP(strcat("^3", "rounds", " ^7", _("Number of rounds won")));
155  case "score": if (!mode) return CTX(_("SCO^score")); else LOG_HELP(strcat("^3", "score", " ^7", _("Total score")));
156  case "suicides": if (!mode) return CTX(_("SCO^suicides")); else LOG_HELP(strcat("^3", "suicides", " ^7", _("Number of suicides")));
157  case "sum": if (!mode) return CTX(_("SCO^sum")); else LOG_HELP(strcat("^3", "sum", " ^7", _("Number of kills minus deaths")));
158  case "takes": if (!mode) return CTX(_("SCO^takes")); else LOG_HELP(strcat("^3", "takes", " ^7", _("Number of domination points taken (Domination)")));
159  case "teamkills": if (!mode) return CTX(_("SCO^teamkills")); else LOG_HELP(strcat("^3", "teamkills", " ^7", _("Number of teamkills")));
160  case "ticks": if (!mode) return CTX(_("SCO^ticks")); else LOG_HELP(strcat("^3", "ticks", " ^7", _("Number of ticks (Domination)")));
161  case "time": if (!mode) return CTX(_("SCO^time")); else LOG_HELP(strcat("^3", "time", " ^7", _("Total time raced (Race/CTS)")));
162  default: return label;
163  }
164  return label;
165 }
166 
168 string TranslateScoresLabel(string label) { return Label_getInfo(label, 0); }
169 
170 #define SB_EXTRA_SORTING_FIELDS 5
173 {
174  int i, f;
175 
177  ts_primary = ts_secondary = -1;
178  FOREACH(Scores, true, {
179  f = (scores_flags(it) & SFL_SORT_PRIO_MASK);
180  if(f == SFL_SORT_PRIO_PRIMARY)
181  ps_primary = it;
182  if(f == SFL_SORT_PRIO_SECONDARY)
183  ps_secondary = it;
184  if(ps_primary == it || ps_secondary == it)
185  continue;
186  if (scores_label(it) == "kills") sb_extra_sorting_field[0] = it;
187  if (scores_label(it) == "deaths") sb_extra_sorting_field[1] = it;
188  if (scores_label(it) == "suicides") sb_extra_sorting_field[2] = it;
189  if (scores_label(it) == "dmg") sb_extra_sorting_field[3] = it;
190  if (scores_label(it) == "dmgtaken") sb_extra_sorting_field[4] = it;
191  });
192  if(ps_secondary == NULL)
194 
195  for(i = 0; i < MAX_TEAMSCORE; ++i)
196  {
198  if(f == SFL_SORT_PRIO_PRIMARY)
199  ts_primary = i;
200  if(f == SFL_SORT_PRIO_SECONDARY)
201  ts_secondary = i;
202  }
203  if(ts_secondary == -1)
205 
207 }
208 
209 //float lastpnum;
211 {
212  entity pl, tmp;
213  //int num = 0;
214  for(pl = players.sort_next; pl; pl = pl.sort_next)
215  {
216  //num += 1;
217  int Team = entcs_GetScoreTeam(pl.sv_entnum);
218  if(SetTeam(pl, Team))
219  {
220  tmp = pl.sort_prev;
222  if(tmp)
223  pl = tmp;
224  else
225  pl = players.sort_next;
226  }
227  }
228  /*
229  if(num != lastpnum)
230  print(strcat("PNUM: ", ftos(num), "\n"));
231  lastpnum = num;
232  */
233 }
234 
235 int Scoreboard_CompareScore(int vl, int vr, int f)
236 {
237  TC(int, vl); TC(int, vr); TC(int, f);
238  if(f & SFL_ZERO_IS_WORST)
239  {
240  if(vl == 0 && vr != 0)
241  return 1;
242  if(vl != 0 && vr == 0)
243  return 0;
244  }
245  if(vl > vr)
246  return IS_INCREASING(f);
247  if(vl < vr)
248  return IS_DECREASING(f);
249  return -1;
250 }
251 
253 {
254  int vl = (left.gotscores) ? entcs_GetTeam(left.sv_entnum) : NUM_SPECTATOR;
255  int vr = (right.gotscores) ? entcs_GetTeam(right.sv_entnum) : NUM_SPECTATOR;
256 
257  if(vl > vr)
258  return true;
259  if(vl < vr)
260  return false;
261 
262  if(vl == NUM_SPECTATOR)
263  {
264  // FIRST the one with scores (spectators), THEN the ones without (downloaders)
265  // no other sorting
266  if(!left.gotscores && right.gotscores)
267  return true;
268  return false;
269  }
270 
271  entity fld = NULL;
272  int r;
273  for (int i = -2; i < SB_EXTRA_SORTING_FIELDS; ++i)
274  {
275  if (i < 0)
276  {
277  if (!fld) fld = ps_primary;
278  else if (ps_secondary == ps_primary) continue;
279  else fld = ps_secondary;
280  }
281  else
282  {
283  fld = sb_extra_sorting_field[i];
284  if (fld == ps_primary || fld == ps_secondary) continue;
285  }
286  if (!fld) continue;
287 
288  r = Scoreboard_CompareScore(left.scores(fld), right.scores(fld), scores_flags(fld));
289  if (r >= 0) return r;
290  }
291 
292  if (left.sv_entnum < right.sv_entnum)
293  return true;
294 
295  return false;
296 }
297 
299 {
300  entity ent;
301  for(ent = player.sort_next; ent && Scoreboard_ComparePlayerScores(player, ent); ent = player.sort_next)
302  {
303  SORT_SWAP(player, ent);
304  }
305  for(ent = player.sort_prev; ent != players && Scoreboard_ComparePlayerScores(ent, player); ent = player.sort_prev)
306  {
307  SORT_SWAP(ent, player);
308  }
309 }
310 
312 {
313  if(left.team == NUM_SPECTATOR)
314  return 1;
315  if(right.team == NUM_SPECTATOR)
316  return 0;
317 
318  int fld_idx = -1;
319  int r;
320  for(int i = -2; i < MAX_TEAMSCORE; ++i)
321  {
322  if (i < 0)
323  {
324  if (fld_idx == -1) fld_idx = ts_primary;
325  else if (ts_secondary == ts_primary) continue;
326  else fld_idx = ts_secondary;
327  }
328  else
329  {
330  fld_idx = i;
331  if (fld_idx == ts_primary || fld_idx == ts_secondary) continue;
332  }
333 
334  r = Scoreboard_CompareScore(left.teamscores(fld_idx), right.teamscores(fld_idx), teamscores_flags(fld_idx));
335  if (r >= 0) return r;
336  }
337 
338  if (left.team < right.team)
339  return true;
340 
341  return false;
342 }
343 
345 {
346  entity ent;
347  for(ent = Team.sort_next; ent && Scoreboard_CompareTeamScores(Team, ent); ent = Team.sort_next)
348  {
349  SORT_SWAP(Team, ent);
350  }
351  for(ent = Team.sort_prev; ent != teams && Scoreboard_CompareTeamScores(ent, Team); ent = Team.sort_prev)
352  {
353  SORT_SWAP(ent, Team);
354  }
355 }
356 
358 {
359  LOG_HELP(_("You can modify the scoreboard using the ^2scoreboard_columns_set command."));
360  LOG_HELP(_("Usage:"));
361  LOG_HELP("^2scoreboard_columns_set ^3default");
362  LOG_HELP(_("^2scoreboard_columns_set ^3field1 field2 ..."));
363  LOG_HELP(_("^2scoreboard_columns_set ^7without arguments reads the arguments from the cvar scoreboard_columns"));
364  LOG_HELP(_(" ^5Note: ^7scoreboard_columns_set without arguments is executed on every map start"));
365  LOG_HELP(_("^2scoreboard_columns_set ^3expand_default ^7loads default layout and expands it into the cvar scoreboard_columns so you can edit it"));
366  LOG_HELP(_("You can use a ^3|^7 to start the right-aligned fields."));
367  LOG_HELP(_("The following field names are recognized (case insensitive):"));
368  LOG_HELP("");
369 
371  LOG_HELP("");
372 
373  LOG_HELP(_("Before a field you can put a + or - sign, then a comma separated list\n"
374  "of game types, then a slash, to make the field show up only in these\n"
375  "or in all but these game types. You can also specify 'all' as a\n"
376  "field to show all fields available for the current game mode."));
377  LOG_HELP("");
378 
379  LOG_HELP(_("The special game type names 'teams' and 'noteams' can be used to\n"
380  "include/exclude ALL teams/noteams game modes."));
381  LOG_HELP("");
382 
383  LOG_HELP(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4"));
384  LOG_HELP(_("will display name, ping and pl aligned to the left, and the fields\n"
385  "right of the vertical bar aligned to the right."));
386  LOG_HELP(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
387  "other gamemodes except DM."));
388 }
389 
390 // NOTE: adding a gametype with ? to not warn for an optional field
391 // make sure it's excluded in a previous exclusive rule, if any
392 // otherwise the previous exclusive rule warns anyway
393 // e.g. -teams,rc,cts,lms/kills ?+rc/kills
394 #define SCOREBOARD_DEFAULT_COLUMNS \
395 "ping pl fps name |" \
396 " -teams,rc,cts,inv,lms/kills +ft,tdm/kills ?+rc,inv/kills" \
397 " -teams,lms/deaths +ft,tdm/deaths" \
398 " +tdm/sum" \
399 " -teams,lms,rc,cts,inv,ka/suicides +ft,tdm/suicides ?+rc,inv/suicides" \
400 " -cts,dm,tdm,ka,ft/frags" /* tdm already has this in "score" */ \
401 " +tdm,ft,dom,ons,as/teamkills"\
402 " -rc,cts,nb/dmg -rc,cts,nb/dmgtaken" \
403 " +ctf/pickups +ctf/fckills +ctf/returns +ctf/caps +ons/takes +ons/caps" \
404 " +lms/lives +lms/rank" \
405 " +kh/kckills +kh/losses +kh/caps" \
406 " ?+rc/laps ?+rc/time +rc,cts/fastest" \
407 " +as/objectives +nb/faults +nb/goals" \
408 " +ka/pickups +ka/bckills +ka/bctime +ft/revivals" \
409 " +dom/ticks +dom/takes" \
410 " -lms,rc,cts,inv,nb/score"
411 
413 {
414  TC(int, argc);
415  int i, slash;
416  string str, pattern;
417  bool have_name = false, have_primary = false, have_secondary = false, have_separator = false;
418  int missing;
419 
420  if(!gametype)
421  return; // do nothing, we don't know gametype and scores yet
422 
423  // sbt_fields uses strunzone on the titles!
424  if(!sbt_field_title[0])
425  for(i = 0; i < MAX_SBT_FIELDS; ++i)
426  sbt_field_title[i] = strzone("(null)");
427 
428  // TODO: re enable with gametype dependant cvars?
429  if(argc < 3) // no arguments provided
431 
432  if(argc < 3)
434 
435  if(argc == 3)
436  {
437  if(argv(2) == "default" || argv(2) == "expand_default")
438  {
439  if(argv(2) == "expand_default")
440  cvar_set("scoreboard_columns", SCOREBOARD_DEFAULT_COLUMNS);
442  }
443  else if(argv(2) == "all" || argv(2) == "ALL")
444  {
445  string s = "ping pl name |"; // scores without label (not really scores)
446  if(argv(2) == "ALL")
447  {
448  // scores without label
449  s = strcat(s, " ", "sum");
450  s = strcat(s, " ", "kdratio");
451  s = strcat(s, " ", "frags");
452  }
453  FOREACH(Scores, true, {
454  if(it != ps_primary)
455  if(it != ps_secondary)
456  if(scores_label(it) != "")
457  s = strcat(s, " ", scores_label(it));
458  });
459  if(ps_secondary != ps_primary)
460  s = strcat(s, " ", scores_label(ps_secondary));
461  s = strcat(s, " ", scores_label(ps_primary));
462  argc = tokenizebyseparator(strcat("0 1 ", s), " ");
463  }
464  }
465 
466 
467  sbt_num_fields = 0;
468 
469  hud_fontsize = HUD_GetFontsize("hud_fontsize");
470 
471  for(i = 1; i < argc - 1; ++i)
472  {
473  str = argv(i+1);
474  bool nocomplain = false;
475  if(substring(str, 0, 1) == "?")
476  {
477  nocomplain = true;
478  str = substring(str, 1, strlen(str) - 1);
479  }
480 
481  slash = strstrofs(str, "/", 0);
482  if(slash >= 0)
483  {
484  pattern = substring(str, 0, slash);
485  str = substring(str, slash + 1, strlen(str) - (slash + 1));
486 
487  if (!isGametypeInFilter(gametype, teamplay, false, pattern))
488  continue;
489  }
490 
491  str = strtolower(str);
494 
496  switch(str)
497  {
498  // fields without a label (not networked via the score system)
499  case "ping": sbt_field[sbt_num_fields] = SP_PING; break;
500  case "pl": sbt_field[sbt_num_fields] = SP_PL; break;
501  case "name": case "nick": sbt_field[sbt_num_fields] = SP_NAME; have_name = true; break;
502  case "|": sbt_field[sbt_num_fields] = SP_SEPARATOR; have_separator = true; break;
503  case "kd": case "kdr": case "kdratio": sbt_field[sbt_num_fields] = SP_KDRATIO; break;
504  case "sum": case "diff": case "k-d": sbt_field[sbt_num_fields] = SP_SUM; break;
505  case "frags": sbt_field[sbt_num_fields] = SP_FRAGS; break;
506  default: // fields with a label
507  {
508  // map alternative labels
509  if (str == "damage") str = "dmg";
510  if (str == "damagetaken") str = "dmgtaken";
511 
512  FOREACH(Scores, true, {
513  if (str == strtolower(scores_label(it))) {
514  j = it;
515  goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
516  }
517  });
518 
519  // NOTE: can't check STAT(SHOWFPS) here, if checked too early it returns false anyway
520  if(!nocomplain && str != "fps") // server can disable the fps field
521  LOG_INFOF("^1Error:^7 Unknown score field: '%s'", str);
522 
523  strfree(sbt_field_title[sbt_num_fields]);
525  continue;
526 
527  LABEL(found)
529  if(j == ps_primary)
530  have_primary = true;
531  if(j == ps_secondary)
532  have_secondary = true;
533 
534  }
535  }
536  ++sbt_num_fields;
537  if(sbt_num_fields >= MAX_SBT_FIELDS)
538  break;
539  }
540 
542  have_primary = true;
543  if(scores_flags(ps_secondary) & SFL_ALLOW_HIDE)
544  have_secondary = true;
545  if(ps_primary == ps_secondary)
546  have_secondary = true;
547  missing = (!have_primary) + (!have_secondary) + (!have_separator) + (!have_name);
548 
549  if(sbt_num_fields + missing < MAX_SBT_FIELDS)
550  {
551  if(!have_name)
552  {
554  for(i = sbt_num_fields; i > 0; --i)
555  {
557  sbt_field_size[i] = sbt_field_size[i-1];
558  sbt_field[i] = sbt_field[i-1];
559  }
561  sbt_field[0] = SP_NAME;
562  ++sbt_num_fields;
563  LOG_INFO("fixed missing field 'name'");
564 
565  if(!have_separator)
566  {
567  strfree(sbt_field_title[sbt_num_fields]);
568  for(i = sbt_num_fields; i > 1; --i)
569  {
571  sbt_field_size[i] = sbt_field_size[i-1];
572  sbt_field[i] = sbt_field[i-1];
573  }
574  sbt_field_title[1] = strzone("|");
575  sbt_field[1] = SP_SEPARATOR;
576  sbt_field_size[1] = stringwidth("|", false, hud_fontsize);
577  ++sbt_num_fields;
578  LOG_INFO("fixed missing field '|'");
579  }
580  }
581  else if(!have_separator)
582  {
585  sbt_field[sbt_num_fields] = SP_SEPARATOR;
586  ++sbt_num_fields;
587  LOG_INFO("fixed missing field '|'");
588  }
589  if(!have_secondary)
590  {
594  ++sbt_num_fields;
595  LOG_INFOF("fixed missing field '%s'", scores_label(ps_secondary));
596  }
597  if(!have_primary)
598  {
602  ++sbt_num_fields;
603  LOG_INFOF("fixed missing field '%s'", scores_label(ps_primary));
604  }
605  }
606 
607  sbt_field[sbt_num_fields] = SP_END;
608 }
609 
610 string Scoreboard_AddPlayerId(string pl_name, entity pl)
611 {
614  return strcat(pref, itos(pl.sv_entnum + 1), suf, pl_name);
615 }
616 
617 // MOVEUP::
626 {
627  if(ready_waiting && pl.ready)
628  {
629  sbt_field_icon0 = "gfx/scoreboard/player_ready";
630  }
631  else if(!teamplay)
632  {
633  int f = entcs_GetClientColors(pl.sv_entnum);
634  {
635  sbt_field_icon0 = "gfx/scoreboard/playercolor_base";
636  sbt_field_icon1 = "gfx/scoreboard/playercolor_shirt";
638  sbt_field_icon2 = "gfx/scoreboard/playercolor_pants";
640  }
641  }
642  return entcs_GetName(pl.sv_entnum);
643 }
644 
646 {
647  float tmp, num, denom;
648  int f;
649  string str;
650  sbt_field_rgb = '1 1 1';
651  sbt_field_icon0 = "";
652  sbt_field_icon1 = "";
653  sbt_field_icon2 = "";
654  sbt_field_icon0_rgb = '1 1 1';
655  sbt_field_icon1_rgb = '1 1 1';
656  sbt_field_icon2_rgb = '1 1 1';
657  switch(field)
658  {
659  case SP_PING:
660  if (!pl.gotscores)
661  return "\xE2\x96\xB6\xE2\x96\xB6\xE2\x96\xB6"; // >>> sign using U+25B6 (Black Right-Pointing Triangle)
662  //str = getplayerkeyvalue(pl.sv_entnum, "ping");
663  f = pl.ping;
664  if(f == 0)
665  return _("N/A");
666  tmp = max(0, min(220, f-80)) / 220;
667  sbt_field_rgb = '1 1 1' - '0 1 1' * tmp;
668  return ftos(f);
669 
670  case SP_PL:
671  if (!pl.gotscores)
672  return _("N/A");
673  f = pl.ping_packetloss;
674  tmp = pl.ping_movementloss;
675  if(f == 0 && tmp == 0)
676  return "";
677  str = ftos(ceil(f * 100));
678  if(tmp != 0)
679  str = strcat(str, "~", ftos(ceil(tmp * 100)));
680  tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
681  sbt_field_rgb = '1 0.5 0.5' - '0 0.5 0.5' * tmp;
682  return str;
683 
684  case SP_NAME:
685  str = Scoreboard_GetName(pl);
687  str = Scoreboard_AddPlayerId(str, pl);
688  return str;
689 
690  case SP_FRAGS:
691  f = pl.(scores(SP_KILLS));
692  f -= pl.(scores(SP_SUICIDES));
693  return ftos(f);
694 
695  case SP_KDRATIO:
696  num = pl.(scores(SP_KILLS));
697  denom = pl.(scores(SP_DEATHS));
698 
699  if(denom == 0) {
700  sbt_field_rgb = '0 1 0';
701  str = sprintf("%d", num);
702  } else if(num <= 0) {
703  sbt_field_rgb = '1 0 0';
704  str = sprintf("%.1f", num/denom);
705  } else
706  str = sprintf("%.1f", num/denom);
707  return str;
708 
709  case SP_SUM:
710  f = pl.(scores(SP_KILLS));
711  f -= pl.(scores(SP_DEATHS));
712 
713  if(f > 0) {
714  sbt_field_rgb = '0 1 0';
715  } else if(f == 0) {
716  sbt_field_rgb = '1 1 1';
717  } else {
718  sbt_field_rgb = '1 0 0';
719  }
720  return ftos(f);
721 
722  case SP_ELO:
723  {
724  float elo = pl.(scores(SP_ELO));
725  switch (elo) {
726  case -1: return "...";
727  case -2: return _("N/A");
728  default: return ftos(elo);
729  }
730  }
731 
732  case SP_FPS:
733  {
734  float fps = pl.(scores(SP_FPS));
735  if(fps == 0)
736  {
737  sbt_field_rgb = '1 1 1';
738  return ((pl.ping == 0) ? _("N/A") : "..."); // if 0 ping, either connecting or bot (either case can't show proper score)
739  }
740  //sbt_field_rgb = HUD_Get_Num_Color(fps, 200, true);
741  sbt_field_rgb = '1 0 0' + '0 1 1' * (bound(0, fps, 60) / 60);
742  return ftos(fps);
743  }
744 
745  case SP_DMG: case SP_DMGTAKEN:
746  return sprintf("%.1f k", pl.(scores(field)) / 1000);
747 
748  default: case SP_SCORE:
749  tmp = pl.(scores(field));
750  f = scores_flags(field);
751  if(field == ps_primary)
752  sbt_field_rgb = '1 1 0';
753  else if(field == ps_secondary)
754  sbt_field_rgb = '0 1 1';
755  else
756  sbt_field_rgb = '1 1 1';
757  return ScoreString(f, tmp);
758  }
759  //return "error";
760 }
761 
765 
766 string Scoreboard_FixColumnWidth(int i, string str)
767 {
768  TC(int, i);
769  float f;
770  vector sz;
771 
773 
774  if(sbt_field_icon0 != "")
775  {
776  sz = draw_getimagesize(sbt_field_icon0);
777  f = sz.x / sz.y;
780  }
781 
782  if(sbt_field_icon1 != "")
783  {
784  sz = draw_getimagesize(sbt_field_icon1);
785  f = sz.x / sz.y;
788  }
789 
790  if(sbt_field_icon2 != "")
791  {
792  sz = draw_getimagesize(sbt_field_icon2);
793  f = sz.x / sz.y;
796  }
797 
799  {
800  sbt_fixcolumnwidth_iconlen *= hud_fontsize.y / hud_fontsize.x; // fix icon aspect
802  }
803  else
805 
806  if(sbt_field[i] == SP_NAME) // name gets all remaining space
807  {
808  int j;
809  float remaining_space = 0;
810  for(j = 0; j < sbt_num_fields; ++j)
811  if(j != i)
812  if (sbt_field[i] != SP_SEPARATOR)
813  remaining_space += sbt_field_size[j] + hud_fontsize.x;
814  sbt_field_size[i] = panel_size.x - remaining_space;
815 
818  float namesize = panel_size.x - remaining_space;
819  str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
821 
822  max_namesize = vid_conwidth - remaining_space;
823  }
824  else
826 
828  if(sbt_field_size[i] < f)
829  sbt_field_size[i] = f;
830 
831  return str;
832 }
833 
835 {
836  for(int i = 0; i < sbt_num_fields; ++i)
837  {
840  }
841 }
842 
843 vector Scoreboard_DrawHeader(vector pos, vector rgb, bool other_players)
844 {
845  int i;
846  vector column_dim = eY * panel_size.y;
847  if(other_players)
848  column_dim.y -= 1.25 * hud_fontsize.y;
849  vector text_offset = eY * (1.25 - 1) / 2 * hud_fontsize.y;
850  pos.x += hud_fontsize.x * 0.5;
851  for(i = 0; i < sbt_num_fields; ++i)
852  {
853  if(sbt_field[i] == SP_SEPARATOR)
854  break;
855  column_dim.x = sbt_field_size[i] + hud_fontsize.x;
856  if (sbt_highlight)
857  if (i % 2)
858  drawfill(pos - eX * hud_fontsize.x * 0.5, column_dim, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
859  drawstring(pos + text_offset, sbt_field_title[i], hud_fontsize, rgb * 1.5, sbt_fg_alpha, DRAWFLAG_NORMAL);
860  pos.x += column_dim.x;
861  }
862  if(sbt_field[i] == SP_SEPARATOR)
863  {
864  pos.x = panel_pos.x + panel_size.x - hud_fontsize.x * 0.5;
865  for(i = sbt_num_fields - 1; i > 0; --i)
866  {
867  if(sbt_field[i] == SP_SEPARATOR)
868  break;
869 
870  pos.x -= sbt_field_size[i];
871 
872  if (sbt_highlight)
873  if (!(i % 2))
874  {
875  column_dim.x = sbt_field_size[i] + hud_fontsize.x;
876  drawfill(pos - eX * hud_fontsize.x * 0.5, column_dim, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
877  }
878 
879  text_offset.x = sbt_field_size[i] - stringwidth(sbt_field_title[i], false, hud_fontsize);
880  drawstring(pos + text_offset, sbt_field_title[i], hud_fontsize, rgb * 1.5, sbt_fg_alpha, DRAWFLAG_NORMAL);
881  pos.x -= hud_fontsize.x;
882  }
883  }
884 
885  pos.x = panel_pos.x;
886  pos.y += 1.25 * hud_fontsize.y;
887  return pos;
888 }
889 
890 void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, int pl_number)
891 {
892  TC(bool, is_self); TC(int, pl_number);
893  string str;
894  bool is_spec = (entcs_GetSpecState(pl.sv_entnum) == ENTCS_SPEC_PURE);
895 
896  vector h_pos = item_pos;
897  vector h_size = vec2(panel_size.x, hud_fontsize.y * 1.25);
898  // alternated rows highlighting
899  if(is_self)
900  drawfill(h_pos, h_size, rgb, sbt_highlight_alpha_self, DRAWFLAG_NORMAL);
901  else if((sbt_highlight) && (!(pl_number % 2)))
902  drawfill(h_pos, h_size, rgb, sbt_highlight_alpha, DRAWFLAG_NORMAL);
903 
904  float fg_alpha = (is_self ? sbt_fg_alpha_self : sbt_fg_alpha);
905 
906  vector pos = item_pos;
907  // put a "self indicator" beside the self row, unicode U+25C0 (black left-pointing triangle)
908  if (is_self)
909  drawstring(pos + eX * (panel_size.x + 0.5 * hud_fontsize.x) + eY, "\xE2\x97\x80", hud_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
910 
911  pos.x += hud_fontsize.x * 0.5;
912  pos.y += (1.25 - 1) / 2 * hud_fontsize.y; // center text vertically
913  vector tmp = '0 0 0';
914  int i;
915  PlayerScoreField field;
916  for(i = 0; i < sbt_num_fields; ++i)
917  {
918  field = sbt_field[i];
919  if(field == SP_SEPARATOR)
920  break;
921 
922  if(is_spec && field != SP_NAME && field != SP_PING) {
923  pos.x += sbt_field_size[i] + hud_fontsize.x;
924  continue;
925  }
926  str = Scoreboard_GetField(pl, field);
927  str = Scoreboard_FixColumnWidth(i, str);
928 
929  pos.x += sbt_field_size[i] + hud_fontsize.x;
930 
931  if(field == SP_NAME) {
933  drawcolorcodedstring(pos - tmp, str, hud_fontsize, fg_alpha, DRAWFLAG_NORMAL);
934  } else {
936  drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, fg_alpha, DRAWFLAG_NORMAL);
937  }
938 
939  tmp.x = sbt_field_size[i] + hud_fontsize.x;
940  if(sbt_field_icon0 != "")
942  if(sbt_field_icon1 != "")
944  if(sbt_field_icon2 != "")
946  }
947 
948  if(sbt_field[i] == SP_SEPARATOR)
949  {
950  pos.x = item_pos.x + panel_size.x - hud_fontsize.x * 0.5;
951  for(i = sbt_num_fields-1; i > 0; --i)
952  {
953  field = sbt_field[i];
954  if(field == SP_SEPARATOR)
955  break;
956 
957  if(is_spec && field != SP_NAME && field != SP_PING) {
958  pos.x -= sbt_field_size[i] + hud_fontsize.x;
959  continue;
960  }
961 
962  str = Scoreboard_GetField(pl, field);
963  str = Scoreboard_FixColumnWidth(i, str);
964 
965  if(field == SP_NAME) {
966  tmp.x = sbt_fixcolumnwidth_len; // left or right aligned? let's put it right...
967  drawcolorcodedstring(pos - tmp, str, hud_fontsize, fg_alpha, DRAWFLAG_NORMAL);
968  } else {
969  tmp.x = sbt_fixcolumnwidth_len;
970  drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, fg_alpha, DRAWFLAG_NORMAL);
971  }
972 
973  tmp.x = sbt_field_size[i];
974  if(sbt_field_icon0 != "")
976  if(sbt_field_icon1 != "")
978  if(sbt_field_icon2 != "")
980  pos.x -= sbt_field_size[i] + hud_fontsize.x;
981  }
982  }
983 
984  if(pl.eliminated)
985  drawfill(h_pos, h_size, '0 0 0', sbt_highlight_alpha_eliminated, DRAWFLAG_NORMAL);
986 }
987 
988 vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity ignored_pl, entity pl, int pl_number)
989 {
990  int i = 0;
991  vector h_pos = item_pos;
992  vector h_size = vec2(panel_size.x, hud_fontsize.y * 1.25);
993 
994  bool complete = (this_team == NUM_SPECTATOR);
995 
996  if(!complete)
997  if((sbt_highlight) && (!(pl_number % 2)))
998  drawfill(h_pos, h_size, rgb, sbt_highlight_alpha, DRAWFLAG_NORMAL);
999 
1000  vector pos = item_pos;
1001  pos.x += hud_fontsize.x * 0.5;
1002  pos.y += (1.25 - 1) / 2 * hud_fontsize.y; // center text vertically
1003 
1004  float width_limit = item_pos.x + panel_size.x - hud_fontsize.x;
1005  if(!complete)
1006  width_limit -= stringwidth("...", false, hud_fontsize);
1008  static float max_name_width = 0;
1009  string field = "";
1010  float fieldsize = 0;
1011  float min_fieldsize = 0;
1012  float fieldpadding = hud_fontsize.x * 0.25;
1013  if(this_team == NUM_SPECTATOR)
1014  {
1016  min_fieldsize = stringwidth("999", false, hud_fontsize);
1017  }
1019  min_fieldsize = stringwidth("99", false, hud_fontsize);
1020  for(i = 0; pl; pl = pl.sort_next)
1021  {
1022  if(pl.team != this_team)
1023  continue;
1024  if(pl == ignored_pl)
1025  continue;
1026 
1027  field = "";
1028  if(this_team == NUM_SPECTATOR)
1029  {
1031  field = Scoreboard_GetField(pl, SP_PING);
1032  }
1034  field = Scoreboard_GetField(pl, SP_SCORE);
1035 
1036  string str = entcs_GetName(pl.sv_entnum);
1038  str = Scoreboard_AddPlayerId(str, pl);
1039  str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
1040  float column_width = stringwidth(str, true, hud_fontsize);
1042  {
1043  if(column_width > max_name_width)
1044  max_name_width = column_width;
1045  column_width = max_name_width;
1046  }
1047  if(field != "")
1048  {
1049  fieldsize = stringwidth(field, false, hud_fontsize);
1050  column_width += hud_fontsize.x * 0.25 + max(fieldsize, min_fieldsize) + 2 * fieldpadding;
1051  }
1052 
1053  if(pos.x + column_width > width_limit)
1054  {
1055  ++i;
1056  if(!complete)
1057  {
1058  drawstring(pos, "...", hud_fontsize, '1 1 1', sbt_fg_alpha, DRAWFLAG_NORMAL);
1059  break;
1060  }
1061  else
1062  {
1063  pos.x = item_pos.x + hud_fontsize.x * 0.5;
1064  pos.y += hud_fontsize.y * 1.25;
1065  }
1066  }
1067 
1068  vector name_pos = pos;
1070  name_pos.x += max(fieldsize, min_fieldsize) + 2 * fieldpadding + hud_fontsize.x * 0.25;
1072  if(field != "")
1073  {
1074  h_size.x = max(fieldsize, min_fieldsize) + 2 * fieldpadding;
1075  h_size.y = hud_fontsize.y;
1076  vector field_pos = pos;
1078  field_pos.x += column_width - h_size.x;
1079  if(sbt_highlight)
1080  drawfill(field_pos, h_size, '1 1 1', sbt_highlight_alpha, DRAWFLAG_NORMAL);
1081  field_pos.x += fieldpadding + (max(fieldsize, min_fieldsize) - fieldsize) * 0.5;
1083  }
1084  if(pl.eliminated)
1085  {
1086  h_size.x = column_width + hud_fontsize.x * 0.25;
1087  h_size.y = hud_fontsize.y;
1088  drawfill(pos - hud_fontsize.x * 0.25 * eX, h_size, '0 0 0', sbt_highlight_alpha_eliminated, DRAWFLAG_NORMAL);
1089  }
1090  pos.x += column_width;
1091  pos.x += hud_fontsize.x;
1092  }
1093  return vec2(item_pos.x, item_pos.y + i * hud_fontsize.y * 1.25);
1094 }
1095 
1097 {
1098  int max_players = 999;
1100  {
1102  if(teamplay)
1103  {
1104  height -= (panel_bg_padding * 2 + hud_fontsize.y * 1.25) * team_count; // - padding and header
1105  height -= hud_fontsize.y * (team_count - 1); // - spacing between tables
1106  height /= team_count;
1107  }
1108  else
1109  height -= panel_bg_padding * 2; // - padding
1110  max_players = floor(height / (hud_fontsize.y * 1.25));
1111  if(max_players <= 1)
1112  max_players = 1;
1113  if(max_players == tm.team_size)
1114  max_players = 999;
1115  }
1116 
1117  entity pl;
1119  panel_pos = pos;
1120  panel_size.y = 1.25 * hud_fontsize.y * (1 + bound(1, tm.team_size, max_players));
1121  panel_size.y += panel_bg_padding * 2;
1122  HUD_Panel_DrawBg();
1123 
1124  vector end_pos = panel_pos + eY * (panel_size.y + 0.5 * hud_fontsize.y);
1125  if(panel.current_panel_bg != "0")
1126  end_pos.y += panel_bg_border * 2;
1127 
1128  if(panel_bg_padding)
1129  {
1130  panel_pos += '1 1 0' * panel_bg_padding;
1131  panel_size -= '2 2 0' * panel_bg_padding;
1132  }
1133 
1134  pos = panel_pos;
1135  vector tmp = vec2(panel_size.x, 1.25 * hud_fontsize.y);
1136 
1137  // rounded header
1138  if (sbt_bg_alpha)
1139  drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', sbt_bg_alpha, DRAWFLAG_NORMAL);
1140 
1141  pos.y += 1.25 * hud_fontsize.y;
1142 
1143  // table background
1144  tmp.y = panel_size.y - 1.25 * hud_fontsize.y;
1145  if (sbt_bg_alpha)
1146  drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha, DRAWFLAG_NORMAL);
1147 
1148 
1149  // print header row and highlight columns
1150  pos = Scoreboard_DrawHeader(panel_pos, rgb, (max_players < tm.team_size));
1151 
1152  // fill the table and draw the rows
1153  bool is_self = false;
1154  bool self_shown = false;
1155  int i = 0;
1156  for(pl = players.sort_next; pl; pl = pl.sort_next)
1157  {
1158  if(pl.team != tm.team)
1159  continue;
1160  if(i == max_players - 2 && pl != me)
1161  {
1162  if(!self_shown && me.team == tm.team)
1163  {
1164  Scoreboard_DrawItem(pos, rgb, me, true, i);
1165  self_shown = true;
1166  pos.y += 1.25 * hud_fontsize.y;
1167  ++i;
1168  }
1169  }
1170  if(i >= max_players - 1)
1171  {
1172  pos = Scoreboard_DrawOthers(pos, rgb, tm.team, (self_shown ? me : NULL), pl, i);
1173  break;
1174  }
1175  is_self = (pl.sv_entnum == current_player);
1176  Scoreboard_DrawItem(pos, rgb, pl, is_self, i);
1177  if(is_self)
1178  self_shown = true;
1179  pos.y += 1.25 * hud_fontsize.y;
1180  ++i;
1181  }
1182 
1183  panel_size.x += panel_bg_padding * 2; // restore initial width
1184  return end_pos;
1185 }
1186 
1188 {
1189  if (MUTATOR_CALLHOOK(DrawScoreboard))
1190  return false;
1191  else if (QuickMenu_IsOpened())
1192  return false;
1193  else if (HUD_Radar_Clickable())
1194  return false;
1195  else if (scoreboard_showscores)
1196  return true;
1197  else if (intermission == 1)
1198  return true;
1199  else if (intermission == 2)
1200  return false;
1201  else if (spectatee_status != -1 && STAT(HEALTH) <= 0 && autocvar_cl_deathscoreboard && !MUTATOR_CALLHOOK(DrawDeathScoreboard)
1203  {
1204  return true;
1205  }
1206  else if (scoreboard_showscores_force || MUTATOR_CALLHOOK(DrawScoreboard_Force))
1207  return true;
1208  return false;
1209 }
1210 
1213 {
1215 
1216  WepSet weapons_stat = WepSet_GetFromStat();
1217  WepSet weapons_inmap = WepSet_GetFromStat_InMap();
1218  int disownedcnt = 0;
1219  int nHidden = 0;
1220  FOREACH(Weapons, it != WEP_Null, {
1221  int weapon_stats = weapon_accuracy[i - WEP_FIRST];
1222 
1223  WepSet set = it.m_wepset;
1224  if(it.spawnflags & WEP_TYPE_OTHER)
1225  {
1226  ++nHidden;
1227  continue;
1228  }
1229  if (weapon_stats < 0 && !((weapons_stat & set) || (weapons_inmap & set)))
1230  {
1232  ++nHidden;
1233  else
1234  ++disownedcnt;
1235  }
1236  });
1237 
1238  int weapon_cnt = (REGISTRY_COUNT(Weapons) - 1) - disownedcnt - nHidden;
1239  if (weapon_cnt <= 0) return pos;
1240 
1241  int rows = 1;
1242  if (autocvar_hud_panel_scoreboard_accuracy_doublerows && weapon_cnt >= floor((REGISTRY_COUNT(Weapons) - nHidden - 1) * 0.5))
1243  rows = 2;
1244  int columns = ceil(weapon_cnt / rows);
1245 
1246  float aspect = max(0.001, autocvar_hud_panel_weapons_aspect);
1247  float weapon_height = hud_fontsize.y * 2.3 / aspect;
1248  float height = weapon_height + hud_fontsize.y;
1249 
1250  drawstring(pos + eX * panel_bg_padding, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', panel_fg_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
1251  pos.y += 1.25 * hud_fontsize.y;
1252  if(panel.current_panel_bg != "0")
1253  pos.y += panel_bg_border;
1254 
1255  panel_pos = pos;
1256  panel_size.y = height * rows;
1257  panel_size.y += panel_bg_padding * 2;
1258 
1259  float panel_bg_alpha_save = panel_bg_alpha;
1261  HUD_Panel_DrawBg();
1262  panel_bg_alpha = panel_bg_alpha_save;
1263 
1264  vector end_pos = panel_pos + eY * (panel_size.y + 0.5 * hud_fontsize.y);
1265  if(panel.current_panel_bg != "0")
1266  end_pos.y += panel_bg_border * 2;
1267 
1268  if(panel_bg_padding)
1269  {
1270  panel_pos += '1 1 0' * panel_bg_padding;
1271  panel_size -= '2 2 0' * panel_bg_padding;
1272  }
1273 
1274  pos = panel_pos;
1275  vector tmp = panel_size;
1276 
1277  float weapon_width = tmp.x / columns / rows;
1278 
1279  if (sbt_bg_alpha)
1280  drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
1281 
1282  if(sbt_highlight)
1283  {
1284  // column highlighting
1285  for (int i = 0; i < columns; ++i)
1286  if ((i % 2) == 0)
1287  drawfill(pos + eX * weapon_width * rows * i, vec2(weapon_width * rows, height * rows), '0 0 0', sbt_highlight_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
1288 
1289  // row highlighting
1290  for (int i = 0; i < rows; ++i)
1291  drawfill(pos + eY * (weapon_height + height * i), vec2(tmp.x, hud_fontsize.y), rgb, sbt_highlight_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
1292  }
1293 
1294  average_accuracy = 0;
1295  int weapons_with_stats = 0;
1296  if (rows == 2)
1297  pos.x += weapon_width / 2;
1298 
1300  rgb = '1 1 1';
1301  else
1303 
1304  float oldposx = pos.x;
1305  vector tmpos = pos;
1306 
1307  int column = 0;
1308  FOREACH(Weapons, it != WEP_Null, {
1309  int weapon_stats = weapon_accuracy[i - WEP_FIRST];
1310 
1311  WepSet set = it.m_wepset;
1312  if (weapon_stats < 0 && !((weapons_stat & set) || (weapons_inmap & set)))
1313  continue;
1314  if (it.spawnflags & WEP_TYPE_OTHER)
1315  continue;
1316 
1317  float weapon_alpha;
1318  if (weapon_stats >= 0)
1319  weapon_alpha = sbt_fg_alpha;
1320  else
1321  weapon_alpha = 0.2 * sbt_fg_alpha;
1322 
1323  // weapon icon
1324  drawpic_aspect_skin(tmpos, it.model2, vec2(weapon_width, weapon_height), '1 1 1', weapon_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
1325  // the accuracy
1326  if (weapon_stats >= 0) {
1327  weapons_with_stats += 1;
1328  average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
1329 
1330  string s = sprintf("%d%%", weapon_stats * 100);
1331  float padding = (weapon_width - stringwidth(s, false, hud_fontsize)) / 2;
1332 
1334  rgb = Accuracy_GetColor(weapon_stats);
1335 
1336  drawstring(tmpos + vec2(padding, weapon_height), s, hud_fontsize, rgb, sbt_fg_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
1337  }
1338  tmpos.x += weapon_width * rows;
1339  pos.x += weapon_width * rows;
1340  if (rows == 2 && column == columns - 1) {
1341  tmpos.x = oldposx;
1342  tmpos.y += height;
1343  pos.y += height;
1344  }
1345  ++column;
1346  });
1347 
1348  if (weapons_with_stats)
1349  average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
1350 
1351  panel_size.x += panel_bg_padding * 2; // restore initial width
1352 
1353  return end_pos;
1354 }
1355 
1357 {
1359  return false;
1361  if (mask <= 0)
1362  return false;
1363  if (it.instanceOfArmor || it.instanceOfHealth)
1364  {
1365  int ha_mask = floor(mask) % 10;
1366  switch (ha_mask)
1367  {
1368  default: return false;
1369  case 4: if (it == ITEM_HealthMega || it == ITEM_ArmorMega) return true; // else fallthrough
1370  case 3: if (it == ITEM_HealthBig || it == ITEM_ArmorBig) return true; // else fallthrough
1371  case 2: if (it == ITEM_HealthMedium || it == ITEM_ArmorMedium) return true; // else fallthrough
1372  case 1: if (it == ITEM_HealthSmall || it == ITEM_ArmorSmall) return true; // else fallthrough
1373  }
1374  }
1375  if (it.instanceOfAmmo)
1376  {
1377  int ammo_mask = floor(mask / 10) % 10;
1378  return (ammo_mask == 1);
1379  }
1380  return false;
1381 }
1382 
1384 {
1386 
1387  int disowned_cnt = 0;
1388  int uninteresting_cnt = 0;
1389  IL_EACH(default_order_items, true, {
1390  int q = g_inventory.inv_items[it.m_id];
1391  //q = 1; // debug: display all items
1392  if (is_item_filtered(it))
1393  ++uninteresting_cnt;
1394  else if (!q)
1395  ++disowned_cnt;
1396  });
1397  int items_cnt = REGISTRY_COUNT(Items) - uninteresting_cnt;
1398  int n = items_cnt - disowned_cnt;
1399  if (n <= 0) return pos;
1400 
1401  int rows = (autocvar_hud_panel_scoreboard_itemstats_doublerows && n >= floor(REGISTRY_COUNT(Items) / 2)) ? 2 : 1;
1402  int columns = max(6, ceil(n / rows));
1403 
1404  float item_height = hud_fontsize.y * 2.3;
1405  float height = item_height + hud_fontsize.y;
1406 
1408  pos.y += 1.25 * hud_fontsize.y;
1409  if(panel.current_panel_bg != "0")
1410  pos.y += panel_bg_border;
1411 
1412  panel_pos = pos;
1413  panel_size.y = height * rows;
1414  panel_size.y += panel_bg_padding * 2;
1415 
1416  float panel_bg_alpha_save = panel_bg_alpha;
1418  HUD_Panel_DrawBg();
1419  panel_bg_alpha = panel_bg_alpha_save;
1420 
1421  vector end_pos = panel_pos + eY * (panel_size.y + 0.5 * hud_fontsize.y);
1422  if(panel.current_panel_bg != "0")
1423  end_pos.y += panel_bg_border * 2;
1424 
1425  if(panel_bg_padding)
1426  {
1427  panel_pos += '1 1 0' * panel_bg_padding;
1428  panel_size -= '2 2 0' * panel_bg_padding;
1429  }
1430 
1431  pos = panel_pos;
1432  vector tmp = panel_size;
1433 
1434  float item_width = tmp.x / columns / rows;
1435 
1436  if (sbt_bg_alpha)
1437  drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL);
1438 
1439  if(sbt_highlight)
1440  {
1441  // column highlighting
1442  for (int i = 0; i < columns; ++i)
1443  if ((i % 2) == 0)
1444  drawfill(pos + eX * item_width * rows * i, vec2(item_width * rows, height * rows), '0 0 0', sbt_highlight_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL);
1445 
1446  // row highlighting
1447  for (int i = 0; i < rows; ++i)
1448  drawfill(pos + eY * (item_height + height * i), vec2(panel_size.x, hud_fontsize.y), rgb, sbt_highlight_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL);
1449  }
1450 
1451  if (rows == 2)
1452  pos.x += item_width / 2;
1453 
1454  float oldposx = pos.x;
1455  vector tmpos = pos;
1456 
1457  int column = 0;
1458  IL_EACH(default_order_items, !is_item_filtered(it), {
1459  int n = g_inventory.inv_items[it.m_id];
1460  //n = 1 + floor(i * 3 + 4.8) % 7; // debug: display a value for each item
1461  if (n <= 0) continue;
1462  drawpic_aspect_skin(tmpos, it.m_icon, eX * item_width + eY * item_height, '1 1 1', panel_fg_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL);
1463  string s = ftos(n);
1464  float padding = (item_width - stringwidth(s, false, hud_fontsize)) / 2;
1465  drawstring(tmpos + vec2(padding, item_height), s, hud_fontsize, '1 1 1', panel_fg_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL);
1466  tmpos.x += item_width * rows;
1467  pos.x += item_width * rows;
1468  if (rows == 2 && column == columns - 1) {
1469  tmpos.x = oldposx;
1470  tmpos.y += height;
1471  pos.y += height;
1472  }
1473  ++column;
1474  });
1475 
1476  panel_size.x += panel_bg_padding * 2; // restore initial width
1477 
1478  return end_pos;
1479 }
1480 
1481 vector MapStats_DrawKeyValue(vector pos, string key, string value) {
1482  float px = pos.x;
1483  pos.x += hud_fontsize.x * 0.25;
1484  drawstring(pos, key, hud_fontsize, '1 1 1', sbt_fg_alpha, DRAWFLAG_NORMAL);
1485  pos.x = panel_pos.x + panel_size.x - stringwidth(value, false, hud_fontsize) - hud_fontsize.x * 0.25;
1486  drawstring(pos, value, hud_fontsize, '1 1 1', sbt_fg_alpha, DRAWFLAG_NORMAL);
1487  pos.x = px;
1488  pos.y += hud_fontsize.y;
1489 
1490  return pos;
1491 }
1492 
1494  float stat_secrets_found, stat_secrets_total;
1495  float stat_monsters_killed, stat_monsters_total;
1496  float rows = 0;
1497  string val;
1498 
1499  // get monster stats
1500  stat_monsters_killed = STAT(MONSTERS_KILLED);
1501  stat_monsters_total = STAT(MONSTERS_TOTAL);
1502 
1503  // get secrets stats
1504  stat_secrets_found = STAT(SECRETS_FOUND);
1505  stat_secrets_total = STAT(SECRETS_TOTAL);
1506 
1507  // get number of rows
1508  if(stat_secrets_total)
1509  rows += 1;
1510  if(stat_monsters_total)
1511  rows += 1;
1512 
1513  // if no rows, return
1514  if (!rows)
1515  return pos;
1516 
1517  // draw table header
1518  drawstring(pos + eX * panel_bg_padding, _("Map stats:"), hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
1519  pos.y += 1.25 * hud_fontsize.y;
1520  if(panel.current_panel_bg != "0")
1521  pos.y += panel_bg_border;
1522 
1523  panel_pos = pos;
1524  panel_size.y = hud_fontsize.y * rows;
1525  panel_size.y += panel_bg_padding * 2;
1526  HUD_Panel_DrawBg();
1527 
1528  vector end_pos = panel_pos + eY * (panel_size.y + 0.5 * hud_fontsize.y);
1529  if(panel.current_panel_bg != "0")
1530  end_pos.y += panel_bg_border * 2;
1531 
1532  if(panel_bg_padding)
1533  {
1534  panel_pos += '1 1 0' * panel_bg_padding;
1535  panel_size -= '2 2 0' * panel_bg_padding;
1536  }
1537 
1538  pos = panel_pos;
1539  vector tmp = panel_size;
1540 
1541  if (sbt_bg_alpha)
1542  drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha, DRAWFLAG_NORMAL);
1543 
1544  // draw monsters
1545  if(stat_monsters_total)
1546  {
1547  val = sprintf("%d/%d", stat_monsters_killed, stat_monsters_total);
1548  pos = MapStats_DrawKeyValue(pos, _("Monsters killed:"), val);
1549  }
1550 
1551  // draw secrets
1552  if(stat_secrets_total)
1553  {
1554  val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
1555  pos = MapStats_DrawKeyValue(pos, _("Secrets found:"), val);
1556  }
1557 
1558  panel_size.x += panel_bg_padding * 2; // restore initial width
1559  return end_pos;
1560 }
1561 
1565 vector Scoreboard_Rankings_Draw(vector pos, string ranktitle, entity pl, vector rgb, vector bg_size)
1566 {
1567  int i;
1569  for (i=RANKINGS_CNT-1; i>=0; --i)
1570  if (grecordtime[i])
1572 
1573  if (RANKINGS_RECEIVED_CNT == 0)
1574  return pos;
1575 
1576  vector hl_rgb = rgb + '0.5 0.5 0.5';
1577 
1578  drawstring(pos + eX * panel_bg_padding, ranktitle, hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
1579  pos.y += 1.25 * hud_fontsize.y;
1580  if(panel.current_panel_bg != "0")
1581  pos.y += panel_bg_border;
1582 
1583  panel_pos = pos;
1584 
1585  float namesize = 0;
1586  for(i = 0; i < RANKINGS_RECEIVED_CNT; ++i)
1587  {
1589  if(f > namesize)
1590  namesize = f;
1591  }
1592  bool cut = false;
1594  {
1596  cut = true;
1597  }
1598 
1599  float ranksize = 3 * hud_fontsize.x;
1600  float timesize = 5 * hud_fontsize.x;
1601  vector columnsize = vec2(ranksize + timesize + namesize + hud_fontsize.x, 1.25 * hud_fontsize.y);
1602  rankings_columns = max(1, floor((panel_size.x - 2 * panel_bg_padding) / columnsize.x));
1603  rankings_columns = min(rankings_columns, RANKINGS_RECEIVED_CNT);
1604  if (!rankings_cnt)
1605  {
1608  }
1609 
1610  // expand name column to fill the entire row
1611  float available_space = (panel_size.x - 2 * panel_bg_padding - columnsize.x * rankings_columns) / rankings_columns;
1612  namesize += available_space;
1613  columnsize.x += available_space;
1614 
1615  panel_size.y = rankings_rows * 1.25 * hud_fontsize.y;
1616  panel_size.y += panel_bg_padding * 2;
1617 
1618  HUD_Panel_DrawBg();
1619 
1620  vector end_pos = panel_pos + eY * (panel_size.y + 0.5 * hud_fontsize.y);
1621  if(panel.current_panel_bg != "0")
1622  end_pos.y += panel_bg_border * 2;
1623 
1624  if(panel_bg_padding)
1625  {
1626  panel_pos += '1 1 0' * panel_bg_padding;
1627  panel_size -= '2 2 0' * panel_bg_padding;
1628  }
1629 
1630  pos = panel_pos;
1631 
1632  if (sbt_bg_alpha)
1633  drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, panel_size, rgb, sbt_bg_alpha, DRAWFLAG_NORMAL);
1634 
1635  vector text_ofs = vec2(0.5 * hud_fontsize.x, (1.25 - 1) / 2 * hud_fontsize.y); // center text vertically
1636  string str = "";
1637  int column = 0, j = 0;
1638  string zoned_name_self = strzone(strdecolorize(entcs_GetName(player_localnum)));
1639  for(i = 0; i < rankings_cnt; ++i)
1640  {
1641  float t;
1642  t = grecordtime[i];
1643  if (t == 0)
1644  continue;
1645 
1646  if(strdecolorize(grecordholder[i]) == zoned_name_self)
1647  drawfill(pos, columnsize, hl_rgb, sbt_highlight_alpha_self, DRAWFLAG_NORMAL);
1648  else if(!((j + column) & 1) && sbt_highlight)
1649  drawfill(pos, columnsize, hl_rgb, sbt_highlight_alpha, DRAWFLAG_NORMAL);
1650 
1651  str = count_ordinal(i+1);
1652  drawstring(pos + text_ofs, str, hud_fontsize, '1 1 1', sbt_fg_alpha, DRAWFLAG_NORMAL);
1653  drawstring(pos + text_ofs + eX * ranksize, TIME_ENCODED_TOSTRING(t), hud_fontsize, '1 1 1', sbt_fg_alpha, DRAWFLAG_NORMAL);
1654  str = ColorTranslateRGB(grecordholder[i]);
1655  if(cut)
1656  str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
1657  drawcolorcodedstring(pos + text_ofs + eX * (ranksize + timesize), str, hud_fontsize, sbt_fg_alpha, DRAWFLAG_NORMAL);
1658 
1659  pos.y += 1.25 * hud_fontsize.y;
1660  j++;
1661  if(j >= rankings_rows)
1662  {
1663  column++;
1664  j = 0;
1665  pos.x += panel_size.x / rankings_columns;
1666  pos.y = panel_pos.y;
1667  }
1668  }
1669  strfree(zoned_name_self);
1670 
1671  panel_size.x += panel_bg_padding * 2; // restore initial width
1672  return end_pos;
1673 }
1674 
1678 {
1679  if (MUTATOR_CALLHOOK(DrawScoreboardAccuracy))
1680  return false;
1682  return false;
1683 
1686  && !intermission)
1687  {
1688  return false;
1689  }
1690 
1691  if (!have_weapon_stats)
1692  {
1693  FOREACH(Weapons, it != WEP_Null, {
1694  int weapon_stats = weapon_accuracy[i - WEP_FIRST];
1695  if (weapon_stats >= 0)
1696  {
1697  have_weapon_stats = true;
1698  break;
1699  }
1700  });
1701  if (!have_weapon_stats)
1702  return false;
1703  }
1704 
1705  return true;
1706 }
1707 
1710 {
1711  if (MUTATOR_CALLHOOK(DrawScoreboardItemStats))
1712  return false;
1713  if (!autocvar_hud_panel_scoreboard_itemstats || !g_inventory || warmup_stage || ypos > 0.91 * vid_conheight)
1714  return false;
1715 
1718  && !intermission)
1719  {
1720  return false;
1721  }
1722 
1723  if (!have_item_stats)
1724  {
1725  IL_EACH(default_order_items, true, {
1726  if (!is_item_filtered(it))
1727  {
1728  int q = g_inventory.inv_items[it.m_id];
1729  //q = 1; // debug: display all items
1730  if (q)
1731  {
1732  have_item_stats = true;
1733  break;
1734  }
1735  }
1736  });
1737  if (!have_item_stats)
1738  return false;
1739  }
1740 
1741  return true;
1742 }
1743 
1745 
1746  entity pl, tm;
1747  string str = "";
1748 
1749  for(pl = players.sort_next; pl; pl = pl.sort_next)
1750  {
1751  if(pl.team == NUM_SPECTATOR)
1752  {
1753  for(tm = teams.sort_next; tm; tm = tm.sort_next)
1754  if(tm.team == NUM_SPECTATOR)
1755  break;
1756  str = sprintf("%s (%d)", _("Spectators"), tm.team_size);
1758  drawstring(pos, str, hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
1759  draw_endBoldFont();
1760  pos.y += 1.25 * hud_fontsize.y;
1761 
1762  pos = Scoreboard_DrawOthers(pos, '0 0 0', pl.team, NULL, pl, 0);
1763  pos.y += 1.25 * hud_fontsize.y;
1764 
1765  break;
1766  }
1767  }
1768  if (str != "") // if there's at least one spectator
1769  pos.y += 0.5 * hud_fontsize.y;
1770 
1771  return pos;
1772 }
1773 
1775 {
1777  {
1778  if(!hud_draw_maximized) return;
1779 
1780  // frametime checks allow to toggle the scoreboard even when the game is paused
1781  if(scoreboard_active) {
1782  if (scoreboard_fade_alpha == 0)
1784  if(hud_configure_menu_open == 1)
1786  float scoreboard_fadeinspeed = autocvar_hud_panel_scoreboard_fadeinspeed;
1787  if (scoreboard_fadeinspeed && frametime)
1788  scoreboard_fade_alpha = min(1, scoreboard_fade_alpha + frametime * scoreboard_fadeinspeed);
1789  else
1792  {
1793  hud_fontsize = HUD_GetFontsize("hud_fontsize");
1796  }
1797  }
1798  else {
1799  float scoreboard_fadeoutspeed = autocvar_hud_panel_scoreboard_fadeoutspeed;
1800  if (scoreboard_fadeoutspeed && frametime)
1801  scoreboard_fade_alpha = max(0, scoreboard_fade_alpha - frametime * scoreboard_fadeoutspeed);
1802  else
1804  }
1805 
1806  if (!scoreboard_fade_alpha)
1807  {
1810  return;
1811  }
1812  }
1813  else
1815 
1817  HUD_Scale_Enable();
1818  else
1820 
1821  if(scoreboard_fade_alpha <= 0)
1822  return;
1825 
1833 
1834  // don't overlap with con_notify
1837 
1839  float fixed_scoreboard_width = bound(vid_conwidth * autocvar_hud_panel_scoreboard_minwidth, vid_conwidth - excess, vid_conwidth * 0.93);
1840  scoreboard_left = 0.5 * (vid_conwidth - fixed_scoreboard_width);
1841  scoreboard_right = scoreboard_left + fixed_scoreboard_width;
1843  panel_size.x = fixed_scoreboard_width;
1844 
1846 
1848  vector pos = panel_pos;
1849  entity tm;
1850  string str;
1851  vector str_pos;
1852 
1853  vector sb_gameinfo_type_fontsize, sb_gameinfo_detail_fontsize;
1854 
1855  // Begin of Game Info Section
1856  sb_gameinfo_type_fontsize = hud_fontsize * 2.5;
1857  sb_gameinfo_detail_fontsize = hud_fontsize * 1.3;
1858 
1859  // Game Info: Game Type
1862  drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(str, true, sb_gameinfo_type_fontsize)), str, sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
1863  draw_endBoldFont();
1864 
1865  // Game Info: Game Detail
1866  float tl = STAT(TIMELIMIT);
1867  float fl = STAT(FRAGLIMIT);
1868  float ll = STAT(LEADLIMIT);
1869  float ll_and_fl = STAT(LEADLIMIT_AND_FRAGLIMIT);
1870  str = "";
1871  if(tl > 0)
1872  str = strcat(str, sprintf(_("^3%1.0f minutes"), tl));
1873  if(!gametype.m_hidelimits)
1874  {
1875  if(fl > 0)
1876  {
1877  if(tl > 0)
1878  str = strcat(str, "^7 / "); // delimiter
1879  if(teamplay)
1880  {
1881  str = strcat(str, sprintf(_("^5%s %s"), ScoreString(teamscores_flags(ts_primary), fl),
1882  (teamscores_label(ts_primary) == "score") ? CTX(_("SCO^points")) :
1883  (teamscores_label(ts_primary) == "fastest") ? "" :
1885  }
1886  else
1887  {
1888  str = strcat(str, sprintf(_("^5%s %s"), ScoreString(scores_flags(ps_primary), fl),
1889  (scores_label(ps_primary) == "score") ? CTX(_("SCO^points")) :
1890  (scores_label(ps_primary) == "fastest") ? "" :
1892  }
1893  }
1894  if(ll > 0)
1895  {
1896  if(tl > 0 || fl > 0)
1897  {
1898  // delimiter
1899  if (ll_and_fl && fl > 0)
1900  str = strcat(str, "^7 & ");
1901  else
1902  str = strcat(str, "^7 / ");
1903  }
1904 
1905  if(teamplay)
1906  {
1907  str = strcat(str, sprintf(_("^2+%s %s"), ScoreString(teamscores_flags(ts_primary), ll),
1908  (teamscores_label(ts_primary) == "score") ? CTX(_("SCO^points")) :
1909  (teamscores_label(ts_primary) == "fastest") ? "" :
1911  }
1912  else
1913  {
1914  str = strcat(str, sprintf(_("^2+%s %s"), ScoreString(scores_flags(ps_primary), ll),
1915  (scores_label(ps_primary) == "score") ? CTX(_("SCO^points")) :
1916  (scores_label(ps_primary) == "fastest") ? "" :
1918  }
1919  }
1920  }
1921 
1922  pos.y += sb_gameinfo_type_fontsize.y;
1923  drawcolorcodedstring(pos + '1 0 0' * (panel_size.x - stringwidth(str, true, sb_gameinfo_detail_fontsize)), str, sb_gameinfo_detail_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); // align right
1924  // map name
1925  str = sprintf(_("^7Map: ^2%s"), shortmapname);
1926  drawcolorcodedstring(pos, str, sb_gameinfo_detail_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); // align left
1927  // End of Game Info Section
1928 
1929  pos.y += sb_gameinfo_detail_fontsize.y + hud_fontsize.y * 0.3; // space between Game Info Section and score table
1930  if(panel.current_panel_bg != "0")
1931  pos.y += panel_bg_border;
1932 
1933  // Draw the scoreboard
1935  if(scale <= 0)
1936  scale = 0.25;
1937  vector bg_size = draw_getimagesize("gfx/scoreboard/scoreboard_bg") * scale;
1938 
1939  if(teamplay)
1940  {
1941  vector panel_bg_color_save = panel_bg_color;
1942  vector team_score_baseoffset;
1943  vector team_size_baseoffset;
1944  if (autocvar_hud_panel_scoreboard_team_size_position != 1) // team size not on left
1945  {
1946  // put team score to the left of scoreboard (and team size to the right)
1947  team_score_baseoffset = eY * hud_fontsize.y - eX * hud_fontsize.x * 0.5;
1948  team_size_baseoffset = eY * hud_fontsize.y + eX * hud_fontsize.x * 0.5;
1949  if(panel.current_panel_bg != "0")
1950  {
1951  team_score_baseoffset.x -= panel_bg_border;
1952  team_size_baseoffset.x += panel_bg_border;
1953  }
1954  }
1955  else
1956  {
1957  // put team score to the right of scoreboard (and team size to the left)
1958  team_score_baseoffset = eY * hud_fontsize.y + eX * hud_fontsize.x * 0.5;
1959  team_size_baseoffset = eY * hud_fontsize.y - eX * hud_fontsize.x * 0.5;
1960  if(panel.current_panel_bg != "0")
1961  {
1962  team_score_baseoffset.x += panel_bg_border;
1963  team_size_baseoffset.x -= panel_bg_border;
1964  }
1965  }
1966 
1967  int team_size_total = 0;
1968  if (autocvar_hud_panel_scoreboard_team_size_position != 0) // team size not off
1969  {
1970  // calculate team size total (sum of all team sizes)
1971  for(tm = teams.sort_next; tm; tm = tm.sort_next)
1972  if(tm.team != NUM_SPECTATOR)
1973  team_size_total += tm.team_size;
1974  }
1975 
1976  for(tm = teams.sort_next; tm; tm = tm.sort_next)
1977  {
1978  if(tm.team == NUM_SPECTATOR)
1979  continue;
1980  if(!tm.team)
1981  continue;
1982 
1984  vector rgb = Team_ColorRGB(tm.team);
1985  str = ftos(tm.(teamscores(ts_primary)));
1986  if (autocvar_hud_panel_scoreboard_team_size_position != 1) // team size not on left
1987  {
1988  // team score on the left (default)
1989  str_pos = pos + team_score_baseoffset - eX * stringwidth(str, false, hud_fontsize * 1.5);
1990  }
1991  else
1992  {
1993  // team score on the right
1994  str_pos = pos + team_score_baseoffset + eX * (panel_size.x + hud_fontsize.x * 1.5);
1995  }
1996  drawstring(str_pos, str, hud_fontsize * 1.5, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
1997 
1998  // team size (if set to show on the side)
1999  if (autocvar_hud_panel_scoreboard_team_size_position != 0) // team size not off
2000  {
2001  // calculate the starting position for the whole team size info string
2002  str = sprintf("%d/%d", tm.team_size, team_size_total);
2004  {
2005  // team size on the left
2006  str_pos = pos + team_size_baseoffset - eX * stringwidth(str, false, hud_fontsize * 1.5);
2007  }
2008  else
2009  {
2010  // team size on the right
2011  str_pos = pos + team_size_baseoffset + eX * (panel_size.x + hud_fontsize.x * 1.5);
2012  }
2013  str = sprintf("%d", tm.team_size);
2014  drawstring(str_pos, str, hud_fontsize * 1.5, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
2015  str_pos += eX * stringwidth(str, true, hud_fontsize * 1.5) + eY * hud_fontsize.y * .5;
2016  str = sprintf("/%d", team_size_total);
2017  drawstring(str_pos, str, hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
2018  }
2019 
2020 
2021  // secondary score, e.g. keyhunt
2022  if(ts_primary != ts_secondary)
2023  {
2024  str = ftos(tm.(teamscores(ts_secondary)));
2025  if (autocvar_hud_panel_scoreboard_team_size_position != 1) // team size not on left
2026  {
2027  // left
2028  str_pos = pos + team_score_baseoffset - vec2(stringwidth(str, false, hud_fontsize), hud_fontsize.y * -1.5);
2029  }
2030  else
2031  {
2032  // right
2033  str_pos = pos + team_score_baseoffset + vec2(panel_size.x + hud_fontsize.x * 1.5, hud_fontsize.y * 1.5);
2034  }
2035 
2036  drawstring(str_pos, str, hud_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
2037  }
2038  draw_endBoldFont();
2041  else if(panel_bg_color_team > 0)
2043  else
2044  panel_bg_color = rgb;
2045  pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size);
2046  }
2047  panel_bg_color = panel_bg_color_save;
2048  }
2049  else
2050  {
2051  for(tm = teams.sort_next; tm; tm = tm.sort_next)
2052  if(tm.team != NUM_SPECTATOR)
2053  break;
2054 
2055  // display it anyway
2056  pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size);
2057  }
2058 
2059  // draw scoreboard spectators before accuracy and item stats
2061  pos = Scoreboard_Spectators_Draw(pos);
2062  }
2063 
2064  // draw accuracy and item stats
2066  pos = Scoreboard_AccuracyStats_Draw(pos, panel_bg_color, bg_size);
2067  if (Scoreboard_ItemStats_WouldDraw(pos.y))
2068  pos = Scoreboard_ItemStats_Draw(pos, panel_bg_color, bg_size);
2069 
2070  // draw scoreboard spectators after accuracy and item stats and before rankings
2072  pos = Scoreboard_Spectators_Draw(pos);
2073  }
2074 
2075  if(MUTATOR_CALLHOOK(ShowRankings)) {
2076  string ranktitle = M_ARGV(0, string);
2078  if(race_speedaward) {
2079  drawcolorcodedstring(pos, sprintf(_("Speed award: %d%s ^7(%s^7)"), race_speedaward, unit, ColorTranslateRGB(race_speedaward_holder)), hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
2080  pos.y += 1.25 * hud_fontsize.y;
2081  }
2083  drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d%s ^7(%s^7)"), race_speedaward_alltimebest, unit, ColorTranslateRGB(race_speedaward_alltimebest_holder)), hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
2084  pos.y += 1.25 * hud_fontsize.y;
2085  }
2087  pos.y += 0.25 * hud_fontsize.y;
2088  pos = Scoreboard_Rankings_Draw(pos, ranktitle, playerslots[player_localnum], panel_bg_color, bg_size);
2089  }
2090  else
2091  rankings_cnt = 0;
2092 
2093  // draw scoreboard spectators after rankings
2095  pos = Scoreboard_Spectators_Draw(pos);
2096  }
2097 
2098  pos = Scoreboard_MapStats_Draw(pos, panel_bg_color, bg_size);
2099 
2100  // draw scoreboard spectators after mapstats
2102  pos = Scoreboard_Spectators_Draw(pos);
2103  }
2104 
2105 
2106  // print information about respawn status
2107  float respawn_time = STAT(RESPAWN_TIME);
2108  if(!intermission)
2109  if(respawn_time)
2110  {
2111  if(respawn_time < 0)
2112  {
2113  // a negative number means we are awaiting respawn, time value is still the same
2114  respawn_time *= -1; // remove mark now that we checked it
2115 
2116  if(respawn_time < time) // it happens for a few frames when server is respawning the player
2117  str = ""; // draw an empty string to not change suddenly scoreboard_bottom
2118  else
2119  str = sprintf(_("^1Respawning in ^3%s^1..."),
2122  :
2123  count_seconds(ceil(respawn_time - time))
2124  )
2125  );
2126  }
2127  else if(time < respawn_time)
2128  {
2129  str = sprintf(_("You are dead, wait ^3%s^7 before respawning"),
2132  :
2133  count_seconds(ceil(respawn_time - time))
2134  )
2135  );
2136  }
2137  else if(time >= respawn_time)
2138  str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
2139 
2140  pos.y += 1.2 * hud_fontsize.y;
2141  drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(str, true, hud_fontsize)), str, hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
2142  }
2143 
2144  pos.y += hud_fontsize.y;
2145  if (scoreboard_fade_alpha < 1)
2147  else if (pos.y != scoreboard_bottom)
2148  {
2149  if (pos.y > scoreboard_bottom)
2150  scoreboard_bottom = min(pos.y, scoreboard_bottom + frametime * 10 * (pos.y - scoreboard_top));
2151  else
2152  scoreboard_bottom = max(pos.y, scoreboard_bottom - frametime * 10 * (pos.y - scoreboard_top));
2153  }
2154 
2155  if (rankings_cnt)
2156  {
2157  if (scoreboard_fade_alpha == 1)
2158  {
2159  if (scoreboard_bottom > 0.95 * vid_conheight)
2160  rankings_rows = max(1, rankings_rows - 1);
2161  else if (scoreboard_bottom + 1.25 * hud_fontsize.y < 0.95 * vid_conheight)
2163  }
2165  }
2166 }
float autocvar_hud_panel_scoreboard_accuracy_showdelay_minpos
Definition: scoreboard.qc:91
vector WepSet
Definition: weapon.qh:11
float vid_conheight
void Scoreboard_InitScores()
Definition: scoreboard.qc:172
float autocvar_hud_panel_scoreboard_spectators_position
Definition: scoreboard.qc:85
noref string autocvar_hud_panel_scoreboard_bg_color_team
Definition: scoreboard.qc:66
#define IL_EACH(this, cond, body)
float panel_bg_border
Definition: hud.qh:169
#define MAX_SCORE
Definition: scores.qh:3
string shortmapname
Definition: main.qh:172
float scoreboard_left
Definition: scoreboard.qh:16
#define draw_endBoldFont()
Definition: draw.qh:5
int ts_secondary
Definition: hud.qh:117
float panel_fg_alpha
Definition: hud.qh:166
vector sbt_field_icon0_rgb
Definition: scoreboard.qc:622
float autocvar_hud_panel_scoreboard_table_bg_scale
Definition: scoreboard.qc:75
float current_player
Definition: hud.qh:182
const int NUM_SPECTATOR
Definition: teams.qh:23
float panel_bg_color_team
Definition: hud.qh:164
string string_null
Definition: nil.qh:9
float autocvar_hud_panel_scoreboard_itemstats_showdelay_minpos
Definition: scoreboard.qc:98
vector Scoreboard_Spectators_Draw(vector pos)
Definition: scoreboard.qc:1744
const int WEP_FIRST
Definition: all.qh:304
vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
Definition: scoreboard.qc:1212
PlayerScoreField sbt_field[MAX_SBT_FIELDS+1]
Definition: scoreboard.qc:43
const vector eY
Definition: vector.qh:45
float autocvar_hud_panel_weapons_aspect
Definition: weapons.qh:15
vector MapStats_DrawKeyValue(vector pos, string key, string value)
Definition: scoreboard.qc:1481
bool autocvar_hud_panel_scoreboard_spectators_aligned
Definition: scoreboard.qc:105
float sbt_fg_alpha
Definition: scoreboard.qc:53
const int SFL_SORT_PRIO_MASK
Definition: scores.qh:128
bool HUD_MinigameMenu_IsOpened()
bool autocvar__hud_configure
Definition: hud_config.qh:3
vector Scoreboard_MapStats_Draw(vector pos, vector rgb, vector bg_size)
Definition: scoreboard.qc:1493
bool Scoreboard_ItemStats_WouldDraw(float ypos)
Definition: scoreboard.qc:1709
float respawn_time
Definition: client.qh:325
#define IS_INCREASING(x)
Definition: scores.qh:130
vector Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
Definition: scoreboard.qc:1096
vector Scoreboard_Rankings_Draw(vector pos, string ranktitle, entity pl, vector rgb, vector bg_size)
Definition: scoreboard.qc:1565
#define stringwidth
Definition: csprogsdefs.qh:29
#define draw_beginBoldFont()
Definition: draw.qh:4
float panel_fade_alpha
Definition: hud.qh:410
vector Team_ColorRGB(int teamid)
Definition: teams.qh:76
float autocvar_hud_panel_scoreboard_table_fg_alpha
Definition: scoreboard.qc:76
float sbt_highlight_alpha_self
Definition: scoreboard.qc:57
float autocvar_hud_panel_scoreboard_fadeinspeed
Definition: scoreboard.qc:71
bool scoreboard_active
Definition: scoreboard.qh:9
bool autocvar_hud_panel_scoreboard_accuracy
Definition: scoreboard.qc:87
vector panel_size
Definition: hud.qh:160
string TranslateScoresLabel(string label)
Definition: scoreboard.qc:168
const int SFL_SORT_PRIO_SECONDARY
Scoring priority (NOTE: PRIMARY is used for fraglimit)
Definition: scores.qh:126
entity() spawn
bool hud_draw_maximized
Definition: hud.qh:68
bool autocvar_hud_panel_scoreboard_spectators_showping
Definition: scoreboard.qc:104
bool autocvar_hud_panel_scoreboard_itemstats
Definition: scoreboard.qc:93
bool scoreboard_showscores
Definition: scoreboard.qh:7
string Scoreboard_GetField(entity pl, PlayerScoreField field)
Definition: scoreboard.qc:645
#define getcommandkey(cmd_name, command)
Definition: main.qh:108
float sbt_fixcolumnwidth_iconlen
Definition: scoreboard.qc:763
vector sbt_field_icon1_rgb
Definition: scoreboard.qc:623
float intermission
Definition: csprogsdefs.qc:148
float autocvar_hud_panel_scoreboard_table_bg_alpha
Definition: scoreboard.qc:74
string MapInfo_Type_ToText(Gametype t)
Definition: mapinfo.qc:621
bool warmup_stage
Definition: main.qh:103
const int SFL_SORT_PRIO_PRIMARY
Definition: scores.qh:127
vector sbt_field_rgb
Definition: scoreboard.qc:618
bool autocvar_hud_panel_scoreboard_accuracy_doublerows
Definition: scoreboard.qc:88
string autocvar_hud_panel_scoreboard_playerid_prefix
Definition: scoreboard.qc:108
noref string autocvar_hud_panel_scoreboard_pos
Definition: scoreboard.qc:62
void HUD_Scale_Disable()
Definition: hud.qc:83
noref string autocvar_hud_panel_scoreboard_bg_color
Definition: scoreboard.qc:65
string textShortenToWidth(string theText, float maxWidth, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
Definition: util.qc:956
float autocvar_hud_panel_scoreboard_namesize
Definition: scoreboard.qc:83
void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, int pl_number)
Definition: scoreboard.qc:890
float autocvar_con_notify
Definition: chat.qh:9
string sbt_field_icon2
Definition: scoreboard.qc:621
float Scoreboard_CompareTeamScores(entity left, entity right)
Definition: scoreboard.qc:311
string sbt_field_icon0
Definition: scoreboard.qc:619
bool autocvar_hud_panel_scoreboard_dynamichud
Definition: scoreboard.qc:100
entity playerslots[255]
Definition: main.qh:70
void PrintScoresLabels()
Definition: scoreboard.qc:167
#define SFL_ZERO_IS_WORST
Definition: scores.qh:121
int rankings_rows
Definition: scoreboard.qc:1562
const int WEP_FLAG_HIDDEN
Definition: weapon.qh:200
#define itos(i)
Definition: int.qh:6
bool autocvar_cl_deathscoreboard
Definition: scoreboard.qh:4
float vid_conwidth
float autocvar_hud_panel_scoreboard_table_highlight_alpha_self
Definition: scoreboard.qc:80
const int MAX_SBT_FIELDS
Definition: scoreboard.qc:41
bool have_weapon_stats
Definition: scoreboard.qc:1676
float sbt_highlight_alpha
Definition: scoreboard.qc:56
string Label_getInfo(string label, int mode)
Definition: scoreboard.qc:113
#define TIME_ENCODED_TOSTRING(n)
Definition: util.qh:57
float scoreboard_showscores_force
Definition: racetimer.qh:40
int rankings_cnt
Definition: scoreboard.qc:1564
#define LOG_HELP(...)
Definition: log.qh:95
string sbt_field_title[MAX_SBT_FIELDS+1]
Definition: scoreboard.qc:45
float autocvar_hud_panel_scoreboard_respawntime_decimals
Definition: scoreboard.qc:73
int Scoreboard_CompareScore(int vl, int vr, int f)
Definition: scoreboard.qc:235
bool have_item_stats
Definition: scoreboard.qc:1708
float average_accuracy
Definition: scoreboard.qc:1211
string autocvar_hud_panel_scoreboard_playerid_suffix
Definition: scoreboard.qc:109
int autocvar_hud_panel_scoreboard_itemstats_filter_mask
Definition: scoreboard.qc:96
bool Scoreboard_AccuracyStats_WouldDraw(float ypos)
Definition: scoreboard.qc:1677
float grecordtime[RANKINGS_CNT]
Definition: main.qh:68
#define SB_EXTRA_SORTING_FIELDS
Definition: scoreboard.qc:170
#define strcpy(this, s)
Definition: string.qh:49
entity teams
Definition: main.qh:44
#define REGISTRY_COUNT(id)
Definition: registry.qh:18
#define teamscores_label(i)
Definition: scores.qh:147
ERASEABLE string count_ordinal(int interval)
Definition: counting.qh:66
void Scoreboard_Draw()
Definition: scoreboard.qc:1774
bool HUD_Radar_Clickable()
Definition: radar.qc:25
#define SCOREBOARD_DEFAULT_COLUMNS
Definition: scoreboard.qc:394
string hud_fontsize_str
Definition: scoreboard.qc:49
vector Scoreboard_ItemStats_Draw(vector pos, vector rgb, vector bg_size)
Definition: scoreboard.qc:1383
#define HUD_Panel_DrawBg()
Definition: hud.qh:54
string race_speedaward_alltimebest_holder
Definition: racetimer.qh:27
string grecordholder[RANKINGS_CNT]
Definition: main.qh:67
float autocvar_hud_panel_scoreboard_table_highlight_alpha
Definition: scoreboard.qc:79
void Scoreboard_Draw_Export(int fh)
Definition: scoreboard.qc:21
void HUD_Scale_Enable()
Definition: hud.qc:90
string Scoreboard_FixColumnWidth(int i, string str)
Definition: scoreboard.qc:766
string autocvar_hud_fontsize
Definition: scoreboard.qc:48
entity active_minigame
Definition: cl_minigames.qh:85
float autocvar_hud_panel_scoreboard_bg_teams_color_team
Definition: scoreboard.qc:82
#define drawpic_aspect_skin(pos, pic, sz, color, theAlpha, drawflag)
Definition: draw.qh:78
noref string autocvar_hud_panel_scoreboard_bg_alpha
Definition: scoreboard.qc:67
PlayerScoreField sb_extra_sorting_field[SB_EXTRA_SORTING_FIELDS]
Definition: scoreboard.qc:171
float RANKINGS_RECEIVED_CNT
Definition: main.qh:65
#define LOG_INFOF(...)
Definition: log.qh:71
bool sbt_highlight
Definition: scoreboard.qc:55
int autocvar_hud_panel_scoreboard_itemstats_filter
Definition: scoreboard.qc:95
vector sbt_field_icon2_rgb
Definition: scoreboard.qc:624
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
#define MAX_TEAMSCORE
Definition: scores.qh:142
vector HUD_GetFontsize(string cvarname)
Definition: hud.qc:111
float height
Definition: jumppads.qh:12
float Scoreboard_ComparePlayerScores(entity left, entity right)
Definition: scoreboard.qc:252
noref string autocvar_hud_panel_scoreboard_bg
Definition: scoreboard.qc:64
ERASEABLE string ColorTranslateRGB(string s)
Definition: string.qh:177
PlayerScoreField ps_secondary
Definition: hud.qh:116
float scoreboard_right
Definition: scoreboard.qh:17
float autocvar_hud_panel_scoreboard_table_highlight_alpha_eliminated
Definition: scoreboard.qc:81
float sbt_fixcolumnwidth_marginlen
Definition: scoreboard.qc:764
float panel_bg_alpha
Definition: hud.qh:167
bool ready_waiting
Definition: main.qh:112
#define NULL
Definition: post.qh:17
#define SORT_SWAP(a, b)
Swap two neighbours in a sortlist.
Definition: sortlist.qh:14
float frametime
Definition: csprogsdefs.qc:17
#define LOG_INFO(...)
Definition: log.qh:70
float isGametypeInFilter(Gametype gt, float tp, float ts, string pattern)
Definition: util.qc:972
const float DRAWFLAG_NORMAL
Definition: csprogsdefs.qc:317
string Scoreboard_AddPlayerId(string pl_name, entity pl)
Definition: scoreboard.qc:610
noref string autocvar_hud_panel_scoreboard_size
Definition: scoreboard.qc:63
entity gametype
Definition: main.qh:30
float autocvar_hud_panel_scoreboard_minwidth
Definition: scoreboard.qc:106
entity panel
Definition: hud.qh:144
noref string autocvar_hud_panel_scoreboard_bg_padding
Definition: scoreboard.qc:69
void Scoreboard_UpdatePlayerPos(entity player)
Definition: scoreboard.qc:298
#define TC(T, sym)
Definition: _all.inc:82
float sbt_highlight_alpha_eliminated
Definition: scoreboard.qc:58
#define strstrofs
Definition: dpextensions.qh:42
string sbt_field_icon1
Definition: scoreboard.qc:620
vector panel_pos
Definition: hud.qh:159
#define IS_DECREASING(x)
Definition: scores.qh:131
int autocvar_hud_panel_physics_speed_unit
Definition: physics.qh:17
float autocvar_hud_panel_scoreboard_team_size_position
Definition: scoreboard.qc:84
float race_speedaward
Definition: racetimer.qh:24
bool Scoreboard_WouldDraw()
Definition: scoreboard.qc:1187
float teamplay
Definition: progsdefs.qc:31
#define count_seconds_decs(time, decs)
Definition: counting.qh:55
#define M_ARGV(x, type)
Definition: events.qh:17
bool autocvar_hud_panel_scoreboard_accuracy_nocolors
Definition: scoreboard.qc:89
#define scores_flags(this)
Definition: scores.qh:140
vector Scoreboard_DrawHeader(vector pos, vector rgb, bool other_players)
Definition: scoreboard.qc:843
float scoreboard_time
Definition: scoreboard.qc:1675
float scale
Definition: projectile.qc:14
float sbt_field_size[MAX_SBT_FIELDS+1]
Definition: scoreboard.qc:44
float sbt_fixcolumnwidth_len
Definition: scoreboard.qc:762
const int WEP_TYPE_OTHER
Definition: weapon.qh:195
void Cmd_Scoreboard_Help()
Definition: scoreboard.qc:357
vector(float skel, float bonenum) _skel_get_boneabs_hidden
string Scoreboard_GetName(entity pl)
Definition: scoreboard.qc:625
bool autocvar_hud_panel_scoreboard_itemstats_doublerows
Definition: scoreboard.qc:94
int rankings_columns
Definition: scoreboard.qc:1563
#define count_seconds(time)
Definition: counting.qh:56
entity players
Definition: main.qh:43
vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity ignored_pl, entity pl, int pl_number)
Definition: scoreboard.qc:988
float sbt_bg_alpha
Definition: scoreboard.qc:52
float spectatee_status
Definition: main.qh:166
bool QuickMenu_IsOpened()
Definition: quickmenu.qc:244
int sbt_num_fields
Definition: scoreboard.qc:46
bool autocvar_hud_panel_scoreboard_others_showscore
Definition: scoreboard.qc:103
const int WEP_FLAG_SPECIALATTACK
Definition: weapon.qh:211
#define scores_label(this)
Definition: scores.qh:139
bool SetTeam(entity o, int Team)
Definition: main.qc:319
const vector eX
Definition: vector.qh:44
float autocvar_hud_panel_scoreboard_table_fg_alpha_self
Definition: scoreboard.qc:77
noref string autocvar_hud_panel_scoreboard_bg_border
Definition: scoreboard.qc:68
float sbt_fg_alpha_self
Definition: scoreboard.qc:54
void Scoreboard_initFieldSizes()
Definition: scoreboard.qc:834
float scoreboard_itemstats_fade_alpha
Definition: scoreboard.qh:12
string GetSpeedUnit(int speed_unit)
Definition: main.qc:1076
float scoreboard_acc_fade_alpha
Definition: scoreboard.qh:11
#define tokenizebyseparator
Definition: dpextensions.qh:21
float team_count
Definition: main.qh:45
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
#define vec2(...)
Definition: vector.qh:90
#define LABEL(id)
Definition: compiler.qh:36
PlayerScoreField ps_primary
Definition: hud.qh:116
float max_namesize
Definition: scoreboard.qc:50
vector hud_fontsize
Definition: main.qh:63
float autocvar_hud_panel_scoreboard_itemstats_showdelay
Definition: scoreboard.qc:97
float hud_configure_menu_open
Definition: hud_config.qh:21
#define strfree(this)
Definition: string.qh:56
void Scoreboard_UpdatePlayerTeams()
Definition: scoreboard.qc:210
ERASEABLE string CTX(string s)
Definition: i18n.qh:45
float autocvar_hud_panel_scoreboard_maxheight
Definition: scoreboard.qc:102
const int WEP_FLAG_MUTATORBLOCKED
Definition: weapon.qh:203
float autocvar_con_notifysize
Definition: chat.qh:10
#define teamscores_flags(i)
Definition: scores.qh:149
float scoreboard_bottom
Definition: scoreboard.qh:15
bool autocvar_hud_panel_scoreboard_playerid
Definition: scoreboard.qc:107
if(IS_DEAD(this))
Definition: impulse.qc:92
float autocvar_hud_panel_scoreboard_fadeoutspeed
Definition: scoreboard.qc:72
void Accuracy_LoadColors()
Definition: weapons.qc:55
bool autocvar_hud_panel_scoreboard_table_highlight
Definition: scoreboard.qc:78
void Scoreboard_UpdateTeamPos(entity Team)
Definition: scoreboard.qc:344
float time
Definition: csprogsdefs.qc:16
#define HUD_Write_Cvar(cvar)
Definition: hud_config.qh:38
vector Accuracy_GetColor(float accuracy)
Definition: weapons.qc:67
int ts_primary
Definition: hud.qh:117
string autocvar_scoreboard_columns
Definition: scoreboard.qh:5
void drawpic_tiled(vector pos, string pic, vector sz, vector area, vector color, float theAlpha, float drawflag)
Definition: draw.qc:24
#define FOREACH(list, cond, body)
Definition: iter.qh:19
float player_localnum
Definition: csprogsdefs.qc:20
float scoreboard_top
Definition: scoreboard.qh:14
int weapon_accuracy[REGISTRY_MAX(Weapons)]
Definition: hud.qh:110
entity PlayerScoreField
Definition: scores.qh:133
const int SFL_ALLOW_HIDE
Allow a column to be hidden (do not automatically add it even if it is a sorting key) ...
Definition: scores.qh:108
#define colormapPaletteColor(c, isPants)
Definition: color.qh:5
float scoreboard_fade_alpha
Definition: scoreboard.qh:10
float race_speedaward_alltimebest
Definition: racetimer.qh:26
void HUD_Panel_LoadCvars()
Definition: hud.qc:216
bool is_item_filtered(entity it)
Definition: scoreboard.qc:1356
float autocvar_hud_panel_scoreboard_accuracy_showdelay
Definition: scoreboard.qc:90
string race_speedaward_holder
Definition: racetimer.qh:25
void Cmd_Scoreboard_SetFields(int argc)
Definition: scoreboard.qc:412
float panel_bg_padding
Definition: hud.qh:171
vector panel_bg_color
Definition: hud.qh:162