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