3 #include <server/defs.qh>
4 #include <server/miscfunctions.qh>
6 #include "command/common.qh"
7 #include "../common/state.qh"
8 #include "../lib/warpzone/common.qh"
9 #include "../common/triggers/subs.qh"
14 // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
21 unused but required by the engine
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.
39 void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz)
41 // check whether antilagged traces are enabled
44 if (!IS_REAL_CLIENT(forent))
45 lag = 0; // only antilag for clients
47 // change shooter to SOLID_BBOX so the shot can hit corpses
48 int oldsolid = source.dphitcontentsmask;
50 source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
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,
58 antilag_takeback(it, it, time - lag);
64 WarpZone_TraceBox (v1, mi, ma, v2, nomonst, forent);
66 tracebox (v1, mi, ma, v2, nomonst, forent);
68 // restore players to current positions
71 FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_restore(it, CS(it)));
72 IL_EACH(g_monsters, it != forent,
74 antilag_restore(it, it);
78 // restore shooter solid type
80 source.dphitcontentsmask = oldsolid;
82 void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
84 tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, false);
86 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
88 bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
89 if (autocvar_g_antilag != 2 || noantilag)
91 traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
93 void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
95 bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
96 if (autocvar_g_antilag != 2 || noantilag)
98 tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, false);
100 void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
102 tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, true);
104 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
106 bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
107 if (autocvar_g_antilag != 2 || noantilag)
109 WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
111 void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
113 bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
114 if (autocvar_g_antilag != 2 || noantilag)
116 tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, true);
119 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
125 //nudge = 2 * cvar("collision_impactnudge"); // why not?
128 dir = normalize(v2 - v1);
130 pos = v1 + dir * nudge;
137 if(pos * dir >= v2 * dir)
145 tracebox(pos, mi, ma, v2, nomonsters, forent);
150 LOG_TRACE("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2));
151 LOG_TRACE(" Nudging gets us nowhere at ", vtos(pos));
152 LOG_TRACE(" trace_endpos is ", vtos(trace_endpos));
153 LOG_TRACE(" trace distance is ", ftos(vlen(pos - trace_endpos)));
156 stopentity = trace_ent;
160 // we started inside solid.
161 // then trace from endpos to pos
163 tracebox(t, mi, ma, pos, nomonsters, forent);
167 // t is still inside solid? bad
168 // force advance, then, and retry
169 pos = t + dir * nudge;
171 // but if we hit an entity, stop RIGHT before it
172 if(stopatentity && stopentity && stopentity != ignorestopatentity)
174 trace_ent = stopentity;
176 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
182 // we actually LEFT solid!
183 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
189 // pos is outside solid?!? but why?!? never mind, just return it.
191 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
197 void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity)
199 tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity);
206 Returns a point at least 12 units away from walls
207 (useful for explosion animations, although the blast is performed where it really happened)
211 vector findbetterlocation (vector org, float mindist)
213 vector vec = mindist * '1 0 0';
217 traceline (org, org + vec, true, NULL);
219 if (trace_fraction < 1)
221 vector loc = trace_endpos;
222 traceline (loc, loc + vec, true, NULL);
223 if (trace_fraction >= 1)
239 bool LOD_customize(entity this, entity client)
241 if(autocvar_loddebug)
243 int d = autocvar_loddebug;
245 this.modelindex = this.lodmodelindex0;
246 else if(d == 2 || !this.lodmodelindex2)
247 this.modelindex = this.lodmodelindex1;
249 this.modelindex = this.lodmodelindex2;
253 // TODO csqc network this so it only gets sent once
254 vector near_point = NearestPointOnBox(this, client.origin);
255 if(vdist(near_point - client.origin, <, this.loddistance1))
256 this.modelindex = this.lodmodelindex0;
257 else if(!this.lodmodelindex2 || vdist(near_point - client.origin, <, this.loddistance2))
258 this.modelindex = this.lodmodelindex1;
260 this.modelindex = this.lodmodelindex2;
265 void LOD_uncustomize(entity this)
267 this.modelindex = this.lodmodelindex0;
270 void LODmodel_attach(entity this)
274 if(!this.loddistance1)
275 this.loddistance1 = 1000;
276 if(!this.loddistance2)
277 this.loddistance2 = 2000;
278 this.lodmodelindex0 = this.modelindex;
280 if(this.lodtarget1 != "")
282 e = find(NULL, targetname, this.lodtarget1);
285 this.lodmodel1 = e.model;
289 if(this.lodtarget2 != "")
291 e = find(NULL, targetname, this.lodtarget2);
294 this.lodmodel2 = e.model;
299 if(autocvar_loddebug < 0)
301 this.lodmodel1 = this.lodmodel2 = ""; // don't even initialize
304 if(this.lodmodel1 != "")
310 precache_model(this.lodmodel1);
311 _setmodel(this, this.lodmodel1);
312 this.lodmodelindex1 = this.modelindex;
314 if(this.lodmodel2 != "")
316 precache_model(this.lodmodel2);
317 _setmodel(this, this.lodmodel2);
318 this.lodmodelindex2 = this.modelindex;
321 this.modelindex = this.lodmodelindex0;
322 setsize(this, mi, ma);
325 if(this.lodmodelindex1)
326 if (!getSendEntity(this))
327 SetCustomizer(this, LOD_customize, LOD_uncustomize);
330 void ApplyMinMaxScaleAngles(entity e)
332 if(e.angles.x != 0 || e.angles.z != 0 || e.avelocity.x != 0 || e.avelocity.z != 0) // "weird" rotation
334 e.maxs = '1 1 1' * vlen(
335 '1 0 0' * max(-e.mins.x, e.maxs.x) +
336 '0 1 0' * max(-e.mins.y, e.maxs.y) +
337 '0 0 1' * max(-e.mins.z, e.maxs.z)
341 else if(e.angles.y != 0 || e.avelocity.y != 0) // yaw only is a bit better
344 '1 0 0' * max(-e.mins.x, e.maxs.x) +
345 '0 1 0' * max(-e.mins.y, e.maxs.y)
348 e.mins_x = -e.maxs.x;
349 e.mins_y = -e.maxs.x;
352 setsize(e, e.mins * e.scale, e.maxs * e.scale);
354 setsize(e, e.mins, e.maxs);
357 void SetBrushEntityModel(entity this)
361 precache_model(this.model);
362 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
364 vector mi = this.mins;
365 vector ma = this.maxs;
366 _setmodel(this, this.model); // no precision needed
367 setsize(this, mi, ma);
370 _setmodel(this, this.model); // no precision needed
371 InitializeEntity(this, LODmodel_attach, INITPRIO_FINDTARGET);
373 setorigin(this, this.origin);
374 ApplyMinMaxScaleAngles(this);
377 void SetBrushEntityModelNoLOD(entity this)
381 precache_model(this.model);
382 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
384 vector mi = this.mins;
385 vector ma = this.maxs;
386 _setmodel(this, this.model); // no precision needed
387 setsize(this, mi, ma);
390 _setmodel(this, this.model); // no precision needed
392 setorigin(this, this.origin);
393 ApplyMinMaxScaleAngles(this);
402 void SetMovedir(entity this)
404 if(this.movedir != '0 0 0')
405 this.movedir = normalize(this.movedir);
408 makevectors(this.angles);
409 this.movedir = v_forward;
412 this.angles = '0 0 0';
415 void InitTrigger(entity this)
417 // trigger angles are used for one-way touches. An angle of 0 is assumed
418 // to mean no restrictions, so use a yaw of 360 instead.
420 this.solid = SOLID_TRIGGER;
421 SetBrushEntityModel(this);
422 set_movetype(this, MOVETYPE_NONE);
427 void InitSolidBSPTrigger(entity this)
429 // trigger angles are used for one-way touches. An angle of 0 is assumed
430 // to mean no restrictions, so use a yaw of 360 instead.
432 this.solid = SOLID_BSP;
433 SetBrushEntityModel(this);
434 set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
435 // this.modelindex = 0;
439 bool InitMovingBrushTrigger(entity this)
441 // trigger angles are used for one-way touches. An angle of 0 is assumed
442 // to mean no restrictions, so use a yaw of 360 instead.
443 this.solid = SOLID_BSP;
444 SetBrushEntityModel(this);
445 set_movetype(this, MOVETYPE_PUSH);
446 if(this.modelindex == 0)
448 objerror(this, "InitMovingBrushTrigger: no brushes found!");