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 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
90 traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
92 void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
94 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
96 tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, false);
98 void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
100 tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, true);
102 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
104 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
106 WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
108 void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
110 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
112 tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, true);
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
121 //nudge = 2 * cvar("collision_impactnudge"); // why not?
124 dir = normalize(v2 - v1);
126 pos = v1 + dir * nudge;
133 if(pos * dir >= v2 * dir)
141 tracebox(pos, mi, ma, v2, nomonsters, forent);
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)));
152 stopentity = trace_ent;
156 // we started inside solid.
157 // then trace from endpos to pos
159 tracebox(t, mi, ma, pos, nomonsters, forent);
163 // t is still inside solid? bad
164 // force advance, then, and retry
165 pos = t + dir * nudge;
167 // but if we hit an entity, stop RIGHT before it
168 if(stopatentity && stopentity && stopentity != ignorestopatentity)
170 trace_ent = stopentity;
172 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
178 // we actually LEFT solid!
179 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
185 // pos is outside solid?!? but why?!? never mind, just return it.
187 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
193 void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity)
195 tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity);
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)
207 vector findbetterlocation (vector org, float mindist)
209 vector vec = mindist * '1 0 0';
213 traceline (org, org + vec, true, NULL);
215 if (trace_fraction < 1)
217 vector loc = trace_endpos;
218 traceline (loc, loc + vec, true, NULL);
219 if (trace_fraction >= 1)
235 bool LOD_customize(entity this, entity client)
237 if(autocvar_loddebug)
239 int d = autocvar_loddebug;
241 this.modelindex = this.lodmodelindex0;
242 else if(d == 2 || !this.lodmodelindex2)
243 this.modelindex = this.lodmodelindex1;
245 this.modelindex = this.lodmodelindex2;
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;
256 this.modelindex = this.lodmodelindex2;
261 void LOD_uncustomize(entity this)
263 this.modelindex = this.lodmodelindex0;
266 void LODmodel_attach(entity this)
270 if(!this.loddistance1)
271 this.loddistance1 = 1000;
272 if(!this.loddistance2)
273 this.loddistance2 = 2000;
274 this.lodmodelindex0 = this.modelindex;
276 if(this.lodtarget1 != "")
278 e = find(NULL, targetname, this.lodtarget1);
281 this.lodmodel1 = e.model;
285 if(this.lodtarget2 != "")
287 e = find(NULL, targetname, this.lodtarget2);
290 this.lodmodel2 = e.model;
295 if(autocvar_loddebug < 0)
297 this.lodmodel1 = this.lodmodel2 = ""; // don't even initialize
300 if(this.lodmodel1 != "")
306 precache_model(this.lodmodel1);
307 _setmodel(this, this.lodmodel1);
308 this.lodmodelindex1 = this.modelindex;
310 if(this.lodmodel2 != "")
312 precache_model(this.lodmodel2);
313 _setmodel(this, this.lodmodel2);
314 this.lodmodelindex2 = this.modelindex;
317 this.modelindex = this.lodmodelindex0;
318 setsize(this, mi, ma);
321 if(this.lodmodelindex1)
322 if (!getSendEntity(this))
323 SetCustomizer(this, LOD_customize, LOD_uncustomize);
326 void ApplyMinMaxScaleAngles(entity e)
328 if(e.angles.x != 0 || e.angles.z != 0 || e.avelocity.x != 0 || e.avelocity.z != 0) // "weird" rotation
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)
337 else if(e.angles.y != 0 || e.avelocity.y != 0) // yaw only is a bit better
340 '1 0 0' * max(-e.mins.x, e.maxs.x) +
341 '0 1 0' * max(-e.mins.y, e.maxs.y)
344 e.mins_x = -e.maxs.x;
345 e.mins_y = -e.maxs.x;
348 setsize(e, e.mins * e.scale, e.maxs * e.scale);
350 setsize(e, e.mins, e.maxs);
353 void SetBrushEntityModel(entity this)
357 precache_model(this.model);
358 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
360 vector mi = this.mins;
361 vector ma = this.maxs;
362 _setmodel(this, this.model); // no precision needed
363 setsize(this, mi, ma);
366 _setmodel(this, this.model); // no precision needed
367 InitializeEntity(this, LODmodel_attach, INITPRIO_FINDTARGET);
369 setorigin(this, this.origin);
370 ApplyMinMaxScaleAngles(this);
373 void SetBrushEntityModelNoLOD(entity this)
377 precache_model(this.model);
378 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
380 vector mi = this.mins;
381 vector ma = this.maxs;
382 _setmodel(this, this.model); // no precision needed
383 setsize(this, mi, ma);
386 _setmodel(this, this.model); // no precision needed
388 setorigin(this, this.origin);
389 ApplyMinMaxScaleAngles(this);
398 void SetMovedir(entity this)
400 if(this.movedir != '0 0 0')
401 this.movedir = normalize(this.movedir);
404 makevectors(this.angles);
405 this.movedir = v_forward;
408 this.angles = '0 0 0';
411 void InitTrigger(entity this)
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.
416 this.solid = SOLID_TRIGGER;
417 SetBrushEntityModel(this);
418 set_movetype(this, MOVETYPE_NONE);
423 void InitSolidBSPTrigger(entity this)
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.
428 this.solid = SOLID_BSP;
429 SetBrushEntityModel(this);
430 set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
431 // this.modelindex = 0;
435 bool InitMovingBrushTrigger(entity this)
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)
444 objerror(this, "InitMovingBrushTrigger: no brushes found!");