some missing files; g_race_qualifying is still broken (ignores fraglimit, no idea...
[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 float race_checkpoint_records[256];
5 string race_checkpoint_recordholders[256];
6
7 float race_highest_checkpoint;
8
9 void race_SendNextCheckpoint(entity e)
10 {
11         float recordtime;
12         string recordholder;
13         float cp;
14
15         if(clienttype(e) != CLIENTTYPE_REAL)
16                 return;
17
18         if(!e.race_laptime)
19                 return;
20
21         cp = e.race_checkpoint;
22         recordtime = race_checkpoint_records[cp];
23         recordholder = race_checkpoint_recordholders[cp];
24         /*
25         recordtime = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/", ftos(cp), "/time")));
26         recordholder = db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/", ftos(cp), "/netname"));
27         */
28         if(recordholder == e.netname)
29                 recordholder = "";
30
31         msg_entity = e;
32         WriteByte(MSG_ONE, SVC_TEMPENTITY);
33         WriteByte(MSG_ONE, TE_CSQC_RACE);
34         WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_NEXT);
35         WriteByte(MSG_ONE, cp); // checkpoint the player will be at next
36         WriteShort(MSG_ONE, recordtime);
37         WriteString(MSG_ONE, recordholder);
38 }
39
40 void race_SendTime(entity e, float cp, float t, float tvalid)
41 {
42         t = floor(0.5 + 10 * t); // make integer
43
44         if(tvalid)
45         if(cp == 0) // finish line
46         {
47                 float s;
48                 s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
49                 if(!s || t < s)
50                         PlayerScore_Add(e, SP_RACE_FASTEST, t - s);
51                 PlayerScore_Add(e, SP_RACE_LAPS, 1);
52         }
53
54         float recordtime;
55         string recordholder;
56
57         if(tvalid)
58         {
59                 recordtime = race_checkpoint_records[cp];
60                 recordholder = strcat1(race_checkpoint_recordholders[cp]); // make a tempstring copy, as we'll possibly strunzone it!
61                 if(recordholder == e.netname)
62                         recordholder = "";
63
64                 if(t < recordtime || recordtime == 0)
65                 {
66                         race_checkpoint_records[cp] = t;
67                         if(race_checkpoint_recordholders[cp])
68                                 strunzone(race_checkpoint_recordholders[cp]);
69                         race_checkpoint_recordholders[cp] = strzone(e.netname);
70                         if(cp == 0)
71                         {
72                                 float grecordtime;
73                                 string grecordholder;
74                                 grecordtime = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/time")));
75                                 grecordholder = db_get(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"));
76                                 if(grecordholder == e.netname)
77                                         grecordholder = "";
78                                 if(grecordholder == "")
79                                         if(grecordtime == 0)
80                                                 bprint(e.netname, "^7 set the all-time fastest lap record with ", mmsss(t), "\n");
81                                         else
82                                                 bprint(e.netname, "^7 broke his all-time fastest lap record with ", mmsss(t), "\n");
83                                 else
84                                         bprint(e.netname, "^7 broke ", grecordholder, "^7's all-time fastest lap record with ", mmsss(t), "\n");
85                                 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/time"), ftos(t));
86                                 db_put(ServerProgsDB, strcat(GetMapname(), "/racerecord/netname"), e.netname);
87                         }
88
89                         entity p;
90                         FOR_EACH_REALPLAYER(p)
91                                 if(p.race_checkpoint == cp)
92                                         race_SendNextCheckpoint(p);
93                 }
94         }
95         else
96         {
97                 // dummies
98                 t = 0;
99                 recordtime = 0;
100                 recordholder = "";
101         }
102
103         if(clienttype(e) != CLIENTTYPE_REAL)
104                 return;
105
106         msg_entity = e;
107         WriteByte(MSG_ONE, SVC_TEMPENTITY);
108         WriteByte(MSG_ONE, TE_CSQC_RACE);
109         WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT);
110         WriteByte(MSG_ONE, cp); // checkpoint the player now is at
111         WriteShort(MSG_ONE, t); // time to that intermediate
112         WriteShort(MSG_ONE, recordtime); // previously best time
113         WriteString(MSG_ONE, recordholder); // record holder
114         print(race_checkpoint_recordholders[cp], "\n");
115 }
116
117 void race_ClearTime(entity e)
118 {
119         e.race_checkpoint = -1;
120         e.race_laptime = 0;
121
122         if(clienttype(e) != CLIENTTYPE_REAL)
123                 return;
124
125         msg_entity = e;
126         WriteByte(MSG_ONE, SVC_TEMPENTITY);
127         WriteByte(MSG_ONE, TE_CSQC_RACE);
128         WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_CLEAR); // next
129 }
130
131 void checkpoint_touch()
132 {
133         if(other.classname != "player")
134                 return;
135
136         if(other.race_checkpoint == -1 || other.race_checkpoint == self.cnt)
137         {
138                 if(self.cnt == race_highest_checkpoint)
139                         other.race_checkpoint = 0;
140                 else
141                         other.race_checkpoint = self.cnt + 1;
142
143                 race_SendTime(other, self.cnt, time - other.race_laptime, !!other.race_laptime);
144
145                 if(!self.cnt) // finish line
146                         other.race_laptime = time;
147
148                 race_SendNextCheckpoint(other);
149         }
150         else if(other.race_checkpoint == self.cnt + 1)
151         {
152                 // ignored
153         }
154         else if(other.race_checkpoint == 0 && self.cnt == race_highest_checkpoint)
155         {
156                 // ignored
157         }
158         else
159         {
160                 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
161         }
162 }
163
164 void checkpoint_use()
165 {
166         other = activator;
167         checkpoint_touch();
168 }
169
170 void spawnfunc_trigger_race_checkpoint()
171 {
172         vector o;
173         if(!g_race)
174                 return;
175         InitTrigger();
176         if(self.targetname)
177                 self.use = checkpoint_use;
178         else
179                 self.touch = checkpoint_touch;
180
181         o = (self.absmin + self.absmax) * 0.5;
182         traceline(o, o - '0 0 1' * (o_z - self.absmin_z), MOVE_NORMAL, self);
183         o = trace_endpos - '0 0 1' * PL_MIN_z;
184         self.nearestwaypoint = waypoint_spawn(o, o, WAYPOINTFLAG_GENERATED);
185         self.nearestwaypointtimeout = time + 1000000000;
186
187         if(!self.message)
188                 self.message = "went backwards";
189
190         if(self.cnt > race_highest_checkpoint)
191                 race_highest_checkpoint = self.cnt;
192 }
193
194 void race_PreparePlayer()
195 {
196         if(!g_race)
197                 return;
198         race_ClearTime(self);
199 }