]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/race.qc
fix Qualifying mode for race; make teleporters able to trigger a timing event
[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(grecordholder == "")
81                                         if(grecordtime == 0)
82                                                 bprint(e.netname, "^7 set the all-time fastest lap record with ", mmsss(t), "\n");
83                                         else
84                                                 bprint(e.netname, "^7 broke his all-time fastest lap record with ", mmsss(t), "\n");
85                                 else
86                                         bprint(e.netname, "^7 broke ", grecordholder, "^7's all-time fastest lap record with ", mmsss(t), "\n");
87                                 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/time"), ftos(t));
88                                 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"), e.netname);
89                         }
90
91                         entity p;
92                         FOR_EACH_REALPLAYER(p)
93                                 if(p.race_checkpoint == cp)
94                                         race_SendNextCheckpoint(p);
95                 }
96         }
97         else
98         {
99                 // dummies
100                 t = 0;
101                 recordtime = 0;
102                 recordholder = "";
103         }
104
105         if(clienttype(e) != CLIENTTYPE_REAL)
106                 return;
107
108         msg_entity = e;
109         WriteByte(MSG_ONE, SVC_TEMPENTITY);
110         WriteByte(MSG_ONE, TE_CSQC_RACE);
111         WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT);
112         WriteByte(MSG_ONE, cp); // checkpoint the player now is at
113         WriteShort(MSG_ONE, t); // time to that intermediate
114         WriteShort(MSG_ONE, recordtime); // previously best time
115         WriteString(MSG_ONE, recordholder); // record holder
116         print(race_checkpoint_recordholders[cp], "\n");
117 }
118
119 void race_ClearTime(entity e)
120 {
121         e.race_checkpoint = -1;
122         e.race_laptime = 0;
123
124         if(clienttype(e) != CLIENTTYPE_REAL)
125                 return;
126
127         msg_entity = e;
128         WriteByte(MSG_ONE, SVC_TEMPENTITY);
129         WriteByte(MSG_ONE, TE_CSQC_RACE);
130         WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_CLEAR); // next
131 }
132
133 void checkpoint_touch()
134 {
135         if(other.classname != "player")
136                 return;
137
138         if(other.race_checkpoint == -1 || other.race_checkpoint == self.cnt)
139         {
140                 if(self.cnt == race_highest_checkpoint)
141                         other.race_checkpoint = 0;
142                 else
143                         other.race_checkpoint = self.cnt + 1;
144
145                 race_SendTime(other, self.cnt, time - other.race_laptime, !!other.race_laptime);
146
147                 if(!self.cnt) // finish line
148                         other.race_laptime = time;
149
150                 race_SendNextCheckpoint(other);
151         }
152         else if(other.race_checkpoint == self.cnt + 1)
153         {
154                 // ignored
155         }
156         else if(other.race_checkpoint == 0 && self.cnt == race_highest_checkpoint)
157         {
158                 // ignored
159         }
160         else
161         {
162                 if(self.spawnflags & 4)
163                         Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
164         }
165 }
166
167 void checkpoint_use()
168 {
169         other = activator;
170         checkpoint_touch();
171 }
172
173 float race_waypointsprite_for_player(entity e)
174 {
175         if(e.race_checkpoint == -1)
176                 return self.modelindex;
177         else if(e.race_checkpoint == self.owner.cnt)
178                 return self.modelindex;
179         else
180                 return FALSE;
181 }
182
183 void spawnfunc_trigger_race_checkpoint()
184 {
185         vector o;
186         if(!g_race)
187                 return;
188         InitTrigger();
189         if(self.targetname)
190                 self.use = checkpoint_use;
191         else
192                 self.touch = checkpoint_touch;
193
194         o = (self.absmin + self.absmax) * 0.5;
195         tracebox(o, PL_MIN, PL_MAX, o - '0 0 1' * (o_z - self.absmin_z), MOVE_NORMAL, self);
196         o = trace_endpos;
197         self.nearestwaypoint = waypoint_spawn(o, o, WAYPOINTFLAG_GENERATED);
198         self.nearestwaypointtimeout = time + 1000000000;
199
200         if(!self.message)
201                 self.message = "went backwards";
202
203         if(self.cnt > race_highest_checkpoint)
204                 race_highest_checkpoint = self.cnt;
205
206         if(self.cnt)
207         {
208                 precache_model("models/sprites/race-checkpoint.sp2");
209                 WaypointSprite_SpawnFixed("race-checkpoint", o, self, sprite);
210         }
211         else
212         {
213                 precache_model("models/sprites/race-finish.sp2");
214                 WaypointSprite_SpawnFixed("race-finish", o, self, sprite);
215         }
216         self.sprite.waypointsprite_for_player = race_waypointsprite_for_player;
217 }
218
219 void race_PreparePlayer()
220 {
221         if(!g_race)
222                 return;
223         race_ClearTime(self);
224 }