Merge branch 'terencehill/spectate_player' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hud / panel / score.qc
1 #include "score.qh"
2
3 #include <client/autocvars.qh>
4 #include <client/defs.qh>
5 #include <client/miscfunctions.qh>
6 #include "scoreboard.qh"
7 #include <common/ent_cs.qh>
8 #include <common/mapinfo.qh>
9 #include <common/scores.qh>
10
11 // Score (#7)
12
13 void HUD_Score_Rankings(vector pos, vector mySize, entity me)
14 {
15         float score;
16         entity tm = NULL, pl;
17         int SCOREPANEL_MAX_ENTRIES = 6;
18         float SCOREPANEL_ASPECTRATIO = 2;
19         int entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize.y/mySize.x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
20         vector fontsize = '1 1 0' * (mySize.y/entries);
21
22         vector rgb, score_color;
23         rgb = '1 1 1';
24         score_color = '1 1 1';
25
26         float name_size = mySize.x*0.75;
27         float spacing_size = mySize.x*0.04;
28         const float highlight_alpha = 0.2;
29         int i = 0, first_pl = 0;
30         bool me_printed = false;
31         string s;
32         if (autocvar__hud_configure)
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                                 if (i == floor((entries - 2) / players_per_team) || (entries == 1 && i == 0))
42                                         HUD_Panel_DrawHighlight(pos + eX * score_size * i, vec2(score_size, fontsize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
43                                 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);
44                         }
45                         first_pl = 1;
46                         pos.y += fontsize.y;
47                 }
48                 score = 10 + SCOREPANEL_MAX_ENTRIES * 3;
49                 for (i=first_pl; i<entries; ++i)
50                 {
51                         //simulate my score is lower than all displayed players,
52                         //so that I don't appear at all showing pure rankings.
53                         //This is to better show the difference between the 2 ranking views
54                         if (i == entries-1 && autocvar_hud_panel_score_rankings == 1)
55                         {
56                                 rgb = '1 1 0';
57                                 drawfill(pos, vec2(mySize.x, fontsize.y), rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
58                                 s = entcs_GetName(player_localnum);
59                                 score = 7;
60                         }
61                         else
62                         {
63                                 s = sprintf(_("Player %d"), i + 1 - first_pl);
64                                 score -= 3;
65                         }
66
67                         if (team_count)
68                                 score_color = Team_ColorRGB(ColorByTeam(floor((i - first_pl) / players_per_team))) * 0.8;
69                         s = textShortenToWidth(s, name_size, fontsize, stringwidth_colors);
70                         drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
71                         drawstring(pos + eX * (name_size + spacing_size), ftos(score), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
72                         pos.y += fontsize.y;
73                 }
74                 return;
75         }
76
77         if (!scoreboard_fade_alpha) // the scoreboard too calls Scoreboard_UpdatePlayerTeams
78                 Scoreboard_UpdatePlayerTeams();
79         if (team_count)
80         {
81                 // show team scores in the first line
82                 float score_size = mySize.x / team_count;
83                 for(tm = teams.sort_next; tm; tm = tm.sort_next) {
84                         if(tm.team == NUM_SPECTATOR)
85                                 continue;
86                         if(!tm.team)
87                                 continue;
88
89                         if (tm.team == myteam)
90                                 drawfill(pos + eX * score_size * i, vec2(score_size, fontsize.y), '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
91                         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);
92                         ++i;
93                 }
94                 first_pl = 1;
95                 pos.y += fontsize.y;
96                 tm = teams.sort_next;
97         }
98         i = first_pl;
99
100         do
101         for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
102         {
103                 if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
104                         continue;
105
106                 if (i == entries-1 && !me_printed && pl != me)
107                 if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
108                 {
109                         for (pl = me.sort_next; pl; pl = pl.sort_next)
110                                 if (pl.team != NUM_SPECTATOR)
111                                         break;
112
113                         if (pl)
114                                 rgb = '1 1 0'; //not last but not among the leading players: yellow
115                         else
116                                 rgb = '1 0 0'; //last: red
117                         pl = me;
118                 }
119
120                 if (pl == me)
121                 {
122                         if (i == first_pl)
123                                 rgb = '0 1 0'; //first: green
124                         me_printed = true;
125                         drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
126                 }
127                 if (team_count)
128                         score_color = Team_ColorRGB(pl.team) * 0.8;
129                 s = textShortenToWidth(entcs_GetName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
130                 drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
131                 drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores(ps_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
132                 pos.y += fontsize.y;
133                 ++i;
134         }
135         while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
136 }
137
138 void HUD_Score()
139 {
140         if(!autocvar__hud_configure)
141         {
142                 if(!autocvar_hud_panel_score) return;
143                 if(spectatee_status == -1 && (ISGAMETYPE(RACE) || ISGAMETYPE(CTS))) return;
144         }
145
146         HUD_Panel_LoadCvars();
147         vector pos, mySize;
148         pos = panel_pos;
149         mySize = panel_size;
150
151         if (autocvar_hud_panel_score_dynamichud)
152                 HUD_Scale_Enable();
153         else
154                 HUD_Scale_Disable();
155         HUD_Panel_DrawBg();
156         if(panel_bg_padding)
157         {
158                 pos += '1 1 0' * panel_bg_padding;
159                 mySize -= '2 2 0' * panel_bg_padding;
160         }
161
162         float score, distribution = 0;
163         string sign;
164         vector distribution_color;
165         entity tm, pl, me;
166
167         me = playerslots[current_player];
168
169         if((scores_flags(ps_primary) & SFL_TIME) && !teamplay) { // race/cts record display on HUD
170                 string timer, distrtimer;
171
172                 pl = players.sort_next;
173                 if(pl == me)
174                         pl = pl.sort_next;
175                 if(scores_flags(ps_primary) & SFL_ZERO_IS_WORST)
176                         if(pl.scores(ps_primary) == 0)
177                                 pl = NULL;
178
179                 score = me.(scores(ps_primary));
180                 timer = TIME_ENCODED_TOSTRING(score);
181
182                 draw_beginBoldFont();
183                 if (pl && ((!(scores_flags(ps_primary) & SFL_ZERO_IS_WORST)) || score)) {
184                         // distribution display
185                         distribution = me.(scores(ps_primary)) - pl.(scores(ps_primary));
186
187                         distrtimer = ftos_decimals(fabs(distribution/(10 ** TIME_DECIMALS)), TIME_DECIMALS);
188
189                         if (distribution <= 0) {
190                                 distribution_color = '0 1 0';
191                                 sign = "-";
192                         }
193                         else {
194                                 distribution_color = '1 0 0';
195                                 sign = "+";
196                         }
197                         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);
198                 }
199                 // race record display
200                 if (distribution <= 0)
201                         HUD_Panel_DrawHighlight(pos, vec2(0.75 * mySize.x, mySize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
202                 drawstring_aspect(pos, timer, vec2(0.75 * mySize.x, mySize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
203                 draw_endBoldFont();
204         } else if (!teamplay) { // non-teamgames
205                 if ((spectatee_status == -1 && !autocvar__hud_configure) || autocvar_hud_panel_score_rankings)
206                 {
207                         HUD_Score_Rankings(pos, mySize, me);
208                         return;
209                 }
210                 // me vector := [team/connected frags id]
211                 pl = players.sort_next;
212                 if(pl == me)
213                         pl = pl.sort_next;
214
215                 if(autocvar__hud_configure)
216                         distribution = 42;
217                 else if(pl)
218                         distribution = me.(scores(ps_primary)) - pl.(scores(ps_primary));
219                 else
220                         distribution = 0;
221
222                 score = me.(scores(ps_primary));
223                 if(autocvar__hud_configure)
224                         score = 123;
225
226                 if(distribution >= 5)
227                         distribution_color = eY;
228                 else if(distribution >= 0)
229                         distribution_color = '1 1 1';
230                 else if(distribution >= -5)
231                         distribution_color = '1 1 0';
232                 else
233                         distribution_color = eX;
234
235                 string distribution_str;
236                 distribution_str = ftos(distribution);
237                 draw_beginBoldFont();
238                 if (distribution >= 0)
239                 {
240                         if (distribution > 0)
241                                 distribution_str = strcat("+", distribution_str);
242                         HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
243                 }
244                 drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
245                 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);
246                 draw_endBoldFont();
247         } else { // teamgames
248                 float row, column, rows = 0, columns = 0;
249                 vector offset = '0 0 0';
250                 vector score_pos, score_size; //for scores other than myteam
251                 if(autocvar_hud_panel_score_rankings)
252                 {
253                         HUD_Score_Rankings(pos, mySize, me);
254                         return;
255                 }
256                 if(spectatee_status == -1)
257                 {
258                         rows = HUD_GetRowCount(team_count, mySize, 3);
259                         columns = ceil(team_count/rows);
260                         score_size = vec2(mySize.x / columns, mySize.y / rows);
261
262                         float newSize;
263                         if(score_size.x/score_size.y > 3)
264                         {
265                                 newSize = 3 * score_size.y;
266                                 offset.x = score_size.x - newSize;
267                                 pos.x += offset.x/2;
268                                 score_size.x = newSize;
269                         }
270                         else
271                         {
272                                 newSize = 1/3 * score_size.x;
273                                 offset.y = score_size.y - newSize;
274                                 pos.y += offset.y/2;
275                                 score_size.y = newSize;
276                         }
277                 }
278                 else
279                         score_size = vec2(mySize.x / 4, mySize.y / 3);
280
281                 float max_fragcount;
282                 max_fragcount = -99;
283                 draw_beginBoldFont();
284                 row = column = 0;
285                 for(tm = teams.sort_next; tm; tm = tm.sort_next) {
286                         if(tm.team == NUM_SPECTATOR)
287                                 continue;
288                         if(!tm.team)
289                                 continue;
290
291                         score = tm.(teamscores(ts_primary));
292                         if(autocvar__hud_configure)
293                                 score = 123;
294
295                         if (score > max_fragcount)
296                                 max_fragcount = score;
297
298                         if (spectatee_status == -1)
299                         {
300                                 score_pos = pos + vec2(column * (score_size.x + offset.x), row * (score_size.y + offset.y));
301                                 if (max_fragcount == score)
302                                         HUD_Panel_DrawHighlight(score_pos, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
303                                 drawstring_aspect(score_pos, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
304                                 ++row;
305                                 if(row >= rows)
306                                 {
307                                         row = 0;
308                                         ++column;
309                                 }
310                         }
311                         else if(tm.team == myteam) {
312                                 if (max_fragcount == score)
313                                         HUD_Panel_DrawHighlight(pos, vec2(0.75 * mySize.x, mySize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
314                                 drawstring_aspect(pos, ftos(score), vec2(0.75 * mySize.x, mySize.y), Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
315                         } else {
316                                 if (max_fragcount == score)
317                                         HUD_Panel_DrawHighlight(pos + vec2(0.75 * mySize.x, (1/3) * rows * mySize.y), score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
318                                 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);
319                                 ++rows;
320                         }
321                 }
322                 draw_endBoldFont();
323         }
324 }