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 dprint("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2), "\n");
191 dprint(" Nudging gets us nowhere at ", vtos(pos), "\n");
192 dprint(" trace_endpos is ", vtos(trace_endpos), "\n");
193 dprint(" 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)
287 Returns a random number between -1.0 and 1.0
292 return 2 * (random () - 0.5);
297 Angc used for animations
302 float angc (float a1, float a2)
325 float LOD_customize()
329 if(autocvar_loddebug)
331 d = autocvar_loddebug;
333 self.modelindex = self.lodmodelindex0;
334 else if(d == 2 || !self.lodmodelindex2)
335 self.modelindex = self.lodmodelindex1;
337 self.modelindex = self.lodmodelindex2;
341 // TODO csqc network this so it only gets sent once
342 d = vlen(NearestPointOnBox(self, other.origin) - other.origin);
343 if(d < self.loddistance1)
344 self.modelindex = self.lodmodelindex0;
345 else if(!self.lodmodelindex2 || d < self.loddistance2)
346 self.modelindex = self.lodmodelindex1;
348 self.modelindex = self.lodmodelindex2;
353 void LOD_uncustomize()
355 self.modelindex = self.lodmodelindex0;
358 void LODmodel_attach()
362 if(!self.loddistance1)
363 self.loddistance1 = 1000;
364 if(!self.loddistance2)
365 self.loddistance2 = 2000;
366 self.lodmodelindex0 = self.modelindex;
368 if(self.lodtarget1 != "")
370 e = find(world, targetname, self.lodtarget1);
373 self.lodmodel1 = e.model;
377 if(self.lodtarget2 != "")
379 e = find(world, targetname, self.lodtarget2);
382 self.lodmodel2 = e.model;
387 if(autocvar_loddebug < 0)
389 self.lodmodel1 = self.lodmodel2 = ""; // don't even initialize
392 if(self.lodmodel1 != "")
398 precache_model(self.lodmodel1);
399 setmodel(self, self.lodmodel1);
400 self.lodmodelindex1 = self.modelindex;
402 if(self.lodmodel2 != "")
404 precache_model(self.lodmodel2);
405 setmodel(self, self.lodmodel2);
406 self.lodmodelindex2 = self.modelindex;
409 self.modelindex = self.lodmodelindex0;
410 setsize(self, mi, ma);
413 if(self.lodmodelindex1)
414 if (!self.SendEntity)
415 SetCustomizer(self, LOD_customize, LOD_uncustomize);
418 void ApplyMinMaxScaleAngles(entity e)
420 if(e.angles.x != 0 || e.angles.z != 0 || self.avelocity.x != 0 || self.avelocity.z != 0) // "weird" rotation
422 e.maxs = '1 1 1' * vlen(
423 '1 0 0' * max(-e.mins.x, e.maxs.x) +
424 '0 1 0' * max(-e.mins.y, e.maxs.y) +
425 '0 0 1' * max(-e.mins.z, e.maxs.z)
429 else if(e.angles.y != 0 || self.avelocity.y != 0) // yaw only is a bit better
432 '1 0 0' * max(-e.mins.x, e.maxs.x) +
433 '0 1 0' * max(-e.mins.y, e.maxs.y)
436 e.mins_x = -e.maxs.x;
437 e.mins_y = -e.maxs.x;
440 setsize(e, e.mins * e.scale, e.maxs * e.scale);
442 setsize(e, e.mins, e.maxs);
445 void SetBrushEntityModel()
449 precache_model(self.model);
450 if(self.mins != '0 0 0' || self.maxs != '0 0 0')
452 vector mi = self.mins;
453 vector ma = self.maxs;
454 setmodel(self, self.model); // no precision needed
455 setsize(self, mi, ma);
458 setmodel(self, self.model); // no precision needed
459 InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
461 setorigin(self, self.origin);
462 ApplyMinMaxScaleAngles(self);
465 void SetBrushEntityModelNoLOD()
469 precache_model(self.model);
470 if(self.mins != '0 0 0' || self.maxs != '0 0 0')
472 vector mi = self.mins;
473 vector ma = self.maxs;
474 setmodel(self, self.model); // no precision needed
475 setsize(self, mi, ma);
478 setmodel(self, self.model); // no precision needed
480 setorigin(self, self.origin);
481 ApplyMinMaxScaleAngles(self);
492 if (self.movedir != '0 0 0')
493 self.movedir = normalize(self.movedir);
496 makevectors (self.angles);
497 self.movedir = v_forward;
500 self.angles = '0 0 0';
505 // trigger angles are used for one-way touches. An angle of 0 is assumed
506 // to mean no restrictions, so use a yaw of 360 instead.
508 self.solid = SOLID_TRIGGER;
509 SetBrushEntityModel();
510 self.movetype = MOVETYPE_NONE;
515 void InitSolidBSPTrigger()
517 // trigger angles are used for one-way touches. An angle of 0 is assumed
518 // to mean no restrictions, so use a yaw of 360 instead.
520 self.solid = SOLID_BSP;
521 SetBrushEntityModel();
522 self.movetype = MOVETYPE_NONE; // why was this PUSH? -div0
523 // self.modelindex = 0;
527 float InitMovingBrushTrigger()
529 // trigger angles are used for one-way touches. An angle of 0 is assumed
530 // to mean no restrictions, so use a yaw of 360 instead.
531 self.solid = SOLID_BSP;
532 SetBrushEntityModel();
533 self.movetype = MOVETYPE_PUSH;
534 if(self.modelindex == 0)
536 objerror("InitMovingBrushTrigger: no brushes found!");