4 #include "command/common.qh"
5 #include "../common/state.qh"
6 #include "../lib/warpzone/common.qh"
7 #include "../common/triggers/subs.qh"
12 // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
19 unused but required by the engine
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.
37 void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz)
39 // check whether antilagged traces are enabled
42 if (!IS_REAL_CLIENT(forent))
43 lag = 0; // only antilag for clients
45 // change shooter to SOLID_BBOX so the shot can hit corpses
46 int oldsolid = source.dphitcontentsmask;
48 source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
52 // take players back into the past
53 FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_takeback(it, CS(it), time - lag));
54 FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, {
56 antilag_takeback(it, it, time - lag);
62 WarpZone_TraceBox (v1, mi, ma, v2, nomonst, forent);
64 tracebox (v1, mi, ma, v2, nomonst, forent);
66 // restore players to current positions
69 FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_restore(it, CS(it)));
70 FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, {
72 antilag_restore(it, it);
76 // restore shooter solid type
78 source.dphitcontentsmask = oldsolid;
80 void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
82 tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, false);
84 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
86 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
88 traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
90 void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
92 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
94 tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, false);
96 void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
98 tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, true);
100 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
102 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
104 WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
106 void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
108 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
110 tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, true);
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
119 //nudge = 2 * cvar("collision_impactnudge"); // why not?
122 dir = normalize(v2 - v1);
124 pos = v1 + dir * nudge;
131 if(pos * dir >= v2 * dir)
139 tracebox(pos, mi, ma, v2, nomonsters, forent);
144 LOG_TRACE("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2), "\n");
145 LOG_TRACE(" Nudging gets us nowhere at ", vtos(pos), "\n");
146 LOG_TRACE(" trace_endpos is ", vtos(trace_endpos), "\n");
147 LOG_TRACE(" trace distance is ", ftos(vlen(pos - trace_endpos)), "\n");
150 stopentity = trace_ent;
154 // we started inside solid.
155 // then trace from endpos to pos
157 tracebox(t, mi, ma, pos, nomonsters, forent);
161 // t is still inside solid? bad
162 // force advance, then, and retry
163 pos = t + dir * nudge;
165 // but if we hit an entity, stop RIGHT before it
166 if(stopatentity && stopentity && stopentity != ignorestopatentity)
168 trace_ent = stopentity;
170 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
176 // we actually LEFT solid!
177 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
183 // pos is outside solid?!? but why?!? never mind, just return it.
185 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
191 void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity)
193 tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity);
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)
205 vector findbetterlocation (vector org, float mindist)
211 vec = mindist * '1 0 0';
215 traceline (org, org + vec, true, NULL);
217 if (trace_fraction < 1)
220 traceline (loc, loc + vec, true, NULL);
221 if (trace_fraction >= 1)
237 bool LOD_customize(entity this, entity client)
239 if(autocvar_loddebug)
241 int d = autocvar_loddebug;
243 this.modelindex = this.lodmodelindex0;
244 else if(d == 2 || !this.lodmodelindex2)
245 this.modelindex = this.lodmodelindex1;
247 this.modelindex = this.lodmodelindex2;
251 // TODO csqc network this so it only gets sent once
252 vector near_point = NearestPointOnBox(this, client.origin);
253 if(vdist(near_point - client.origin, <, this.loddistance1))
254 this.modelindex = this.lodmodelindex0;
255 else if(!this.lodmodelindex2 || vdist(near_point - client.origin, <, this.loddistance2))
256 this.modelindex = this.lodmodelindex1;
258 this.modelindex = this.lodmodelindex2;
263 void LOD_uncustomize(entity this)
265 this.modelindex = this.lodmodelindex0;
268 void LODmodel_attach(entity this)
272 if(!this.loddistance1)
273 this.loddistance1 = 1000;
274 if(!this.loddistance2)
275 this.loddistance2 = 2000;
276 this.lodmodelindex0 = this.modelindex;
278 if(this.lodtarget1 != "")
280 e = find(NULL, targetname, this.lodtarget1);
283 this.lodmodel1 = e.model;
287 if(this.lodtarget2 != "")
289 e = find(NULL, targetname, this.lodtarget2);
292 this.lodmodel2 = e.model;
297 if(autocvar_loddebug < 0)
299 this.lodmodel1 = this.lodmodel2 = ""; // don't even initialize
302 if(this.lodmodel1 != "")
308 precache_model(this.lodmodel1);
309 _setmodel(this, this.lodmodel1);
310 this.lodmodelindex1 = this.modelindex;
312 if(this.lodmodel2 != "")
314 precache_model(this.lodmodel2);
315 _setmodel(this, this.lodmodel2);
316 this.lodmodelindex2 = this.modelindex;
319 this.modelindex = this.lodmodelindex0;
320 setsize(this, mi, ma);
323 if(this.lodmodelindex1)
324 if (!getSendEntity(this))
325 SetCustomizer(this, LOD_customize, LOD_uncustomize);
328 void ApplyMinMaxScaleAngles(entity e)
330 if(e.angles.x != 0 || e.angles.z != 0 || e.avelocity.x != 0 || e.avelocity.z != 0) // "weird" rotation
332 e.maxs = '1 1 1' * vlen(
333 '1 0 0' * max(-e.mins.x, e.maxs.x) +
334 '0 1 0' * max(-e.mins.y, e.maxs.y) +
335 '0 0 1' * max(-e.mins.z, e.maxs.z)
339 else if(e.angles.y != 0 || e.avelocity.y != 0) // yaw only is a bit better
342 '1 0 0' * max(-e.mins.x, e.maxs.x) +
343 '0 1 0' * max(-e.mins.y, e.maxs.y)
346 e.mins_x = -e.maxs.x;
347 e.mins_y = -e.maxs.x;
350 setsize(e, e.mins * e.scale, e.maxs * e.scale);
352 setsize(e, e.mins, e.maxs);
355 void SetBrushEntityModel(entity this)
359 precache_model(this.model);
360 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
362 vector mi = this.mins;
363 vector ma = this.maxs;
364 _setmodel(this, this.model); // no precision needed
365 setsize(this, mi, ma);
368 _setmodel(this, this.model); // no precision needed
369 InitializeEntity(this, LODmodel_attach, INITPRIO_FINDTARGET);
371 setorigin(this, this.origin);
372 ApplyMinMaxScaleAngles(this);
375 void SetBrushEntityModelNoLOD(entity this)
379 precache_model(this.model);
380 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
382 vector mi = this.mins;
383 vector ma = this.maxs;
384 _setmodel(this, this.model); // no precision needed
385 setsize(this, mi, ma);
388 _setmodel(this, this.model); // no precision needed
390 setorigin(this, this.origin);
391 ApplyMinMaxScaleAngles(this);
400 void SetMovedir(entity this)
402 if(this.movedir != '0 0 0')
403 this.movedir = normalize(this.movedir);
406 makevectors(this.angles);
407 this.movedir = v_forward;
410 this.angles = '0 0 0';
413 void InitTrigger(entity this)
415 // trigger angles are used for one-way touches. An angle of 0 is assumed
416 // to mean no restrictions, so use a yaw of 360 instead.
418 this.solid = SOLID_TRIGGER;
419 SetBrushEntityModel(this);
420 set_movetype(this, MOVETYPE_NONE);
425 void InitSolidBSPTrigger(entity this)
427 // trigger angles are used for one-way touches. An angle of 0 is assumed
428 // to mean no restrictions, so use a yaw of 360 instead.
430 this.solid = SOLID_BSP;
431 SetBrushEntityModel(this);
432 set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
433 // this.modelindex = 0;
437 bool InitMovingBrushTrigger(entity this)
439 // trigger angles are used for one-way touches. An angle of 0 is assumed
440 // to mean no restrictions, so use a yaw of 360 instead.
441 this.solid = SOLID_BSP;
442 SetBrushEntityModel(this);
443 set_movetype(this, MOVETYPE_PUSH);
444 if(this.modelindex == 0)
446 objerror(this, "InitMovingBrushTrigger: no brushes found!");