]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/gamemodes/gamemode/race/cl_race.qc
Phase out miscfunctions.qc from the server codebase, preferring more fitting location...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / gamemodes / gamemode / race / cl_race.qc
1 #include "cl_race.qh"
2
3 #include <common/mutators/base.qh>
4
5 // Race/CTS HUD mod icons
6 float crecordtime_prev; // last remembered crecordtime
7 float crecordtime_change_time; // time when crecordtime last changed
8 float srecordtime_prev; // last remembered srecordtime
9 float srecordtime_change_time; // time when srecordtime last changed
10
11 float race_status_time;
12 int race_status_prev;
13 string race_status_name_prev;
14
15 // Check if the given name already exist in race rankings? In that case, where? (otherwise return 0)
16 int race_CheckName(string net_name)
17 {
18         int rank = 0;
19         string zoned_name = strzone(strdecolorize(entcs_GetName(player_localnum)));
20         for (int i = RANKINGS_CNT - 1; i >= 0; --i)
21                 if (strdecolorize(grecordholder[i]) == zoned_name)
22                 {
23                         rank = i + 1;
24                         break;
25                 }
26         strfree(zoned_name);
27         return rank;
28 }
29
30 void race_showTime(string text, vector pos, vector timeText_ofs, float theTime, vector textSize, float f)
31 {
32         drawstring_aspect(pos, text, textSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
33         drawstring_aspect(pos + timeText_ofs, TIME_ENCODED_TOSTRING(theTime), textSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
34         if (f < 1) {
35                 drawstring_aspect_expanding(pos, text, textSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
36                 drawstring_aspect_expanding(pos + timeText_ofs, TIME_ENCODED_TOSTRING(theTime), textSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
37         }
38 }
39
40 void HUD_Mod_Race(vector pos, vector mySize)
41 {
42         entity me = playerslots[player_localnum];
43         float score = me.(scores(ps_primary));
44
45         if(!(scores_flags(ps_primary) & SFL_TIME) || teamplay) // race/cts record display on HUD
46         {
47                 mod_active = 0; // hide it in this case!
48                 return; // no records in the actual race
49         }
50
51         mod_active = 1;
52
53         // clientside personal record
54         string rr;
55         if(ISGAMETYPE(CTS))
56                 rr = CTS_RECORD;
57         else
58                 rr = RACE_RECORD;
59         float t = stof(db_get(ClientProgsDB, strcat(shortmapname, rr, "time")));
60
61         if(score && (score < t || !t)) {
62                 db_put(ClientProgsDB, strcat(shortmapname, rr, "time"), ftos(score));
63                 if(autocvar_cl_autodemo_delete_keeprecords)
64                 {
65                         float f = autocvar_cl_autodemo_delete;
66                         f &= ~1;
67                         cvar_set("cl_autodemo_delete", ftos(f)); // don't delete demo with new record!
68                 }
69         }
70
71         if(t != crecordtime_prev) {
72                 crecordtime_prev = t;
73                 crecordtime_change_time = time;
74         }
75
76         vector textPos, medalPos;
77         float squareSize;
78         if(mySize.x > mySize.y) {
79                 // text on left side
80                 squareSize = min(mySize.y, mySize.x/2);
81                 vector ofs = vec2(0.5 * max(0, mySize.x/2 - squareSize), 0.5 * (mySize.y - squareSize));
82                 textPos = pos + ofs;
83                 ofs.x += 0.5 * mySize.x;
84                 medalPos = pos + ofs;
85         } else {
86                 // text on top
87                 squareSize = min(mySize.x, mySize.y/2);
88                 vector ofs = vec2(0.5 * (mySize.x - squareSize), 0.5 * max(0, mySize.y/2 - squareSize));
89                 textPos = pos + ofs;
90                 ofs.y += 0.5 * mySize.y;
91                 medalPos = pos + ofs;
92         }
93         vector textSize = vec2(squareSize, 0.25 * squareSize);
94
95         race_showTime(_("Personal best"), textPos, eY * 0.25 * squareSize, t, textSize, time - crecordtime_change_time);
96
97         // server record
98         t = race_server_record;
99         if(t != srecordtime_prev) {
100                 srecordtime_prev = t;
101                 srecordtime_change_time = time;
102         }
103
104         textPos += eY * 0.5 * squareSize;
105         race_showTime(_("Server best"), textPos, eY * 0.25 * squareSize, t, textSize, time - srecordtime_change_time);
106
107         if (race_status != race_status_prev || race_status_name != race_status_name_prev) {
108                 race_status_time = time + 5;
109                 race_status_prev = race_status;
110                 strcpy(race_status_name_prev, race_status_name);
111         }
112
113         // race "awards"
114         float a = bound(0, race_status_time - time, 1);
115         string s = textShortenToWidth(ColorTranslateRGB(race_status_name), squareSize, '1 1 0' * 0.1 * squareSize, stringwidth_colors);
116
117         float rank = 0;
118         if(race_status > 0)
119                 rank = race_CheckName(race_status_name);
120         string rankname = count_ordinal(rank);
121         vector namepos = medalPos + '0 0.8 0' * squareSize;
122         vector rankpos = medalPos + '0 0.15 0' * squareSize;
123
124         if(race_status == 0)
125                 drawpic_aspect_skin(medalPos, "race_newfail", '1 1 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
126         else if(race_status == 1) {
127                 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);
128                 drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
129                 drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
130         } else if(race_status == 2) {
131                 if(strdecolorize(race_status_name) == strdecolorize(entcs_GetName(player_localnum)) || !race_myrank || race_myrank < rank)
132                         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);
133                 else
134                         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);
135                 drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
136                 drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
137         } else if(race_status == 3) {
138                 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);
139                 drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
140                 drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
141         }
142
143         if (race_status_time - time <= 0) {
144                 race_status_prev = -1;
145                 race_status = -1;
146                 strfree(race_status_name);
147                 strfree(race_status_name_prev);
148         }
149 }
150
151 REGISTER_MUTATOR(cl_race, true);
152
153 MUTATOR_HOOKFUNCTION(cl_race, HUD_Physics_showoptional)
154 {
155         return ISGAMETYPE(RACE); // show the optional physics panel
156 }
157
158 MUTATOR_HOOKFUNCTION(cl_race, HUD_Score_show)
159 {
160         return spectatee_status == -1 && ISGAMETYPE(RACE); // hide the score panel while observing
161 }
162
163 MUTATOR_HOOKFUNCTION(cl_race, ShowRankings)
164 {
165         if(ISGAMETYPE(RACE))
166         {
167                 M_ARGV(0, string) = _("Rankings");
168                 return true;
169         }
170 }
171
172 MUTATOR_HOOKFUNCTION(cl_race, DrawScoreboardAccuracy)
173 {
174         return ISGAMETYPE(RACE); // accuracy is not a factor in this gamemode
175 }
176
177 MUTATOR_HOOKFUNCTION(cl_race, ShowRaceTimer)
178 {
179         return ISGAMETYPE(RACE); // show the race timer panel
180 }
181
182 MUTATOR_HOOKFUNCTION(cl_race, TeamRadar_Draw)
183 {
184         return ISGAMETYPE(RACE); // show all competitors in a race
185 }