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 IL_EACH(g_monsters, it != forent,
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 IL_EACH(g_monsters, it != forent,
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));
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)));
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)
207 vector vec = mindist * '1 0 0';
211 traceline (org, org + vec, true, NULL);
213 if (trace_fraction < 1)
215 vector loc = trace_endpos;
216 traceline (loc, loc + vec, true, NULL);
217 if (trace_fraction >= 1)
233 bool LOD_customize(entity this, entity client)
235 if(autocvar_loddebug)
237 int d = autocvar_loddebug;
239 this.modelindex = this.lodmodelindex0;
240 else if(d == 2 || !this.lodmodelindex2)
241 this.modelindex = this.lodmodelindex1;
243 this.modelindex = this.lodmodelindex2;
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;
254 this.modelindex = this.lodmodelindex2;
259 void LOD_uncustomize(entity this)
261 this.modelindex = this.lodmodelindex0;
264 void LODmodel_attach(entity this)
268 if(!this.loddistance1)
269 this.loddistance1 = 1000;
270 if(!this.loddistance2)
271 this.loddistance2 = 2000;
272 this.lodmodelindex0 = this.modelindex;
274 if(this.lodtarget1 != "")
276 e = find(NULL, targetname, this.lodtarget1);
279 this.lodmodel1 = e.model;
283 if(this.lodtarget2 != "")
285 e = find(NULL, targetname, this.lodtarget2);
288 this.lodmodel2 = e.model;
293 if(autocvar_loddebug < 0)
295 this.lodmodel1 = this.lodmodel2 = ""; // don't even initialize
298 if(this.lodmodel1 != "")
304 precache_model(this.lodmodel1);
305 _setmodel(this, this.lodmodel1);
306 this.lodmodelindex1 = this.modelindex;
308 if(this.lodmodel2 != "")
310 precache_model(this.lodmodel2);
311 _setmodel(this, this.lodmodel2);
312 this.lodmodelindex2 = this.modelindex;
315 this.modelindex = this.lodmodelindex0;
316 setsize(this, mi, ma);
319 if(this.lodmodelindex1)
320 if (!getSendEntity(this))
321 SetCustomizer(this, LOD_customize, LOD_uncustomize);
324 void ApplyMinMaxScaleAngles(entity e)
326 if(e.angles.x != 0 || e.angles.z != 0 || e.avelocity.x != 0 || e.avelocity.z != 0) // "weird" rotation
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)
335 else if(e.angles.y != 0 || e.avelocity.y != 0) // yaw only is a bit better
338 '1 0 0' * max(-e.mins.x, e.maxs.x) +
339 '0 1 0' * max(-e.mins.y, e.maxs.y)
342 e.mins_x = -e.maxs.x;
343 e.mins_y = -e.maxs.x;
346 setsize(e, e.mins * e.scale, e.maxs * e.scale);
348 setsize(e, e.mins, e.maxs);
351 void SetBrushEntityModel(entity this)
355 precache_model(this.model);
356 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
358 vector mi = this.mins;
359 vector ma = this.maxs;
360 _setmodel(this, this.model); // no precision needed
361 setsize(this, mi, ma);
364 _setmodel(this, this.model); // no precision needed
365 InitializeEntity(this, LODmodel_attach, INITPRIO_FINDTARGET);
367 setorigin(this, this.origin);
368 ApplyMinMaxScaleAngles(this);
371 void SetBrushEntityModelNoLOD(entity this)
375 precache_model(this.model);
376 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
378 vector mi = this.mins;
379 vector ma = this.maxs;
380 _setmodel(this, this.model); // no precision needed
381 setsize(this, mi, ma);
384 _setmodel(this, this.model); // no precision needed
386 setorigin(this, this.origin);
387 ApplyMinMaxScaleAngles(this);
396 void SetMovedir(entity this)
398 if(this.movedir != '0 0 0')
399 this.movedir = normalize(this.movedir);
402 makevectors(this.angles);
403 this.movedir = v_forward;
406 this.angles = '0 0 0';
409 void InitTrigger(entity this)
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.
414 this.solid = SOLID_TRIGGER;
415 SetBrushEntityModel(this);
416 set_movetype(this, MOVETYPE_NONE);
421 void InitSolidBSPTrigger(entity this)
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.
426 this.solid = SOLID_BSP;
427 SetBrushEntityModel(this);
428 set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
429 // this.modelindex = 0;
433 bool InitMovingBrushTrigger(entity this)
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)
442 objerror(this, "InitMovingBrushTrigger: no brushes found!");