]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/g_subs.qc
Add an intrusive list for seeker tags and fix seeker tracing to world origin when...
[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         delete(this);
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                 IL_EACH(g_monsters, it != forent,
55                 {
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                 IL_EACH(g_monsters, it != forent,
71                 {
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));
145                         LOG_TRACE("  Nudging gets us nowhere at ", vtos(pos));
146                         LOG_TRACE("  trace_endpos is ", vtos(trace_endpos));
147                         LOG_TRACE("  trace distance is ", ftos(vlen(pos - trace_endpos)));
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 vec = mindist * '1 0 0';
208         int c = 0;
209         while (c < 6)
210         {
211                 traceline (org, org + vec, true, NULL);
212                 vec = vec * -1;
213                 if (trace_fraction < 1)
214                 {
215                         vector loc = trace_endpos;
216                         traceline (loc, loc + vec, true, NULL);
217                         if (trace_fraction >= 1)
218                                 org = loc + vec;
219                 }
220                 if (c & 1)
221                 {
222                         float h = vec.y;
223                         vec.y = vec.x;
224                         vec.x = vec.z;
225                         vec.z = h;
226                 }
227                 c = c + 1;
228         }
229
230         return org;
231 }
232
233 bool LOD_customize(entity this, entity client)
234 {
235         if(autocvar_loddebug)
236         {
237                 int d = autocvar_loddebug;
238                 if(d == 1)
239                         this.modelindex = this.lodmodelindex0;
240                 else if(d == 2 || !this.lodmodelindex2)
241                         this.modelindex = this.lodmodelindex1;
242                 else // if(d == 3)
243                         this.modelindex = this.lodmodelindex2;
244                 return true;
245         }
246
247         // TODO csqc network this so it only gets sent once
248         vector near_point = NearestPointOnBox(this, client.origin);
249         if(vdist(near_point - client.origin, <, this.loddistance1))
250                 this.modelindex = this.lodmodelindex0;
251         else if(!this.lodmodelindex2 || vdist(near_point - client.origin, <, this.loddistance2))
252                 this.modelindex = this.lodmodelindex1;
253         else
254                 this.modelindex = this.lodmodelindex2;
255
256         return true;
257 }
258
259 void LOD_uncustomize(entity this)
260 {
261         this.modelindex = this.lodmodelindex0;
262 }
263
264 void LODmodel_attach(entity this)
265 {
266         entity e;
267
268         if(!this.loddistance1)
269                 this.loddistance1 = 1000;
270         if(!this.loddistance2)
271                 this.loddistance2 = 2000;
272         this.lodmodelindex0 = this.modelindex;
273
274         if(this.lodtarget1 != "")
275         {
276                 e = find(NULL, targetname, this.lodtarget1);
277                 if(e)
278                 {
279                         this.lodmodel1 = e.model;
280                         delete(e);
281                 }
282         }
283         if(this.lodtarget2 != "")
284         {
285                 e = find(NULL, targetname, this.lodtarget2);
286                 if(e)
287                 {
288                         this.lodmodel2 = e.model;
289                         delete(e);
290                 }
291         }
292
293         if(autocvar_loddebug < 0)
294         {
295                 this.lodmodel1 = this.lodmodel2 = ""; // don't even initialize
296         }
297
298         if(this.lodmodel1 != "")
299         {
300                 vector mi, ma;
301                 mi = this.mins;
302                 ma = this.maxs;
303
304                 precache_model(this.lodmodel1);
305                 _setmodel(this, this.lodmodel1);
306                 this.lodmodelindex1 = this.modelindex;
307
308                 if(this.lodmodel2 != "")
309                 {
310                         precache_model(this.lodmodel2);
311                         _setmodel(this, this.lodmodel2);
312                         this.lodmodelindex2 = this.modelindex;
313                 }
314
315                 this.modelindex = this.lodmodelindex0;
316                 setsize(this, mi, ma);
317         }
318
319         if(this.lodmodelindex1)
320                 if (!getSendEntity(this))
321                         SetCustomizer(this, LOD_customize, LOD_uncustomize);
322 }
323
324 void ApplyMinMaxScaleAngles(entity e)
325 {
326         if(e.angles.x != 0 || e.angles.z != 0 || e.avelocity.x != 0 || e.avelocity.z != 0) // "weird" rotation
327         {
328                 e.maxs = '1 1 1' * vlen(
329                         '1 0 0' * max(-e.mins.x, e.maxs.x) +
330                         '0 1 0' * max(-e.mins.y, e.maxs.y) +
331                         '0 0 1' * max(-e.mins.z, e.maxs.z)
332                 );
333                 e.mins = -e.maxs;
334         }
335         else if(e.angles.y != 0 || e.avelocity.y != 0) // yaw only is a bit better
336         {
337                 e.maxs_x = vlen(
338                         '1 0 0' * max(-e.mins.x, e.maxs.x) +
339                         '0 1 0' * max(-e.mins.y, e.maxs.y)
340                 );
341                 e.maxs_y = e.maxs.x;
342                 e.mins_x = -e.maxs.x;
343                 e.mins_y = -e.maxs.x;
344         }
345         if(e.scale)
346                 setsize(e, e.mins * e.scale, e.maxs * e.scale);
347         else
348                 setsize(e, e.mins, e.maxs);
349 }
350
351 void SetBrushEntityModel(entity this)
352 {
353         if(this.model != "")
354         {
355                 precache_model(this.model);
356                 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
357                 {
358                         vector mi = this.mins;
359                         vector ma = this.maxs;
360                         _setmodel(this, this.model); // no precision needed
361                         setsize(this, mi, ma);
362                 }
363                 else
364                         _setmodel(this, this.model); // no precision needed
365                 InitializeEntity(this, LODmodel_attach, INITPRIO_FINDTARGET);
366         }
367         setorigin(this, this.origin);
368         ApplyMinMaxScaleAngles(this);
369 }
370
371 void SetBrushEntityModelNoLOD(entity this)
372 {
373         if(this.model != "")
374         {
375                 precache_model(this.model);
376                 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
377                 {
378                         vector mi = this.mins;
379                         vector ma = this.maxs;
380                         _setmodel(this, this.model); // no precision needed
381                         setsize(this, mi, ma);
382                 }
383                 else
384                         _setmodel(this, this.model); // no precision needed
385         }
386         setorigin(this, this.origin);
387         ApplyMinMaxScaleAngles(this);
388 }
389
390 /*
391 ================
392 InitTrigger
393 ================
394 */
395
396 void SetMovedir(entity this)
397 {
398         if(this.movedir != '0 0 0')
399                 this.movedir = normalize(this.movedir);
400         else
401         {
402                 makevectors(this.angles);
403                 this.movedir = v_forward;
404         }
405
406         this.angles = '0 0 0';
407 }
408
409 void InitTrigger(entity this)
410 {
411 // trigger angles are used for one-way touches.  An angle of 0 is assumed
412 // to mean no restrictions, so use a yaw of 360 instead.
413         SetMovedir(this);
414         this.solid = SOLID_TRIGGER;
415         SetBrushEntityModel(this);
416         set_movetype(this, MOVETYPE_NONE);
417         this.modelindex = 0;
418         this.model = "";
419 }
420
421 void InitSolidBSPTrigger(entity this)
422 {
423 // trigger angles are used for one-way touches.  An angle of 0 is assumed
424 // to mean no restrictions, so use a yaw of 360 instead.
425         SetMovedir(this);
426         this.solid = SOLID_BSP;
427         SetBrushEntityModel(this);
428         set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
429 //      this.modelindex = 0;
430         this.model = "";
431 }
432
433 bool InitMovingBrushTrigger(entity this)
434 {
435 // trigger angles are used for one-way touches.  An angle of 0 is assumed
436 // to mean no restrictions, so use a yaw of 360 instead.
437         this.solid = SOLID_BSP;
438         SetBrushEntityModel(this);
439         set_movetype(this, MOVETYPE_PUSH);
440         if(this.modelindex == 0)
441         {
442                 objerror(this, "InitMovingBrushTrigger: no brushes found!");
443                 return false;
444         }
445         return true;
446 }