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