5 #include "command/common.qh"
6 #include "../warpzonelib/common.qh"
8 void spawnfunc_info_null (void)
11 // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
14 void setanim(entity e, vector anim, float looping, float override, float restart)
17 return; // no animation was given to us! We can't use this.
19 if (anim.x == e.animstate_startframe)
20 if (anim.y == e.animstate_numframes)
21 if (anim.z == e.animstate_framerate)
26 if(anim.y == 1) // ZYM animation
27 BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
32 e.animstate_startframe = anim.x;
33 e.animstate_numframes = anim.y;
34 e.animstate_framerate = anim.z;
35 e.animstate_starttime = servertime - 0.1 * serverframetime; // shift it a little bit into the past to prevent float inaccuracy hiccups
36 e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate;
37 e.animstate_looping = looping;
38 e.animstate_override = override;
39 e.frame = e.animstate_startframe;
40 e.frame1time = servertime;
43 void updateanim(entity e)
45 if (time >= e.animstate_endtime)
47 if (e.animstate_looping)
49 e.animstate_starttime = e.animstate_endtime;
50 e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate;
52 e.animstate_override = false;
54 e.frame = e.animstate_startframe + bound(0, (time - e.animstate_starttime) * e.animstate_framerate, e.animstate_numframes - 1);
55 //print(ftos(time), " -> ", ftos(e.frame), "\n");
62 unused but required by the engine
76 A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
77 Additionally it moves players back into the past before the trace and restores them afterward.
80 void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz)
85 // check whether antilagged traces are enabled
88 if (!IS_REAL_CLIENT(forent))
89 lag = 0; // only antilag for clients
91 // change shooter to SOLID_BBOX so the shot can hit corpses
92 oldsolid = source.dphitcontentsmask;
94 source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
98 // take players back into the past
99 FOR_EACH_PLAYER(player)
101 antilag_takeback(player, time - lag);
102 FOR_EACH_MONSTER(player)
103 antilag_takeback(player, time - lag);
108 WarpZone_TraceBox (v1, mi, ma, v2, nomonst, forent);
110 tracebox (v1, mi, ma, v2, nomonst, forent);
112 // restore players to current positions
115 FOR_EACH_PLAYER(player)
117 antilag_restore(player);
118 FOR_EACH_MONSTER(player)
119 antilag_restore(player);
122 // restore shooter solid type
124 source.dphitcontentsmask = oldsolid;
126 void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
128 tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, false);
130 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
132 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
134 traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
136 void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
138 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
140 tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, false);
142 void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
144 tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, true);
146 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
148 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
150 WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
152 void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
154 if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
156 tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, true);
159 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
165 //nudge = 2 * cvar("collision_impactnudge"); // why not?
168 dir = normalize(v2 - v1);
170 pos = v1 + dir * nudge;
177 if(pos * dir >= v2 * dir)
185 tracebox(pos, mi, ma, v2, nomonsters, forent);
190 LOG_TRACE("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2), "\n");
191 LOG_TRACE(" Nudging gets us nowhere at ", vtos(pos), "\n");
192 LOG_TRACE(" trace_endpos is ", vtos(trace_endpos), "\n");
193 LOG_TRACE(" trace distance is ", ftos(vlen(pos - trace_endpos)), "\n");
196 stopentity = trace_ent;
200 // we started inside solid.
201 // then trace from endpos to pos
203 tracebox(t, mi, ma, pos, nomonsters, forent);
207 // t is still inside solid? bad
208 // force advance, then, and retry
209 pos = t + dir * nudge;
211 // but if we hit an entity, stop RIGHT before it
212 if(stopatentity && stopentity && stopentity != ignorestopatentity)
214 trace_ent = stopentity;
216 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
222 // we actually LEFT solid!
223 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
229 // pos is outside solid?!? but why?!? never mind, just return it.
231 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
237 void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity)
239 tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity);
246 Returns a point at least 12 units away from walls
247 (useful for explosion animations, although the blast is performed where it really happened)
251 vector findbetterlocation (vector org, float mindist)
257 vec = mindist * '1 0 0';
261 traceline (org, org + vec, true, world);
263 if (trace_fraction < 1)
266 traceline (loc, loc + vec, true, world);
267 if (trace_fraction >= 1)
283 float LOD_customize()
287 if(autocvar_loddebug)
289 d = autocvar_loddebug;
291 self.modelindex = self.lodmodelindex0;
292 else if(d == 2 || !self.lodmodelindex2)
293 self.modelindex = self.lodmodelindex1;
295 self.modelindex = self.lodmodelindex2;
299 // TODO csqc network this so it only gets sent once
300 d = vlen(NearestPointOnBox(self, other.origin) - other.origin);
301 if(d < self.loddistance1)
302 self.modelindex = self.lodmodelindex0;
303 else if(!self.lodmodelindex2 || d < self.loddistance2)
304 self.modelindex = self.lodmodelindex1;
306 self.modelindex = self.lodmodelindex2;
311 void LOD_uncustomize()
313 self.modelindex = self.lodmodelindex0;
316 void LODmodel_attach()
320 if(!self.loddistance1)
321 self.loddistance1 = 1000;
322 if(!self.loddistance2)
323 self.loddistance2 = 2000;
324 self.lodmodelindex0 = self.modelindex;
326 if(self.lodtarget1 != "")
328 e = find(world, targetname, self.lodtarget1);
331 self.lodmodel1 = e.model;
335 if(self.lodtarget2 != "")
337 e = find(world, targetname, self.lodtarget2);
340 self.lodmodel2 = e.model;
345 if(autocvar_loddebug < 0)
347 self.lodmodel1 = self.lodmodel2 = ""; // don't even initialize
350 if(self.lodmodel1 != "")
356 precache_model(self.lodmodel1);
357 setmodel(self, self.lodmodel1);
358 self.lodmodelindex1 = self.modelindex;
360 if(self.lodmodel2 != "")
362 precache_model(self.lodmodel2);
363 setmodel(self, self.lodmodel2);
364 self.lodmodelindex2 = self.modelindex;
367 self.modelindex = self.lodmodelindex0;
368 setsize(self, mi, ma);
371 if(self.lodmodelindex1)
372 if (!self.SendEntity)
373 SetCustomizer(self, LOD_customize, LOD_uncustomize);
376 void ApplyMinMaxScaleAngles(entity e)
378 if(e.angles.x != 0 || e.angles.z != 0 || self.avelocity.x != 0 || self.avelocity.z != 0) // "weird" rotation
380 e.maxs = '1 1 1' * vlen(
381 '1 0 0' * max(-e.mins.x, e.maxs.x) +
382 '0 1 0' * max(-e.mins.y, e.maxs.y) +
383 '0 0 1' * max(-e.mins.z, e.maxs.z)
387 else if(e.angles.y != 0 || self.avelocity.y != 0) // yaw only is a bit better
390 '1 0 0' * max(-e.mins.x, e.maxs.x) +
391 '0 1 0' * max(-e.mins.y, e.maxs.y)
394 e.mins_x = -e.maxs.x;
395 e.mins_y = -e.maxs.x;
398 setsize(e, e.mins * e.scale, e.maxs * e.scale);
400 setsize(e, e.mins, e.maxs);
403 void SetBrushEntityModel()
407 precache_model(self.model);
408 if(self.mins != '0 0 0' || self.maxs != '0 0 0')
410 vector mi = self.mins;
411 vector ma = self.maxs;
412 setmodel(self, self.model); // no precision needed
413 setsize(self, mi, ma);
416 setmodel(self, self.model); // no precision needed
417 InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
419 setorigin(self, self.origin);
420 ApplyMinMaxScaleAngles(self);
423 void SetBrushEntityModelNoLOD()
427 precache_model(self.model);
428 if(self.mins != '0 0 0' || self.maxs != '0 0 0')
430 vector mi = self.mins;
431 vector ma = self.maxs;
432 setmodel(self, self.model); // no precision needed
433 setsize(self, mi, ma);
436 setmodel(self, self.model); // no precision needed
438 setorigin(self, self.origin);
439 ApplyMinMaxScaleAngles(self);
450 if (self.movedir != '0 0 0')
451 self.movedir = normalize(self.movedir);
454 makevectors (self.angles);
455 self.movedir = v_forward;
458 self.angles = '0 0 0';
463 // trigger angles are used for one-way touches. An angle of 0 is assumed
464 // to mean no restrictions, so use a yaw of 360 instead.
466 self.solid = SOLID_TRIGGER;
467 SetBrushEntityModel();
468 self.movetype = MOVETYPE_NONE;
473 void InitSolidBSPTrigger()
475 // trigger angles are used for one-way touches. An angle of 0 is assumed
476 // to mean no restrictions, so use a yaw of 360 instead.
478 self.solid = SOLID_BSP;
479 SetBrushEntityModel();
480 self.movetype = MOVETYPE_NONE; // why was this PUSH? -div0
481 // self.modelindex = 0;
485 float InitMovingBrushTrigger()
487 // trigger angles are used for one-way touches. An angle of 0 is assumed
488 // to mean no restrictions, so use a yaw of 360 instead.
489 self.solid = SOLID_BSP;
490 SetBrushEntityModel();
491 self.movetype = MOVETYPE_PUSH;
492 if(self.modelindex == 0)
494 objerror("InitMovingBrushTrigger: no brushes found!");