Merge branch 'terencehill/spectate_player' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hud / panel / modicons.qc
1 #include "modicons.qh"
2
3 #include <client/miscfunctions.qh>
4 #include <client/autocvars.qh>
5 #include <common/mapinfo.qh>
6 #include <common/ent_cs.qh>
7 #include <common/scores.qh>
8 #include <common/gamemodes/_mod.qh>
9
10 // Mod icons (#10)
11
12 void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
13 {
14         TC(int, layout); TC(int, i);
15         int stat = -1;
16         string pic = "";
17         vector color = '0 0 0';
18         switch(i)
19         {
20                 case 0: stat = STAT(REDALIVE); pic = "player_red"; color = '1 0 0'; break;
21                 case 1: stat = STAT(BLUEALIVE); pic = "player_blue"; color = '0 0 1'; break;
22                 case 2: stat = STAT(YELLOWALIVE); pic = "player_yellow"; color = '1 1 0'; break;
23                 default:
24                 case 3: stat = STAT(PINKALIVE); pic = "player_pink"; color = '1 0 1'; break;
25         }
26
27         if(mySize.x/mySize.y > aspect_ratio)
28         {
29                 i = aspect_ratio * mySize.y;
30                 myPos.x = myPos.x + (mySize.x - i) / 2;
31                 mySize.x = i;
32         }
33         else
34         {
35                 i = 1/aspect_ratio * mySize.x;
36                 myPos.y = myPos.y + (mySize.y - i) / 2;
37                 mySize.y = i;
38         }
39
40         if(layout)
41         {
42                 drawpic_aspect_skin(myPos, pic, vec2(0.5 * mySize.x, mySize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
43                 drawstring_aspect(myPos + eX * 0.5 * mySize.x, ftos(stat), vec2(0.5 * mySize.x, mySize.y), color, panel_fg_alpha, DRAWFLAG_NORMAL);
44         }
45         else
46                 drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
47 }
48
49 // Clan Arena and Freeze Tag HUD modicons
50 void HUD_Mod_CA(vector myPos, vector mySize)
51 {
52         mod_active = 1; // required in each mod function that always shows something
53
54         int layout;
55         if(ISGAMETYPE(CA))
56                 layout = autocvar_hud_panel_modicons_ca_layout;
57         else //if(ISGAMETYPE(FREEZETAG))
58                 layout = autocvar_hud_panel_modicons_freezetag_layout;
59         int rows, columns;
60         float aspect_ratio;
61         aspect_ratio = (layout) ? 2 : 1;
62         rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
63         columns = ceil(team_count/rows);
64
65         int i;
66         float row = 0, column = 0;
67         vector pos = '0 0 0', itemSize;
68         itemSize = vec2(mySize.x / columns, mySize.y / rows);
69         for(i=0; i<team_count; ++i)
70         {
71                 pos.x = myPos.x + column * itemSize.x;
72                 pos.y = myPos.y + row * itemSize.y;
73
74                 DrawCAItem(pos, itemSize, aspect_ratio, layout, i);
75
76                 ++row;
77                 if(row >= rows)
78                 {
79                         row = 0;
80                         ++column;
81                 }
82         }
83 }
84
85 // Race/CTS HUD mod icons
86 float crecordtime_prev; // last remembered crecordtime
87 float crecordtime_change_time; // time when crecordtime last changed
88 float srecordtime_prev; // last remembered srecordtime
89 float srecordtime_change_time; // time when srecordtime last changed
90
91 float race_status_time;
92 int race_status_prev;
93 string race_status_name_prev;
94
95 // Check if the given name already exist in race rankings? In that case, where? (otherwise return 0)
96 int race_CheckName(string net_name)
97 {
98         int rank = 0;
99         string zoned_name = strzone(strdecolorize(entcs_GetName(player_localnum)));
100         for (int i = RANKINGS_CNT - 1; i >= 0; --i)
101                 if (strdecolorize(grecordholder[i]) == zoned_name)
102                 {
103                         rank = i + 1;
104                         break;
105                 }
106         strfree(zoned_name);
107         return rank;
108 }
109
110 void race_showTime(string text, vector pos, vector timeText_ofs, float theTime, vector textSize, float f)
111 {
112         drawstring_aspect(pos, text, textSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
113         drawstring_aspect(pos + timeText_ofs, TIME_ENCODED_TOSTRING(theTime), textSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
114         if (f < 1) {
115                 drawstring_aspect_expanding(pos, text, textSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
116                 drawstring_aspect_expanding(pos + timeText_ofs, TIME_ENCODED_TOSTRING(theTime), textSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
117         }
118 }
119
120 void HUD_Mod_Race(vector pos, vector mySize)
121 {
122         entity me = playerslots[player_localnum];
123         float score = me.(scores(ps_primary));
124
125         if(!(scores_flags(ps_primary) & SFL_TIME) || teamplay) // race/cts record display on HUD
126         {
127                 mod_active = 0; // hide it in this case!
128                 return; // no records in the actual race
129         }
130
131         mod_active = 1;
132
133         // clientside personal record
134         string rr;
135         if(ISGAMETYPE(CTS))
136                 rr = CTS_RECORD;
137         else
138                 rr = RACE_RECORD;
139         float t = stof(db_get(ClientProgsDB, strcat(shortmapname, rr, "time")));
140
141         if(score && (score < t || !t)) {
142                 db_put(ClientProgsDB, strcat(shortmapname, rr, "time"), ftos(score));
143                 if(autocvar_cl_autodemo_delete_keeprecords)
144                 {
145                         float f = autocvar_cl_autodemo_delete;
146                         f &= ~1;
147                         cvar_set("cl_autodemo_delete", ftos(f)); // don't delete demo with new record!
148                 }
149         }
150
151         if(t != crecordtime_prev) {
152                 crecordtime_prev = t;
153                 crecordtime_change_time = time;
154         }
155
156         vector textPos, medalPos;
157         float squareSize;
158         if(mySize.x > mySize.y) {
159                 // text on left side
160                 squareSize = min(mySize.y, mySize.x/2);
161                 vector ofs = vec2(0.5 * max(0, mySize.x/2 - squareSize), 0.5 * (mySize.y - squareSize));
162                 textPos = pos + ofs;
163                 ofs.x += 0.5 * mySize.x;
164                 medalPos = pos + ofs;
165         } else {
166                 // text on top
167                 squareSize = min(mySize.x, mySize.y/2);
168                 vector ofs = vec2(0.5 * (mySize.x - squareSize), 0.5 * max(0, mySize.y/2 - squareSize));
169                 textPos = pos + ofs;
170                 ofs.y += 0.5 * mySize.y;
171                 medalPos = pos + ofs;
172         }
173         vector textSize = vec2(squareSize, 0.25 * squareSize);
174
175         race_showTime(_("Personal best"), textPos, eY * 0.25 * squareSize, t, textSize, time - crecordtime_change_time);
176
177         // server record
178         t = race_server_record;
179         if(t != srecordtime_prev) {
180                 srecordtime_prev = t;
181                 srecordtime_change_time = time;
182         }
183
184         textPos += eY * 0.5 * squareSize;
185         race_showTime(_("Server best"), textPos, eY * 0.25 * squareSize, t, textSize, time - srecordtime_change_time);
186
187         if (race_status != race_status_prev || race_status_name != race_status_name_prev) {
188                 race_status_time = time + 5;
189                 race_status_prev = race_status;
190                 strcpy(race_status_name_prev, race_status_name);
191         }
192
193         // race "awards"
194         float a = bound(0, race_status_time - time, 1);
195         string s = textShortenToWidth(ColorTranslateRGB(race_status_name), squareSize, '1 1 0' * 0.1 * squareSize, stringwidth_colors);
196
197         float rank = 0;
198         if(race_status > 0)
199                 rank = race_CheckName(race_status_name);
200         string rankname = count_ordinal(rank);
201         vector namepos = medalPos + '0 0.8 0' * squareSize;
202         vector rankpos = medalPos + '0 0.15 0' * squareSize;
203
204         if(race_status == 0)
205                 drawpic_aspect_skin(medalPos, "race_newfail", '1 1 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
206         else if(race_status == 1) {
207                 drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newtime", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
208                 drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
209                 drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
210         } else if(race_status == 2) {
211                 if(strdecolorize(race_status_name) == strdecolorize(entcs_GetName(player_localnum)) || !race_myrank || race_myrank < rank)
212                         drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankgreen", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
213                 else
214                         drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankyellow", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
215                 drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
216                 drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
217         } else if(race_status == 3) {
218                 drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrecordserver", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
219                 drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
220                 drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
221         }
222
223         if (race_status_time - time <= 0) {
224                 race_status_prev = -1;
225                 race_status = -1;
226                 strfree(race_status_name);
227                 strfree(race_status_name_prev);
228         }
229 }
230
231 void HUD_ModIcons_SetFunc()
232 {
233         HUD_ModIcons_GameType = gametype.m_modicons;
234 }
235
236 float mod_alpha;
237
238 void HUD_ModIcons()
239 {
240         if(!autocvar__hud_configure)
241         {
242                 if(!autocvar_hud_panel_modicons) return;
243                 if(!HUD_ModIcons_GameType) return;
244         }
245
246         if(mod_active || autocvar__hud_configure)
247                 mod_alpha = min(mod_alpha + frametime * 2, 1);
248         else
249                 mod_alpha = max(mod_alpha - frametime * 2, 0);
250
251         //if(mod_alpha <= 0)
252         //      return;
253         panel_fade_alpha *= mod_alpha;
254         HUD_Panel_LoadCvars();
255
256         draw_beginBoldFont();
257
258         if (autocvar_hud_panel_modicons_dynamichud)
259                 HUD_Scale_Enable();
260         else
261                 HUD_Scale_Disable();
262
263         HUD_Panel_DrawBg();
264
265         if(panel_bg_padding)
266         {
267                 panel_pos += '1 1 0' * panel_bg_padding;
268                 panel_size -= '2 2 0' * panel_bg_padding;
269         }
270
271         if(autocvar__hud_configure)
272                 HUD_Mod_CTF(panel_pos, panel_size);
273         else
274                 HUD_ModIcons_GameType(panel_pos, panel_size);
275
276         draw_endBoldFont();
277 }