]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/race.qc
fix all-time records
[divverent/nexuiz.git] / data / qcsrc / server / race.qc
1 .float race_checkpoint; // player: next checkpoint that has to be reached
2 .float race_laptime;
3
4 .entity sprite;
5
6 float race_checkpoint_records[256];
7 string race_checkpoint_recordholders[256];
8
9 float race_highest_checkpoint;
10
11 void race_SendNextCheckpoint(entity e)
12 {
13         float recordtime;
14         string recordholder;
15         float cp;
16
17         if(clienttype(e) != CLIENTTYPE_REAL)
18                 return;
19
20         if(!e.race_laptime)
21                 return;
22
23         cp = e.race_checkpoint;
24         recordtime = race_checkpoint_records[cp];
25         recordholder = race_checkpoint_recordholders[cp];
26         /*
27         recordtime = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/", ftos(cp), "/time")));
28         recordholder = db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/", ftos(cp), "/netname"));
29         */
30         if(recordholder == e.netname)
31                 recordholder = "";
32
33         msg_entity = e;
34         WriteByte(MSG_ONE, SVC_TEMPENTITY);
35         WriteByte(MSG_ONE, TE_CSQC_RACE);
36         WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_NEXT);
37         WriteByte(MSG_ONE, cp); // checkpoint the player will be at next
38         WriteShort(MSG_ONE, recordtime);
39         WriteString(MSG_ONE, recordholder);
40 }
41
42 void race_SendTime(entity e, float cp, float t, float tvalid)
43 {
44         t = floor(0.5 + 10 * t); // make integer
45
46         if(tvalid)
47         if(cp == 0) // finish line
48         {
49                 float s;
50                 s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
51                 if(!s || t < s)
52                         PlayerScore_Add(e, SP_RACE_FASTEST, t - s);
53                 PlayerScore_Add(e, SP_RACE_LAPS, 1);
54         }
55
56         float recordtime;
57         string recordholder;
58
59         if(tvalid)
60         {
61                 recordtime = race_checkpoint_records[cp];
62                 recordholder = strcat1(race_checkpoint_recordholders[cp]); // make a tempstring copy, as we'll possibly strunzone it!
63                 if(recordholder == e.netname)
64                         recordholder = "";
65
66                 if(t < recordtime || recordtime == 0)
67                 {
68                         race_checkpoint_records[cp] = t;
69                         if(race_checkpoint_recordholders[cp])
70                                 strunzone(race_checkpoint_recordholders[cp]);
71                         race_checkpoint_recordholders[cp] = strzone(e.netname);
72                         if(cp == 0)
73                         {
74                                 float grecordtime;
75                                 string grecordholder;
76                                 grecordtime = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/time")));
77                                 grecordholder = db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"));
78                                 if(grecordholder == e.netname)
79                                         grecordholder = "";
80                                 if(grecordtime == 0)
81                                 {
82                                         bprint(e.netname, "^7 set the all-time fastest lap record with ", mmsss(t), "\n");
83                                         db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/time"), ftos(t));
84                                         db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"), e.netname);
85                                 }
86                                 else if(t < grecordtime)
87                                 {
88                                         if(grecordholder == "")
89                                                 bprint(e.netname, "^7 broke his all-time fastest lap record with ", mmsss(t), "\n");
90                                         else
91                                                 bprint(e.netname, "^7 broke ", grecordholder, "^7's all-time fastest lap record with ", mmsss(t), "\n");
92                                         db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/time"), ftos(t));
93                                         db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"), e.netname);
94                                 }
95                                 else
96                                 {
97                                         bprint(e.netname, "^7's new fastest lap could not break ", grecordholder, "^7's all-time fastest lap record of ", mmsss(grecordtime), "\n");
98                                 }
99                         }
100
101                         entity p;
102                         FOR_EACH_REALPLAYER(p)
103                                 if(p.race_checkpoint == cp)
104                                         race_SendNextCheckpoint(p);
105                 }
106         }
107         else
108         {
109                 // dummies
110                 t = 0;
111                 recordtime = 0;
112                 recordholder = "";
113         }
114
115         if(clienttype(e) != CLIENTTYPE_REAL)
116                 return;
117
118         msg_entity = e;
119         WriteByte(MSG_ONE, SVC_TEMPENTITY);
120         WriteByte(MSG_ONE, TE_CSQC_RACE);
121         WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT);
122         WriteByte(MSG_ONE, cp); // checkpoint the player now is at
123         WriteShort(MSG_ONE, t); // time to that intermediate
124         WriteShort(MSG_ONE, recordtime); // previously best time
125         WriteString(MSG_ONE, recordholder); // record holder
126 }
127
128 void race_ClearTime(entity e)
129 {
130         e.race_checkpoint = -1;
131         e.race_laptime = 0;
132
133         if(clienttype(e) != CLIENTTYPE_REAL)
134                 return;
135
136         msg_entity = e;
137         WriteByte(MSG_ONE, SVC_TEMPENTITY);
138         WriteByte(MSG_ONE, TE_CSQC_RACE);
139         WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_CLEAR); // next
140 }
141
142 void checkpoint_touch()
143 {
144         if(other.classname != "player")
145                 return;
146
147         if(other.race_checkpoint == -1 || other.race_checkpoint == self.cnt)
148         {
149                 if(self.cnt == race_highest_checkpoint)
150                         other.race_checkpoint = 0;
151                 else
152                         other.race_checkpoint = self.cnt + 1;
153
154                 race_SendTime(other, self.cnt, time - other.race_laptime, !!other.race_laptime);
155
156                 if(!self.cnt) // finish line
157                         other.race_laptime = time;
158
159                 race_SendNextCheckpoint(other);
160         }
161         else if(other.race_checkpoint == self.cnt + 1)
162         {
163                 // ignored
164         }
165         else if(other.race_checkpoint == 0 && self.cnt == race_highest_checkpoint)
166         {
167                 // ignored
168         }
169         else
170         {
171                 if(self.spawnflags & 4)
172                         Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
173         }
174 }
175
176 void checkpoint_use()
177 {
178         other = activator;
179         checkpoint_touch();
180 }
181
182 float race_waypointsprite_for_player(entity e)
183 {
184         if(e.race_checkpoint == -1)
185                 return self.modelindex;
186         else if(e.race_checkpoint == self.owner.cnt)
187                 return self.modelindex;
188         else
189                 return FALSE;
190 }
191
192 void spawnfunc_trigger_race_checkpoint()
193 {
194         vector o;
195         if(!g_race)
196                 return;
197         InitTrigger();
198         if(self.targetname)
199                 self.use = checkpoint_use;
200         else
201                 self.touch = checkpoint_touch;
202
203         o = (self.absmin + self.absmax) * 0.5;
204         tracebox(o, PL_MIN, PL_MAX, o - '0 0 1' * (o_z - self.absmin_z), MOVE_NORMAL, self);
205         o = trace_endpos;
206         self.nearestwaypoint = waypoint_spawn(o, o, WAYPOINTFLAG_GENERATED);
207         self.nearestwaypointtimeout = time + 1000000000;
208
209         if(!self.message)
210                 self.message = "went backwards";
211
212         if(self.cnt > race_highest_checkpoint)
213                 race_highest_checkpoint = self.cnt;
214
215         if(self.cnt)
216         {
217                 precache_model("models/sprites/race-checkpoint.sp2");
218                 WaypointSprite_SpawnFixed("race-checkpoint", o, self, sprite);
219         }
220         else
221         {
222                 precache_model("models/sprites/race-finish.sp2");
223                 WaypointSprite_SpawnFixed("race-finish", o, self, sprite);
224         }
225         self.sprite.waypointsprite_for_player = race_waypointsprite_for_player;
226 }
227
228 void race_PreparePlayer()
229 {
230         if(!g_race)
231                 return;
232         race_ClearTime(self);
233 }