Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
score.qc
Go to the documentation of this file.
1#include "score.qh"
2
3#include <client/draw.qh>
5#include <common/ent_cs.qh>
6#include <common/scores.qh>
7
8// Score (#7)
9
10void HUD_Score_Export(int fh)
11{
12 // allow saving cvars that aesthetically change the panel into hud skin files
13 HUD_Write_Cvar("hud_panel_score_rankings");
14}
15
17{
18 float score;
19 int SCOREPANEL_MAX_ENTRIES = 6;
20 float SCOREPANEL_ASPECTRATIO = 2;
21 int entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize.y / mySize.x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
22 vector fontsize = '1 1 0' * (mySize.y / entries);
23
24 vector rgb = '1 1 1';
25 vector score_color = '1 1 1';
26
27 float name_size = mySize.x * 0.75;
28 float spacing_size = mySize.x * 0.04;
29 const float highlight_alpha = 0.2;
30 int i = 0, first_pl = 0;
31 string s;
33 {
34 float players_per_team = 0;
35 if (team_count)
36 {
37 // show team scores in the first line
38 float score_size = mySize.x / team_count;
39 players_per_team = max(2, ceil((entries - 1) / team_count));
40 for (i = 0; i < team_count; ++i)
41 {
42 if (i == floor((entries - 2) / players_per_team) || (entries == 1 && i == 0))
43 HUD_Panel_DrawHighlight(pos + eX * score_size * i, vec2(score_size, fontsize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
44 drawstring_aspect(pos + eX * score_size * i, ftos(175 - 23 * i), vec2(score_size, fontsize.y), Team_ColorRGB(ColorByTeam(i)) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
45 }
46 first_pl = 1;
47 pos.y += fontsize.y;
48 }
49 score = 10 + SCOREPANEL_MAX_ENTRIES * 3;
50 for (i = first_pl; i < entries; ++i)
51 {
52 //simulate my score is lower than all displayed players,
53 //so that I don't appear at all showing pure rankings.
54 //This is to better show the difference between the 2 ranking views
55 if (i == entries - 1 && autocvar_hud_panel_score_rankings == 1)
56 {
57 rgb = '1 1 0';
58 drawfill(pos, vec2(mySize.x, fontsize.y), rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
60 score = 7;
61 }
62 else
63 {
64 s = sprintf(_("Player %d"), i + 1 - first_pl);
65 score -= 3;
66 }
67
68 if (team_count)
69 score_color = Team_ColorRGB(ColorByTeam(floor((i - first_pl) / players_per_team))) * 0.8;
70 s = textShortenToWidth(s, name_size, fontsize, stringwidth_colors);
71 drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
72 drawstring(pos + eX * (name_size + spacing_size), ftos(score), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
73 pos.y += fontsize.y;
74 }
75 return;
76 }
77
78 entity tm = NULL, pl;
79 bool me_printed = false;
80
82 if (team_count)
83 {
84 // show team scores in the first line
85 float score_size = mySize.x / team_count;
86 for (tm = teams.sort_next; tm; tm = tm.sort_next)
87 {
88 if (!tm.team || tm.team == NUM_SPECTATOR)
89 continue;
90
91 if (tm.team == myteam)
92 drawfill(pos + eX * score_size * i, vec2(score_size, fontsize.y), '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
93 drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores(ts_primary))), vec2(score_size, fontsize.y), Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
94 ++i;
95 }
96 first_pl = 1;
97 pos.y += fontsize.y;
98 tm = teams.sort_next;
99 }
100 i = first_pl;
101
102 do
103 for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
104 {
105 if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
106 continue;
107
108 if (i == entries - 1 && !me_printed && pl != me
110 {
111 for (pl = me.sort_next; pl; pl = pl.sort_next)
112 if (pl.team != NUM_SPECTATOR)
113 break;
114
115 if (pl)
116 rgb = '1 1 0'; //not last but not among the leading players: yellow
117 else
118 rgb = '1 0 0'; //last: red
119 pl = me;
120 }
121
122 if (pl == me)
123 {
124 if (i == first_pl)
125 rgb = '0 1 0'; //first: green
126 me_printed = true;
127 drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
128 }
129 if (team_count)
130 score_color = Team_ColorRGB(pl.team) * 0.8;
131 s = textShortenToWidth(entcs_GetName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
132 drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
133 drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores(ps_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
134 pos.y += fontsize.y;
135 ++i;
136 }
137 while (i < entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
138}
139
141{
143 {
145 return;
146 if (MUTATOR_CALLHOOK(HUD_Score_show))
147 return;
148 }
149
151 vector pos = panel_pos;
152 vector mySize = panel_size;
153
156 else
160 {
161 pos += '1 1 0' * panel_bg_padding;
162 mySize -= '2 2 0' * panel_bg_padding;
163 }
164
165 float score, distribution = 0;
166 vector distribution_color;
167 entity pl;
169
170 if ((scores_flags(ps_primary) & SFL_TIME) && !teamplay) // race/cts record display on HUD
171 {
172 pl = players.sort_next;
173 if (pl == me)
174 pl = pl.sort_next;
176 if (pl.scores(ps_primary) == 0)
177 pl = NULL;
178
179 score = me.(scores(ps_primary));
180 string timer = TIME_ENCODED_TOSTRING(score, false);
181
183 if (pl && ((!(scores_flags(ps_primary) & SFL_ZERO_IS_WORST)) || score))
184 {
185 // distribution display
186 distribution = me.(scores(ps_primary)) - pl.(scores(ps_primary));
187
188 string distrtimer = ftos_decimals(fabs(distribution / (10 ** TIME_DECIMALS)), TIME_DECIMALS);
189
190 string sign;
191 if (distribution <= 0)
192 {
193 distribution_color = '0 1 0';
194 sign = "-";
195 }
196 else
197 {
198 distribution_color = '1 0 0';
199 sign = "+";
200 }
201 drawstring_aspect(pos + eX * 0.75 * mySize.x, strcat(sign, distrtimer), vec2(0.25 * mySize.x, (1/3) * mySize.y), distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
202 }
203 // race record display
204 if (distribution <= 0)
205 HUD_Panel_DrawHighlight(pos, vec2(0.75 * mySize.x, mySize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
206 drawstring_aspect(pos, timer, vec2(0.75 * mySize.x, mySize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
208 }
209 else if (!teamplay) // non-teamgames
210 {
212 {
213 HUD_Score_Rankings(pos, mySize, me);
214 return;
215 }
216 // me vector := [team/connected frags id]
217 pl = players.sort_next;
218 if (pl == me)
219 pl = pl.sort_next;
220
222 distribution = 42;
223 else if (pl)
224 distribution = me.(scores(ps_primary)) - pl.(scores(ps_primary));
225 else
226 distribution = 0;
227
228 score = me.(scores(ps_primary));
230 score = 123;
231
232 if (distribution >= 5)
233 distribution_color = eY;
234 else if (distribution >= 0)
235 distribution_color = '1 1 1';
236 else if (distribution >= -5)
237 distribution_color = '1 1 0';
238 else
239 distribution_color = eX;
240
241 string distribution_str;
242 distribution_str = ftos(distribution);
244 if (distribution >= 0)
245 {
246 if (distribution > 0)
247 distribution_str = strcat("+", distribution_str);
248 HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
249 }
250 drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
251 drawstring_aspect(pos + eX * 0.75 * mySize.x, distribution_str, vec2(0.25 * mySize.x, (1/3) * mySize.y), distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
253 }
254 else // teamgames
255 {
257 {
258 HUD_Score_Rankings(pos, mySize, me);
259 return;
260 }
261 float rows = 0, columns = 0;
262 vector offset = '0 0 0';
263 vector score_size; // for scores other than myteam
264 if (spectatee_status == -1)
265 {
266 rows = HUD_GetRowCount(team_count, mySize, 3);
267 columns = ceil(team_count / rows);
268 score_size = vec2(mySize.x / columns, mySize.y / rows);
269
270 float newSize;
271 if (score_size.x / score_size.y > 3)
272 {
273 newSize = 3 * score_size.y;
274 offset.x = score_size.x - newSize;
275 pos.x += offset.x * 0.5;
276 score_size.x = newSize;
277 }
278 else
279 {
280 newSize = 1/3 * score_size.x;
281 offset.y = score_size.y - newSize;
282 pos.y += offset.y * 0.5;
283 score_size.y = newSize;
284 }
285 }
286 else
287 score_size = vec2(mySize.x / 4, mySize.y / 3);
288
289 float max_fragcount = -99;
290 float row = 0, column = 0;
292 for (entity tm = teams.sort_next; tm; tm = tm.sort_next)
293 {
294 if (!tm.team || tm.team == NUM_SPECTATOR)
295 continue;
296
297 score = tm.(teamscores(ts_primary));
299 score = 123;
300
301 if (score > max_fragcount)
302 max_fragcount = score;
303
304 if (spectatee_status == -1)
305 {
306 vector score_pos = pos + vec2(column * (score_size.x + offset.x), row * (score_size.y + offset.y));
307 if (max_fragcount == score)
308 HUD_Panel_DrawHighlight(score_pos, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
309 drawstring_aspect(score_pos, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
310 ++row;
311 if (row >= rows)
312 {
313 row = 0;
314 ++column;
315 }
316 }
317 else if (tm.team == myteam)
318 {
319 if (max_fragcount == score)
320 HUD_Panel_DrawHighlight(pos, vec2(0.75 * mySize.x, mySize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
321 drawstring_aspect(pos, ftos(score), vec2(0.75 * mySize.x, mySize.y), Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
322 }
323 else
324 {
325 if (max_fragcount == score)
326 HUD_Panel_DrawHighlight(pos + vec2(0.75 * mySize.x, (1/3) * rows * mySize.y), score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
327 drawstring_aspect(pos + vec2(0.75 * mySize.x, (1/3) * rows * mySize.y), ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
328 ++rows;
329 }
330 }
332 }
333}
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
void drawstring_aspect(vector pos, string text, vector sz, vector color, float theAlpha, float drawflag)
Definition draw.qc:110
#define drawcolorcodedstring(position, text, scale, alpha, flag)
Definition draw.qh:30
#define drawstring(position, text, scale, rgb, alpha, flag)
Definition draw.qh:27
#define draw_beginBoldFont()
Definition draw.qh:4
#define drawfill(position, size, rgb, alpha, flag)
Definition draw.qh:36
#define draw_endBoldFont()
Definition draw.qh:5
entity playerslots[255]
Definition main.qh:84
entity players
Definition main.qh:57
int spectatee_status
the -1 disables HUD panels before CSQC receives necessary data
Definition main.qh:197
float team_count
Definition main.qh:59
entity teams
Definition main.qh:58
const int SFL_TIME
Display as mm:ss.s, value is stored as 10ths of a second (AND 0 is the worst possible value!...
Definition scores.qh:122
#define scores_flags(this)
Definition scores.qh:147
#define SFL_ZERO_IS_WORST
Definition scores.qh:127
string textShortenToWidth(string theText, float maxWidth, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
Definition util.qc:1071
#define TIME_ENCODED_TOSTRING(n, compact)
Definition util.qh:96
const int TIME_DECIMALS
Definition util.qh:94
const float DRAWFLAG_NORMAL
float player_localnum
#define stringwidth
string entcs_GetName(int i)
Definition ent_cs.qh:151
void HUD_Panel_LoadCvars()
Definition hud.qc:215
float HUD_GetRowCount(int item_count, vector size, float item_aspect)
Definition hud.qc:165
void HUD_Scale_Enable()
Definition hud.qc:91
void HUD_Panel_DrawHighlight(vector pos, vector mySize, vector color, float theAlpha, int drawflag)
Definition hud.qc:374
void HUD_Scale_Disable()
Definition hud.qc:84
vector panel_size
Definition hud.qh:163
float panel_fg_alpha
Definition hud.qh:169
float panel_bg_padding
Definition hud.qh:174
#define HUD_Panel_DrawBg()
Definition hud.qh:55
float current_player
Definition hud.qh:185
PlayerScoreField ps_primary
Definition hud.qh:117
float timer
Definition hud.qh:125
vector panel_pos
Definition hud.qh:162
int ts_primary
Definition hud.qh:118
#define HUD_Write_Cvar(cvar)
Definition hud_config.qh:40
bool autocvar__hud_configure
Definition hud_config.qh:3
float ceil(float f)
float bound(float min, float value, float max)
string ftos(float f)
float fabs(float f)
float floor(float f)
float max(float f,...)
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
#define NULL
Definition post.qh:14
void HUD_Score_Rankings(vector pos, vector mySize, entity me)
Definition score.qc:16
void HUD_Score_Export(int fh)
Definition score.qc:10
void HUD_Score()
Definition score.qc:140
bool autocvar_hud_panel_score_dynamichud
Definition score.qh:5
bool autocvar_hud_panel_score
Definition score.qh:4
bool autocvar_hud_panel_score_rankings
Definition score.qh:6
void Scoreboard_UpdatePlayerTeams()
vector
Definition self.qh:92
ERASEABLE string ftos_decimals(float number, int decimals)
converts a number to a string with the indicated number of decimals
Definition string.qh:469
float stringwidth_colors(string s, vector theSize)
Definition string.qh:30
#define ColorByTeam(number)
Definition teams.qh:219
int myteam
Definition teams.qh:60
const int NUM_SPECTATOR
Definition teams.qh:23
vector Team_ColorRGB(int teamid)
Definition teams.qh:76
bool teamplay
Definition teams.qh:59
const vector eY
Definition vector.qh:45
const vector eX
Definition vector.qh:44
#define vec2(...)
Definition vector.qh:90