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