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
71 if(cp == 0) // finish line
76 s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
78 PlayerScore_Add(e, SP_RACE_FASTEST, t - s);
82 s = PlayerScore_Add(e, SP_RACE_TIME, 0);
83 PlayerScore_Add(e, SP_RACE_TIME, floor(0.5 + 10 * (time - s)));
84 PlayerTeamScore_Add(e, SP_RACE_LAPS, ST_RACE_LAPS, 1);
95 recordtime = race_checkpoint_records[cp];
96 recordholder = strcat1(race_checkpoint_recordholders[cp]); // make a tempstring copy, as we'll possibly strunzone it!
97 if(recordholder == e.netname)
100 if(t < recordtime || recordtime == 0)
102 race_checkpoint_records[cp] = t;
103 if(race_checkpoint_recordholders[cp])
104 strunzone(race_checkpoint_recordholders[cp]);
105 race_checkpoint_recordholders[cp] = strzone(e.netname);
109 string grecordholder;
110 grecordtime = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/time")));
111 grecordholder = db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"));
112 if(grecordholder == e.netname)
116 bprint(e.netname, "^7 set the all-time fastest lap record with ", mmsss(t), "\n");
117 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/time"), ftos(t));
118 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"), e.netname);
120 else if(t < grecordtime)
122 if(grecordholder == "")
123 bprint(e.netname, "^7 broke his all-time fastest lap record with ", mmsss(t), "\n");
125 bprint(e.netname, "^7 broke ", grecordholder, "^7's all-time fastest lap record with ", mmsss(t), "\n");
126 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/time"), ftos(t));
127 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"), e.netname);
131 if(grecordholder == "")
132 bprint(e.netname, "^7's new fastest lap could not break his all-time fastest lap record of ", mmsss(grecordtime), "\n");
134 bprint(e.netname, "^7's new fastest lap could not break ", grecordholder, "^7's all-time fastest lap record of ", mmsss(grecordtime), "\n");
138 if(g_race_qualifying)
141 FOR_EACH_REALPLAYER(p)
142 if(p.race_checkpoint == cp)
143 race_SendNextCheckpoint(p);
155 if(clienttype(e) == CLIENTTYPE_REAL)
158 if(g_race_qualifying)
160 WriteByte(MSG_ONE, SVC_TEMPENTITY);
161 WriteByte(MSG_ONE, TE_CSQC_RACE);
162 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_QUALIFYING);
163 WriteByte(MSG_ONE, cp); // checkpoint the player now is at
164 WriteShort(MSG_ONE, t); // time to that intermediate
165 WriteShort(MSG_ONE, recordtime); // previously best time
166 WriteString(MSG_ONE, recordholder); // record holder
170 else // RACE! Not Qualifying
172 float lself, lother, othtime;
174 oth = race_checkpoint_lastplayers[cp];
177 lself = PlayerScore_Add(e, SP_RACE_LAPS, 0);
178 lother = race_checkpoint_lastlaps[cp];
179 othtime = race_checkpoint_lasttimes[cp];
182 lself = lother = othtime = 0;
184 if(clienttype(e) == CLIENTTYPE_REAL)
187 WriteByte(MSG_ONE, SVC_TEMPENTITY);
188 WriteByte(MSG_ONE, TE_CSQC_RACE);
189 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE);
190 WriteByte(MSG_ONE, cp); // checkpoint the player now is at
193 WriteShort(MSG_ONE, 0);
194 WriteByte(MSG_ONE, 0);
195 WriteString(MSG_ONE, "");
199 WriteShort(MSG_ONE, floor(10 * (time - race_checkpoint_lasttimes[cp]) + 0.5));
200 WriteByte(MSG_ONE, lself - lother);
201 WriteString(MSG_ONE, oth.netname); // record holder
205 race_checkpoint_lastplayers[cp] = e;
206 race_checkpoint_lasttimes[cp] = time;
207 race_checkpoint_lastlaps[cp] = lself;
209 if(clienttype(oth) == CLIENTTYPE_REAL)
212 WriteByte(MSG_ONE, SVC_TEMPENTITY);
213 WriteByte(MSG_ONE, TE_CSQC_RACE);
214 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT);
215 WriteByte(MSG_ONE, cp); // checkpoint the player now is at
218 WriteShort(MSG_ONE, 0);
219 WriteByte(MSG_ONE, 0);
220 WriteString(MSG_ONE, "");
224 WriteShort(MSG_ONE, floor(10 * (time - othtime) + 0.5));
225 WriteByte(MSG_ONE, lother - lself);
226 WriteString(MSG_ONE, e.netname); // record holder
232 void race_ClearTime(entity e)
234 e.race_checkpoint = -1;
237 if(clienttype(e) != CLIENTTYPE_REAL)
241 WriteByte(MSG_ONE, SVC_TEMPENTITY);
242 WriteByte(MSG_ONE, TE_CSQC_RACE);
243 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_CLEAR); // next
246 void checkpoint_touch()
248 if(other.classname != "player")
251 if(other.race_checkpoint == -1 || other.race_checkpoint == self.race_checkpoint)
253 other.race_checkpoint = race_NextCheckpoint(self.race_checkpoint);
255 race_SendTime(other, self.race_checkpoint, time - other.race_laptime, !!other.race_laptime);
257 if(!self.race_checkpoint) // finish line
258 other.race_laptime = time;
260 if(g_race_qualifying)
261 race_SendNextCheckpoint(other);
263 else if(other.race_checkpoint == race_NextCheckpoint(self.race_checkpoint))
269 if(self.spawnflags & 4)
270 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
274 void checkpoint_use()
280 float race_waypointsprite_for_player(entity e)
282 if(e.race_checkpoint == -1)
283 return self.modelindex;
284 else if(e.race_checkpoint == self.owner.race_checkpoint)
285 return self.modelindex;
290 void spawnfunc_trigger_race_checkpoint()
299 self.use = checkpoint_use;
300 if not(self.spawnflags & 1)
301 self.touch = checkpoint_touch;
303 o = (self.absmin + self.absmax) * 0.5;
304 tracebox(o, PL_MIN, PL_MAX, o - '0 0 1' * (o_z - self.absmin_z), MOVE_NORMAL, self);
305 self.nearestwaypoint = waypoint_spawn(trace_endpos, trace_endpos, WAYPOINTFLAG_GENERATED);
306 self.nearestwaypointtimeout = time + 1000000000;
309 self.message = "went backwards";
311 self.race_checkpoint = self.cnt;
313 if(self.race_checkpoint > race_highest_checkpoint)
314 race_highest_checkpoint = self.race_checkpoint;
316 if(self.race_checkpoint)
318 precache_model("models/sprites/race-checkpoint.sp2");
319 WaypointSprite_SpawnFixed("race-checkpoint", o, self, sprite);
323 precache_model("models/sprites/race-finish.sp2");
324 WaypointSprite_SpawnFixed("race-finish", o, self, sprite);
326 self.sprite.waypointsprite_for_player = race_waypointsprite_for_player;
329 void race_PreparePlayer()
331 race_ClearTime(self);
335 void race_RetractPlayer()
339 self.race_checkpoint = race_PreviousCheckpoint(self.race_checkpoint);
340 if(self.race_checkpoint == 0)
342 race_ClearTime(self);
343 self.race_checkpoint = 0;
351 if(self.killcount == -666 || g_race_qualifying)
352 race_PreparePlayer();
355 void race_PostSpawn(entity spot)
359 if(self.killcount != -666 && !g_race_qualifying)
361 if(spot.target == "")
362 // let the player run without timing, if he did not spawn at a targetting spawnpoint
363 race_PreparePlayer();
365 race_RetractPlayer();
368 if(spot.target != "" && self.race_checkpoint == -1)
369 self.race_checkpoint = 0;
374 void race_PreSpawnObserver()
378 race_PreparePlayer();
381 void spawnfunc_info_player_race (void)
389 spawnfunc_info_player_deathmatch();
391 if(self.race_place > race_highest_place_spawn)
392 race_highest_place_spawn = self.race_place;
395 void race_ClearRecords()
400 for(i = 0; i < MAX_CHECKPOINTS; ++i)
402 race_checkpoint_records[i] = 0;
403 if(race_checkpoint_recordholders[i])
404 strunzone(race_checkpoint_recordholders[i]);
405 race_checkpoint_recordholders[i] = string_null;
412 void race_ReadyRestart()
416 if(g_race_qualifying == 2)
418 g_race_qualifying = 0;
419 independent_players = 0;
423 if(PlayerScore_Sort(race_place) <= race_highest_place_spawn)
424 race_place_valid = 1;
426 race_place_valid = 0;