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];
11 float race_highest_checkpoint;
12 float race_highest_place_spawn;
14 float race_NextCheckpoint(float f)
16 if(f >= race_highest_checkpoint)
22 float race_PreviousCheckpoint(float f)
27 return race_highest_checkpoint;
32 void race_SendNextCheckpoint(entity e)
38 if(clienttype(e) != CLIENTTYPE_REAL)
44 cp = e.race_checkpoint;
45 recordtime = race_checkpoint_records[cp];
46 recordholder = race_checkpoint_recordholders[cp];
48 recordtime = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/", ftos(cp), "/time")));
49 recordholder = db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/", ftos(cp), "/netname"));
51 if(recordholder == e.netname)
55 WriteByte(MSG_ONE, SVC_TEMPENTITY);
56 WriteByte(MSG_ONE, TE_CSQC_RACE);
57 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_NEXT);
58 WriteByte(MSG_ONE, cp); // checkpoint the player will be at next
59 WriteShort(MSG_ONE, recordtime);
60 WriteString(MSG_ONE, recordholder);
63 void race_SendTime(entity e, float cp, float t, float tvalid)
65 t = floor(0.5 + 10 * t); // make integer
68 if(cp == 0) // finish line
71 s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
73 PlayerScore_Add(e, SP_RACE_FASTEST, t - s);
74 PlayerTeamScore_Add(e, SP_RACE_LAPS, ST_RACE_LAPS, 1);
82 recordtime = race_checkpoint_records[cp];
83 recordholder = strcat1(race_checkpoint_recordholders[cp]); // make a tempstring copy, as we'll possibly strunzone it!
84 if(recordholder == e.netname)
87 if(t < recordtime || recordtime == 0)
89 race_checkpoint_records[cp] = t;
90 if(race_checkpoint_recordholders[cp])
91 strunzone(race_checkpoint_recordholders[cp]);
92 race_checkpoint_recordholders[cp] = strzone(e.netname);
97 grecordtime = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/time")));
98 grecordholder = db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"));
99 if(grecordholder == e.netname)
103 bprint(e.netname, "^7 set the all-time fastest lap record with ", mmsss(t), "\n");
104 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/time"), ftos(t));
105 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"), e.netname);
107 else if(t < grecordtime)
109 if(grecordholder == "")
110 bprint(e.netname, "^7 broke his all-time fastest lap record with ", mmsss(t), "\n");
112 bprint(e.netname, "^7 broke ", grecordholder, "^7's all-time fastest lap record with ", mmsss(t), "\n");
113 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/time"), ftos(t));
114 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"), e.netname);
118 if(grecordholder == "")
119 bprint(e.netname, "^7's new fastest lap could not break his all-time fastest lap record of ", mmsss(grecordtime), "\n");
121 bprint(e.netname, "^7's new fastest lap could not break ", grecordholder, "^7's all-time fastest lap record of ", mmsss(grecordtime), "\n");
126 FOR_EACH_REALPLAYER(p)
127 if(p.race_checkpoint == cp)
128 race_SendNextCheckpoint(p);
139 if(clienttype(e) != CLIENTTYPE_REAL)
143 WriteByte(MSG_ONE, SVC_TEMPENTITY);
144 WriteByte(MSG_ONE, TE_CSQC_RACE);
145 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT);
146 WriteByte(MSG_ONE, cp); // checkpoint the player now is at
147 WriteShort(MSG_ONE, t); // time to that intermediate
148 WriteShort(MSG_ONE, recordtime); // previously best time
149 WriteString(MSG_ONE, recordholder); // record holder
152 void race_ClearTime(entity e)
154 e.race_checkpoint = -1;
157 if(clienttype(e) != CLIENTTYPE_REAL)
161 WriteByte(MSG_ONE, SVC_TEMPENTITY);
162 WriteByte(MSG_ONE, TE_CSQC_RACE);
163 WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_CLEAR); // next
166 void checkpoint_touch()
168 if(other.classname != "player")
171 if(other.race_checkpoint == -1 || other.race_checkpoint == self.race_checkpoint)
173 other.race_checkpoint = race_NextCheckpoint(self.race_checkpoint);
175 race_SendTime(other, self.race_checkpoint, time - other.race_laptime, !!other.race_laptime);
177 if(!self.race_checkpoint) // finish line
178 other.race_laptime = time;
180 race_SendNextCheckpoint(other);
182 else if(other.race_checkpoint == race_NextCheckpoint(self.race_checkpoint))
188 if(self.spawnflags & 4)
189 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
193 void checkpoint_use()
199 float race_waypointsprite_for_player(entity e)
201 if(e.race_checkpoint == -1)
202 return self.modelindex;
203 else if(e.race_checkpoint == self.owner.race_checkpoint)
204 return self.modelindex;
209 void spawnfunc_trigger_race_checkpoint()
218 self.use = checkpoint_use;
219 if not(self.spawnflags & 1)
220 self.touch = checkpoint_touch;
222 o = (self.absmin + self.absmax) * 0.5;
223 tracebox(o, PL_MIN, PL_MAX, o - '0 0 1' * (o_z - self.absmin_z), MOVE_NORMAL, self);
224 self.nearestwaypoint = waypoint_spawn(trace_endpos, trace_endpos, WAYPOINTFLAG_GENERATED);
225 self.nearestwaypointtimeout = time + 1000000000;
228 self.message = "went backwards";
230 self.race_checkpoint = self.cnt;
232 if(self.race_checkpoint > race_highest_checkpoint)
233 race_highest_checkpoint = self.race_checkpoint;
235 if(self.race_checkpoint)
237 precache_model("models/sprites/race-checkpoint.sp2");
238 WaypointSprite_SpawnFixed("race-checkpoint", o, self, sprite);
242 precache_model("models/sprites/race-finish.sp2");
243 WaypointSprite_SpawnFixed("race-finish", o, self, sprite);
245 self.sprite.waypointsprite_for_player = race_waypointsprite_for_player;
248 void race_PreparePlayer()
250 race_ClearTime(self);
254 void race_RetractPlayer()
258 self.race_checkpoint = race_PreviousCheckpoint(self.race_checkpoint);
259 if(self.race_checkpoint == 0)
261 race_ClearTime(self);
262 self.race_checkpoint = 0;
270 if(self.killcount == -666 || g_race_qualifying)
271 race_PreparePlayer();
274 void race_PostSpawn(entity spot)
278 if(self.killcount != -666 && !g_race_qualifying)
280 if(spot.target == "")
281 // let the player run without timing, if he did not spawn at a targetting spawnpoint
282 race_PreparePlayer();
284 race_RetractPlayer();
287 if(spot.target != "" && self.race_checkpoint == -1)
288 self.race_checkpoint = 0;
293 void race_PreSpawnObserver()
297 race_PreparePlayer();
300 void spawnfunc_info_player_race (void)
308 spawnfunc_info_player_deathmatch();
310 if(self.race_place > race_highest_place_spawn)
311 race_highest_place_spawn = self.race_place;
314 void race_ClearRecords()
319 for(i = 0; i < MAX_CHECKPOINTS; ++i)
321 race_checkpoint_records[i] = 0;
322 if(race_checkpoint_recordholders[i])
323 strunzone(race_checkpoint_recordholders[i]);
324 race_checkpoint_recordholders[i] = string_null;
331 void race_ReadyRestart()
335 if(g_race_qualifying == 2)
337 g_race_qualifying = 0;
338 independent_players = 0;
342 if(PlayerScore_Sort(race_place) <= race_highest_place_spawn)
343 race_place_valid = 1;
345 race_place_valid = 0;