]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/g_subs.qc
Fix up some more FOR_EACH_PLAYER loops
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_subs.qc
1 #include "g_subs.qh"
2
3 #include "antilag.qh"
4 #include "command/common.qh"
5 #include "../lib/warpzone/common.qh"
6 #include "../common/triggers/subs.qh"
7
8 spawnfunc(info_null)
9 {
10         remove(self);
11         // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
12 }
13
14 /*
15 ==================
16 main
17
18 unused but required by the engine
19 ==================
20 */
21 void main ()
22 {
23
24 }
25
26 // Misc
27
28 /*
29 ==================
30 traceline_antilag
31
32 A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
33 Additionally it moves players back into the past before the trace and restores them afterward.
34 ==================
35 */
36 void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz)
37 {
38         // check whether antilagged traces are enabled
39         if (lag < 0.001)
40                 lag = 0;
41         if (!IS_REAL_CLIENT(forent))
42                 lag = 0; // only antilag for clients
43
44         // change shooter to SOLID_BBOX so the shot can hit corpses
45         int oldsolid = source.dphitcontentsmask;
46         if(source)
47                 source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
48
49         if (lag)
50         {
51                 // take players back into the past
52                 FOREACH_CLIENT(IS_PLAYER(it) && it != forent, LAMBDA(antilag_takeback(it, time - lag)));
53                 FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, LAMBDA(
54                         if(it != forent)
55                                 antilag_takeback(it, time - lag);
56                 ));
57         }
58
59         // do the trace
60         if(wz)
61                 WarpZone_TraceBox (v1, mi, ma, v2, nomonst, forent);
62         else
63                 tracebox (v1, mi, ma, v2, nomonst, forent);
64
65         // restore players to current positions
66         if (lag)
67         {
68                 FOREACH_CLIENT(IS_PLAYER(it) && it != forent, LAMBDA(antilag_restore(it)));
69                 FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, LAMBDA(
70                         if(it != forent)
71                                 antilag_restore(it);
72                 ));
73         }
74
75         // restore shooter solid type
76         if(source)
77                 source.dphitcontentsmask = oldsolid;
78 }
79 void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
80 {
81         tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, false);
82 }
83 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
84 {
85         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
86                 lag = 0;
87         traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
88 }
89 void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
90 {
91         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
92                 lag = 0;
93         tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, false);
94 }
95 void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
96 {
97         tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, true);
98 }
99 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
100 {
101         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
102                 lag = 0;
103         WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
104 }
105 void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
106 {
107         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
108                 lag = 0;
109         tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, true);
110 }
111
112 float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity) // returns the number of traces done, for benchmarking
113 {
114         vector pos, dir, t;
115         float nudge;
116         entity stopentity;
117
118         //nudge = 2 * cvar("collision_impactnudge"); // why not?
119         nudge = 0.5;
120
121         dir = normalize(v2 - v1);
122
123         pos = v1 + dir * nudge;
124
125         float c;
126         c = 0;
127
128         for (;;)
129         {
130                 if(pos * dir >= v2 * dir)
131                 {
132                         // went too far
133                         trace_fraction = 1;
134                         trace_endpos = v2;
135                         return c;
136                 }
137
138                 tracebox(pos, mi, ma, v2, nomonsters, forent);
139                 ++c;
140
141                 if(c == 50)
142                 {
143                         LOG_TRACE("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2), "\n");
144                         LOG_TRACE("  Nudging gets us nowhere at ", vtos(pos), "\n");
145                         LOG_TRACE("  trace_endpos is ", vtos(trace_endpos), "\n");
146                         LOG_TRACE("  trace distance is ", ftos(vlen(pos - trace_endpos)), "\n");
147                 }
148
149                 stopentity = trace_ent;
150
151                 if(trace_startsolid)
152                 {
153                         // we started inside solid.
154                         // then trace from endpos to pos
155                         t = trace_endpos;
156                         tracebox(t, mi, ma, pos, nomonsters, forent);
157                         ++c;
158                         if(trace_startsolid)
159                         {
160                                 // t is still inside solid? bad
161                                 // force advance, then, and retry
162                                 pos = t + dir * nudge;
163
164                                 // but if we hit an entity, stop RIGHT before it
165                                 if(stopatentity && stopentity && stopentity != ignorestopatentity)
166                                 {
167                                         trace_ent = stopentity;
168                                         trace_endpos = t;
169                                         trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
170                                         return c;
171                                 }
172                         }
173                         else
174                         {
175                                 // we actually LEFT solid!
176                                 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
177                                 return c;
178                         }
179                 }
180                 else
181                 {
182                         // pos is outside solid?!? but why?!? never mind, just return it.
183                         trace_endpos = pos;
184                         trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
185                         return c;
186                 }
187         }
188 }
189
190 void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity)
191 {
192         tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity);
193 }
194
195 /*
196 ==================
197 findbetterlocation
198
199 Returns a point at least 12 units away from walls
200 (useful for explosion animations, although the blast is performed where it really happened)
201 Ripped from DPMod
202 ==================
203 */
204 vector findbetterlocation (vector org, float mindist)
205 {
206         vector  loc;
207         vector vec;
208         float c, h;
209
210         vec = mindist * '1 0 0';
211         c = 0;
212         while (c < 6)
213         {
214                 traceline (org, org + vec, true, world);
215                 vec = vec * -1;
216                 if (trace_fraction < 1)
217                 {
218                         loc = trace_endpos;
219                         traceline (loc, loc + vec, true, world);
220                         if (trace_fraction >= 1)
221                                 org = loc + vec;
222                 }
223                 if (c & 1)
224                 {
225                         h = vec.y;
226                         vec.y = vec.x;
227                         vec.x = vec.z;
228                         vec.z = h;
229                 }
230                 c = c + 1;
231         }
232
233         return org;
234 }
235
236 float LOD_customize()
237 {SELFPARAM();
238         float d;
239
240         if(autocvar_loddebug)
241         {
242                 d = autocvar_loddebug;
243                 if(d == 1)
244                         self.modelindex = self.lodmodelindex0;
245                 else if(d == 2 || !self.lodmodelindex2)
246                         self.modelindex = self.lodmodelindex1;
247                 else // if(d == 3)
248                         self.modelindex = self.lodmodelindex2;
249                 return true;
250         }
251
252         // TODO csqc network this so it only gets sent once
253         d = vlen(NearestPointOnBox(self, other.origin) - other.origin);
254         if(d < self.loddistance1)
255                 self.modelindex = self.lodmodelindex0;
256         else if(!self.lodmodelindex2 || d < self.loddistance2)
257                 self.modelindex = self.lodmodelindex1;
258         else
259                 self.modelindex = self.lodmodelindex2;
260
261         return true;
262 }
263
264 void LOD_uncustomize()
265 {SELFPARAM();
266         self.modelindex = self.lodmodelindex0;
267 }
268
269 void LODmodel_attach()
270 {SELFPARAM();
271         entity e;
272
273         if(!self.loddistance1)
274                 self.loddistance1 = 1000;
275         if(!self.loddistance2)
276                 self.loddistance2 = 2000;
277         self.lodmodelindex0 = self.modelindex;
278
279         if(self.lodtarget1 != "")
280         {
281                 e = find(world, targetname, self.lodtarget1);
282                 if(e)
283                 {
284                         self.lodmodel1 = e.model;
285                         remove(e);
286                 }
287         }
288         if(self.lodtarget2 != "")
289         {
290                 e = find(world, targetname, self.lodtarget2);
291                 if(e)
292                 {
293                         self.lodmodel2 = e.model;
294                         remove(e);
295                 }
296         }
297
298         if(autocvar_loddebug < 0)
299         {
300                 self.lodmodel1 = self.lodmodel2 = ""; // don't even initialize
301         }
302
303         if(self.lodmodel1 != "")
304         {
305                 vector mi, ma;
306                 mi = self.mins;
307                 ma = self.maxs;
308
309                 precache_model(self.lodmodel1);
310                 _setmodel(self, self.lodmodel1);
311                 self.lodmodelindex1 = self.modelindex;
312
313                 if(self.lodmodel2 != "")
314                 {
315                         precache_model(self.lodmodel2);
316                         _setmodel(self, self.lodmodel2);
317                         self.lodmodelindex2 = self.modelindex;
318                 }
319
320                 self.modelindex = self.lodmodelindex0;
321                 setsize(self, mi, ma);
322         }
323
324         if(self.lodmodelindex1)
325                 if (!self.SendEntity)
326                         SetCustomizer(self, LOD_customize, LOD_uncustomize);
327 }
328
329 void ApplyMinMaxScaleAngles(entity e)
330 {SELFPARAM();
331         if(e.angles.x != 0 || e.angles.z != 0 || self.avelocity.x != 0 || self.avelocity.z != 0) // "weird" rotation
332         {
333                 e.maxs = '1 1 1' * vlen(
334                         '1 0 0' * max(-e.mins.x, e.maxs.x) +
335                         '0 1 0' * max(-e.mins.y, e.maxs.y) +
336                         '0 0 1' * max(-e.mins.z, e.maxs.z)
337                 );
338                 e.mins = -e.maxs;
339         }
340         else if(e.angles.y != 0 || self.avelocity.y != 0) // yaw only is a bit better
341         {
342                 e.maxs_x = vlen(
343                         '1 0 0' * max(-e.mins.x, e.maxs.x) +
344                         '0 1 0' * max(-e.mins.y, e.maxs.y)
345                 );
346                 e.maxs_y = e.maxs.x;
347                 e.mins_x = -e.maxs.x;
348                 e.mins_y = -e.maxs.x;
349         }
350         if(e.scale)
351                 setsize(e, e.mins * e.scale, e.maxs * e.scale);
352         else
353                 setsize(e, e.mins, e.maxs);
354 }
355
356 void SetBrushEntityModel()
357 {SELFPARAM();
358         if(self.model != "")
359         {
360                 precache_model(self.model);
361                 if(self.mins != '0 0 0' || self.maxs != '0 0 0')
362                 {
363                         vector mi = self.mins;
364                         vector ma = self.maxs;
365                         _setmodel(self, self.model); // no precision needed
366                         setsize(self, mi, ma);
367                 }
368                 else
369                         _setmodel(self, self.model); // no precision needed
370                 InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
371         }
372         setorigin(self, self.origin);
373         ApplyMinMaxScaleAngles(self);
374 }
375
376 void SetBrushEntityModelNoLOD()
377 {SELFPARAM();
378         if(self.model != "")
379         {
380                 precache_model(self.model);
381                 if(self.mins != '0 0 0' || self.maxs != '0 0 0')
382                 {
383                         vector mi = self.mins;
384                         vector ma = self.maxs;
385                         _setmodel(self, self.model); // no precision needed
386                         setsize(self, mi, ma);
387                 }
388                 else
389                         _setmodel(self, self.model); // no precision needed
390         }
391         setorigin(self, self.origin);
392         ApplyMinMaxScaleAngles(self);
393 }
394
395 /*
396 ================
397 InitTrigger
398 ================
399 */
400
401 void SetMovedir(entity this)
402 {
403         if(this.movedir != '0 0 0')
404                 this.movedir = normalize(this.movedir);
405         else
406         {
407                 makevectors(this.angles);
408                 this.movedir = v_forward;
409         }
410
411         this.angles = '0 0 0';
412 }
413
414 void InitTrigger()
415 {SELFPARAM();
416 // trigger angles are used for one-way touches.  An angle of 0 is assumed
417 // to mean no restrictions, so use a yaw of 360 instead.
418         SetMovedir(self);
419         self.solid = SOLID_TRIGGER;
420         SetBrushEntityModel();
421         self.movetype = MOVETYPE_NONE;
422         self.modelindex = 0;
423         self.model = "";
424 }
425
426 void InitSolidBSPTrigger()
427 {SELFPARAM();
428 // trigger angles are used for one-way touches.  An angle of 0 is assumed
429 // to mean no restrictions, so use a yaw of 360 instead.
430         SetMovedir(self);
431         self.solid = SOLID_BSP;
432         SetBrushEntityModel();
433         self.movetype = MOVETYPE_NONE; // why was this PUSH? -div0
434 //      self.modelindex = 0;
435         self.model = "";
436 }
437
438 float InitMovingBrushTrigger()
439 {SELFPARAM();
440 // trigger angles are used for one-way touches.  An angle of 0 is assumed
441 // to mean no restrictions, so use a yaw of 360 instead.
442         self.solid = SOLID_BSP;
443         SetBrushEntityModel();
444         self.movetype = MOVETYPE_PUSH;
445         if(self.modelindex == 0)
446         {
447                 objerror("InitMovingBrushTrigger: no brushes found!");
448                 return 0;
449         }
450         return 1;
451 }