1 #define MAX_CHECKPOINTS 255
3 .float race_checkpoint; // player: next checkpoint that has to be reached
8 float race_checkpoint_records[MAX_CHECKPOINTS];
9 string race_checkpoint_recordholders[MAX_CHECKPOINTS];
10 float race_checkpoint_lasttimes[MAX_CHECKPOINTS];
11 float race_checkpoint_lastlaps[MAX_CHECKPOINTS];
12 entity race_checkpoint_lastplayers[MAX_CHECKPOINTS];
14 float race_highest_checkpoint;
15 float race_highest_place_spawn;
17 float race_NextCheckpoint(float f)
19 if(f >= race_highest_checkpoint)
25 float race_PreviousCheckpoint(float f)
30 return race_highest_checkpoint;
35 void race_SendNextCheckpoint(entity e)
41 if(clienttype(e) != CLIENTTYPE_REAL)
47 cp = e.race_checkpoint;
48 recordtime = race_checkpoint_records[cp];
49 recordholder = race_checkpoint_recordholders[cp];
51 recordtime = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/", ftos(cp), "/time")));
52 recordholder = db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/", ftos(cp), "/netname"));
54 if(recordholder == e.netname)
58 WriteByte(MSG_ONE, SVC_TEMPENTITY);
59 WriteByte(MSG_ONE, TE_CSQC_RACE);
60 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_NEXT_QUALIFYING);
61 WriteByte(MSG_ONE, cp); // checkpoint the player will be at next
62 WriteShort(MSG_ONE, recordtime);
63 WriteString(MSG_ONE, recordholder);
66 void race_SendTime(entity e, float cp, float t, float tvalid)
68 t = floor(0.5 + 10 * t); // make integer
72 if(cp == 0) // finish line
77 s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
79 PlayerScore_Add(e, SP_RACE_FASTEST, t - s);
83 s = PlayerScore_Add(e, SP_RACE_TIME, 0);
84 snew = floor(0.5 + 10 * (time - restart_countdown));
85 PlayerScore_Add(e, SP_RACE_TIME, snew - s);
86 PlayerTeamScore_Add(e, SP_RACE_LAPS, ST_RACE_LAPS, 1);
97 recordtime = race_checkpoint_records[cp];
98 recordholder = strcat1(race_checkpoint_recordholders[cp]); // make a tempstring copy, as we'll possibly strunzone it!
99 if(recordholder == e.netname)
102 if(t < recordtime || recordtime == 0)
104 race_checkpoint_records[cp] = t;
105 if(race_checkpoint_recordholders[cp])
106 strunzone(race_checkpoint_recordholders[cp]);
107 race_checkpoint_recordholders[cp] = strzone(e.netname);
111 string grecordholder;
112 grecordtime = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/time")));
113 grecordholder = db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"));
114 if(grecordholder == e.netname)
118 bprint(e.netname, "^7 set the all-time fastest lap record with ", mmsss(t), "\n");
119 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/time"), ftos(t));
120 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"), e.netname);
122 else if(t < grecordtime)
124 if(grecordholder == "")
125 bprint(e.netname, "^7 broke his all-time fastest lap record with ", mmsss(t), "\n");
127 bprint(e.netname, "^7 broke ", grecordholder, "^7's all-time fastest lap record with ", mmsss(t), "\n");
128 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/time"), ftos(t));
129 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"), e.netname);
133 if(grecordholder == "")
134 bprint(e.netname, "^7's new fastest lap could not break his all-time fastest lap record of ", mmsss(grecordtime), "\n");
136 bprint(e.netname, "^7's new fastest lap could not break ", grecordholder, "^7's all-time fastest lap record of ", mmsss(grecordtime), "\n");
140 if(g_race_qualifying)
143 FOR_EACH_REALPLAYER(p)
144 if(p.race_checkpoint == cp)
145 race_SendNextCheckpoint(p);
157 if(clienttype(e) == CLIENTTYPE_REAL)
160 if(g_race_qualifying)
162 WriteByte(MSG_ONE, SVC_TEMPENTITY);
163 WriteByte(MSG_ONE, TE_CSQC_RACE);
164 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_QUALIFYING);
165 WriteByte(MSG_ONE, cp); // checkpoint the player now is at
166 WriteShort(MSG_ONE, t); // time to that intermediate
167 WriteShort(MSG_ONE, recordtime); // previously best time
168 WriteString(MSG_ONE, recordholder); // record holder
172 else // RACE! Not Qualifying
174 float lself, lother, othtime;
176 oth = race_checkpoint_lastplayers[cp];
179 lself = PlayerScore_Add(e, SP_RACE_LAPS, 0);
180 lother = race_checkpoint_lastlaps[cp];
181 othtime = race_checkpoint_lasttimes[cp];
184 lself = lother = othtime = 0;
186 if(clienttype(e) == CLIENTTYPE_REAL)
189 WriteByte(MSG_ONE, SVC_TEMPENTITY);
190 WriteByte(MSG_ONE, TE_CSQC_RACE);
191 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE);
192 WriteByte(MSG_ONE, cp); // checkpoint the player now is at
195 WriteShort(MSG_ONE, 0);
196 WriteByte(MSG_ONE, 0);
197 WriteString(MSG_ONE, "");
201 WriteShort(MSG_ONE, floor(10 * (time - race_checkpoint_lasttimes[cp]) + 0.5));
202 WriteByte(MSG_ONE, lself - lother);
203 WriteString(MSG_ONE, oth.netname); // record holder
207 race_checkpoint_lastplayers[cp] = e;
208 race_checkpoint_lasttimes[cp] = time;
209 race_checkpoint_lastlaps[cp] = lself;
211 if(clienttype(oth) == CLIENTTYPE_REAL)
214 WriteByte(MSG_ONE, SVC_TEMPENTITY);
215 WriteByte(MSG_ONE, TE_CSQC_RACE);
216 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT);
217 WriteByte(MSG_ONE, cp); // checkpoint the player now is at
220 WriteShort(MSG_ONE, 0);
221 WriteByte(MSG_ONE, 0);
222 WriteString(MSG_ONE, "");
226 WriteShort(MSG_ONE, floor(10 * (time - othtime) + 0.5));
227 WriteByte(MSG_ONE, lother - lself);
228 WriteString(MSG_ONE, e.netname); // record holder
234 void race_ClearTime(entity e)
236 e.race_checkpoint = -1;
239 if(clienttype(e) != CLIENTTYPE_REAL)
243 WriteByte(MSG_ONE, SVC_TEMPENTITY);
244 WriteByte(MSG_ONE, TE_CSQC_RACE);
245 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_CLEAR); // next
248 void checkpoint_touch()
250 if(other.classname != "player")
253 if(other.race_checkpoint == -1 || other.race_checkpoint == self.race_checkpoint)
255 other.race_checkpoint = race_NextCheckpoint(self.race_checkpoint);
257 race_SendTime(other, self.race_checkpoint, time - other.race_laptime, !!other.race_laptime);
259 if(!self.race_checkpoint) // finish line
260 other.race_laptime = time;
262 if(g_race_qualifying)
263 race_SendNextCheckpoint(other);
265 else if(other.race_checkpoint == race_NextCheckpoint(self.race_checkpoint))
271 if(self.spawnflags & 4)
272 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
276 void checkpoint_use()
282 float race_waypointsprite_for_player(entity e)
284 if(e.race_checkpoint == -1)
285 return self.modelindex;
286 else if(e.race_checkpoint == self.owner.race_checkpoint)
287 return self.modelindex;
292 void spawnfunc_trigger_race_checkpoint()
301 self.use = checkpoint_use;
302 if not(self.spawnflags & 1)
303 self.touch = checkpoint_touch;
305 o = (self.absmin + self.absmax) * 0.5;
306 tracebox(o, PL_MIN, PL_MAX, o - '0 0 1' * (o_z - self.absmin_z), MOVE_NORMAL, self);
307 self.nearestwaypoint = waypoint_spawn(trace_endpos, trace_endpos, WAYPOINTFLAG_GENERATED);
308 self.nearestwaypointtimeout = time + 1000000000;
311 self.message = "went backwards";
313 self.race_checkpoint = self.cnt;
315 if(self.race_checkpoint > race_highest_checkpoint)
316 race_highest_checkpoint = self.race_checkpoint;
318 if(self.race_checkpoint)
320 precache_model("models/sprites/race-checkpoint.sp2");
321 WaypointSprite_SpawnFixed("race-checkpoint", o, self, sprite);
325 precache_model("models/sprites/race-finish.sp2");
326 WaypointSprite_SpawnFixed("race-finish", o, self, sprite);
328 self.sprite.waypointsprite_for_player = race_waypointsprite_for_player;
331 void race_PreparePlayer()
333 race_ClearTime(self);
337 void race_RetractPlayer()
341 self.race_checkpoint = race_PreviousCheckpoint(self.race_checkpoint);
342 if(self.race_checkpoint == 0)
344 race_ClearTime(self);
345 self.race_checkpoint = 0;
353 if(self.killcount == -666 || g_race_qualifying)
354 race_PreparePlayer();
357 void race_PostSpawn(entity spot)
361 if(self.killcount != -666 && !g_race_qualifying)
363 if(spot.target == "")
364 // let the player run without timing, if he did not spawn at a targetting spawnpoint
365 race_PreparePlayer();
367 race_RetractPlayer();
370 if(spot.target != "" && self.race_checkpoint == -1)
371 self.race_checkpoint = 0;
376 void race_PreSpawnObserver()
380 race_PreparePlayer();
383 void spawnfunc_info_player_race (void)
391 spawnfunc_info_player_deathmatch();
393 if(self.race_place > race_highest_place_spawn)
394 race_highest_place_spawn = self.race_place;
397 void race_ClearRecords()
402 for(i = 0; i < MAX_CHECKPOINTS; ++i)
404 race_checkpoint_records[i] = 0;
405 if(race_checkpoint_recordholders[i])
406 strunzone(race_checkpoint_recordholders[i]);
407 race_checkpoint_recordholders[i] = string_null;
414 void race_ReadyRestart()
418 if(g_race_qualifying == 2)
420 g_race_qualifying = 0;
421 independent_players = 0;
425 if(PlayerScore_Sort(race_place) <= race_highest_place_spawn)
426 race_place_valid = 1;
428 race_place_valid = 0;