]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/g_subs.qc
server: remove _all
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_subs.qc
1 #include "g_subs.qh"
2
3 #include <server/defs.qh>
4 #include <server/miscfunctions.qh>
5 #include "antilag.qh"
6 #include "command/common.qh"
7 #include "../common/state.qh"
8 #include "../lib/warpzone/common.qh"
9 #include "../common/triggers/subs.qh"
10
11 spawnfunc(info_null)
12 {
13         delete(this);
14         // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
15 }
16
17 /*
18 ==================
19 main
20
21 unused but required by the engine
22 ==================
23 */
24 void main ()
25 {
26
27 }
28
29 // Misc
30
31 /*
32 ==================
33 traceline_antilag
34
35 A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
36 Additionally it moves players back into the past before the trace and restores them afterward.
37 ==================
38 */
39 void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz)
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         int 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                 FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_takeback(it, CS(it), time - lag));
56                 IL_EACH(g_monsters, it != forent,
57                 {
58                         antilag_takeback(it, it, time - lag);
59                 });
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                 FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_restore(it, CS(it)));
72                 IL_EACH(g_monsters, it != forent,
73                 {
74                         antilag_restore(it, it);
75                 });
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));
147                         LOG_TRACE("  Nudging gets us nowhere at ", vtos(pos));
148                         LOG_TRACE("  trace_endpos is ", vtos(trace_endpos));
149                         LOG_TRACE("  trace distance is ", ftos(vlen(pos - trace_endpos)));
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 vec = mindist * '1 0 0';
210         int c = 0;
211         while (c < 6)
212         {
213                 traceline (org, org + vec, true, NULL);
214                 vec = vec * -1;
215                 if (trace_fraction < 1)
216                 {
217                         vector loc = trace_endpos;
218                         traceline (loc, loc + vec, true, NULL);
219                         if (trace_fraction >= 1)
220                                 org = loc + vec;
221                 }
222                 if (c & 1)
223                 {
224                         float h = vec.y;
225                         vec.y = vec.x;
226                         vec.x = vec.z;
227                         vec.z = h;
228                 }
229                 c = c + 1;
230         }
231
232         return org;
233 }
234
235 bool LOD_customize(entity this, entity client)
236 {
237         if(autocvar_loddebug)
238         {
239                 int d = autocvar_loddebug;
240                 if(d == 1)
241                         this.modelindex = this.lodmodelindex0;
242                 else if(d == 2 || !this.lodmodelindex2)
243                         this.modelindex = this.lodmodelindex1;
244                 else // if(d == 3)
245                         this.modelindex = this.lodmodelindex2;
246                 return true;
247         }
248
249         // TODO csqc network this so it only gets sent once
250         vector near_point = NearestPointOnBox(this, client.origin);
251         if(vdist(near_point - client.origin, <, this.loddistance1))
252                 this.modelindex = this.lodmodelindex0;
253         else if(!this.lodmodelindex2 || vdist(near_point - client.origin, <, this.loddistance2))
254                 this.modelindex = this.lodmodelindex1;
255         else
256                 this.modelindex = this.lodmodelindex2;
257
258         return true;
259 }
260
261 void LOD_uncustomize(entity this)
262 {
263         this.modelindex = this.lodmodelindex0;
264 }
265
266 void LODmodel_attach(entity this)
267 {
268         entity e;
269
270         if(!this.loddistance1)
271                 this.loddistance1 = 1000;
272         if(!this.loddistance2)
273                 this.loddistance2 = 2000;
274         this.lodmodelindex0 = this.modelindex;
275
276         if(this.lodtarget1 != "")
277         {
278                 e = find(NULL, targetname, this.lodtarget1);
279                 if(e)
280                 {
281                         this.lodmodel1 = e.model;
282                         delete(e);
283                 }
284         }
285         if(this.lodtarget2 != "")
286         {
287                 e = find(NULL, targetname, this.lodtarget2);
288                 if(e)
289                 {
290                         this.lodmodel2 = e.model;
291                         delete(e);
292                 }
293         }
294
295         if(autocvar_loddebug < 0)
296         {
297                 this.lodmodel1 = this.lodmodel2 = ""; // don't even initialize
298         }
299
300         if(this.lodmodel1 != "")
301         {
302                 vector mi, ma;
303                 mi = this.mins;
304                 ma = this.maxs;
305
306                 precache_model(this.lodmodel1);
307                 _setmodel(this, this.lodmodel1);
308                 this.lodmodelindex1 = this.modelindex;
309
310                 if(this.lodmodel2 != "")
311                 {
312                         precache_model(this.lodmodel2);
313                         _setmodel(this, this.lodmodel2);
314                         this.lodmodelindex2 = this.modelindex;
315                 }
316
317                 this.modelindex = this.lodmodelindex0;
318                 setsize(this, mi, ma);
319         }
320
321         if(this.lodmodelindex1)
322                 if (!getSendEntity(this))
323                         SetCustomizer(this, LOD_customize, LOD_uncustomize);
324 }
325
326 void ApplyMinMaxScaleAngles(entity e)
327 {
328         if(e.angles.x != 0 || e.angles.z != 0 || e.avelocity.x != 0 || e.avelocity.z != 0) // "weird" rotation
329         {
330                 e.maxs = '1 1 1' * vlen(
331                         '1 0 0' * max(-e.mins.x, e.maxs.x) +
332                         '0 1 0' * max(-e.mins.y, e.maxs.y) +
333                         '0 0 1' * max(-e.mins.z, e.maxs.z)
334                 );
335                 e.mins = -e.maxs;
336         }
337         else if(e.angles.y != 0 || e.avelocity.y != 0) // yaw only is a bit better
338         {
339                 e.maxs_x = vlen(
340                         '1 0 0' * max(-e.mins.x, e.maxs.x) +
341                         '0 1 0' * max(-e.mins.y, e.maxs.y)
342                 );
343                 e.maxs_y = e.maxs.x;
344                 e.mins_x = -e.maxs.x;
345                 e.mins_y = -e.maxs.x;
346         }
347         if(e.scale)
348                 setsize(e, e.mins * e.scale, e.maxs * e.scale);
349         else
350                 setsize(e, e.mins, e.maxs);
351 }
352
353 void SetBrushEntityModel(entity this)
354 {
355         if(this.model != "")
356         {
357                 precache_model(this.model);
358                 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
359                 {
360                         vector mi = this.mins;
361                         vector ma = this.maxs;
362                         _setmodel(this, this.model); // no precision needed
363                         setsize(this, mi, ma);
364                 }
365                 else
366                         _setmodel(this, this.model); // no precision needed
367                 InitializeEntity(this, LODmodel_attach, INITPRIO_FINDTARGET);
368         }
369         setorigin(this, this.origin);
370         ApplyMinMaxScaleAngles(this);
371 }
372
373 void SetBrushEntityModelNoLOD(entity this)
374 {
375         if(this.model != "")
376         {
377                 precache_model(this.model);
378                 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
379                 {
380                         vector mi = this.mins;
381                         vector ma = this.maxs;
382                         _setmodel(this, this.model); // no precision needed
383                         setsize(this, mi, ma);
384                 }
385                 else
386                         _setmodel(this, this.model); // no precision needed
387         }
388         setorigin(this, this.origin);
389         ApplyMinMaxScaleAngles(this);
390 }
391
392 /*
393 ================
394 InitTrigger
395 ================
396 */
397
398 void SetMovedir(entity this)
399 {
400         if(this.movedir != '0 0 0')
401                 this.movedir = normalize(this.movedir);
402         else
403         {
404                 makevectors(this.angles);
405                 this.movedir = v_forward;
406         }
407
408         this.angles = '0 0 0';
409 }
410
411 void InitTrigger(entity this)
412 {
413 // trigger angles are used for one-way touches.  An angle of 0 is assumed
414 // to mean no restrictions, so use a yaw of 360 instead.
415         SetMovedir(this);
416         this.solid = SOLID_TRIGGER;
417         SetBrushEntityModel(this);
418         set_movetype(this, MOVETYPE_NONE);
419         this.modelindex = 0;
420         this.model = "";
421 }
422
423 void InitSolidBSPTrigger(entity this)
424 {
425 // trigger angles are used for one-way touches.  An angle of 0 is assumed
426 // to mean no restrictions, so use a yaw of 360 instead.
427         SetMovedir(this);
428         this.solid = SOLID_BSP;
429         SetBrushEntityModel(this);
430         set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
431 //      this.modelindex = 0;
432         this.model = "";
433 }
434
435 bool InitMovingBrushTrigger(entity this)
436 {
437 // trigger angles are used for one-way touches.  An angle of 0 is assumed
438 // to mean no restrictions, so use a yaw of 360 instead.
439         this.solid = SOLID_BSP;
440         SetBrushEntityModel(this);
441         set_movetype(this, MOVETYPE_PUSH);
442         if(this.modelindex == 0)
443         {
444                 objerror(this, "InitMovingBrushTrigger: no brushes found!");
445                 return false;
446         }
447         return true;
448 }