2 #include "../dpdefs/csprogsdefs.qh"
4 #include "../server/t_items.qh"
7 #include "../dpdefs/progsdefs.qh"
8 #include "../dpdefs/dpextensions.qh"
9 #include "../server/sys-post.qh"
11 #include "../common/weapons/weapons.qh"
14 void WarpZone_Accumulator_Clear(entity acc)
16 acc.warpzone_transform = '0 0 0';
17 acc.warpzone_shift = '0 0 0';
19 void WarpZone_Accumulator_AddTransform(entity acc, vector t, vector s)
22 tr = AnglesTransform_Multiply(t, acc.warpzone_transform);
23 st = AnglesTransform_Multiply_GetPostShift(t, s, acc.warpzone_transform, acc.warpzone_shift);
24 acc.warpzone_transform = tr;
25 acc.warpzone_shift = st;
27 void WarpZone_Accumulator_Add(entity acc, entity wz)
29 WarpZone_Accumulator_AddTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
31 void WarpZone_Accumulator_AddInverseTransform(entity acc, vector t, vector s)
34 tt = AnglesTransform_Invert(t);
35 ss = AnglesTransform_PrePostShift_GetPostShift(s, tt, '0 0 0');
36 WarpZone_Accumulator_AddTransform(acc, tt, ss);
37 // yes, this probably can be done simpler... but this way is "obvious" :)
39 void WarpZone_Accumulator_AddInverse(entity acc, entity wz)
41 WarpZone_Accumulator_AddInverseTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
44 .vector(vector, vector) camera_transform;
45 float autocvar_cl_warpzone_usetrace = 1;
46 vector WarpZone_camera_transform(vector org, vector ang)
49 if(self.warpzone_fadestart)
50 if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400)
52 // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
53 // unneeded on client, on server this helps a lot
57 org = WarpZone_TransformOrigin(self, org);
58 vf = WarpZone_TransformVelocity(self, vf);
59 vr = WarpZone_TransformVelocity(self, vr);
60 vu = WarpZone_TransformVelocity(self, vu);
61 if(autocvar_cl_warpzone_usetrace)
62 traceline(self.warpzone_targetorigin, org, MOVE_NOMONSTERS, world);
64 trace_endpos = self.warpzone_targetorigin;
71 void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
73 e.warpzone_transform = AnglesTransform_RightDivide(other_ang, AnglesTransform_TurnDirectionFR(my_ang));
74 e.warpzone_shift = AnglesTransform_PrePostShift_GetPostShift(my_org, e.warpzone_transform, other_org);
75 e.warpzone_origin = my_org;
76 e.warpzone_targetorigin = other_org;
77 e.warpzone_angles = my_ang;
78 e.warpzone_targetangles = other_ang;
79 fixedmakevectors(my_ang); e.warpzone_forward = v_forward;
80 fixedmakevectors(other_ang); e.warpzone_targetforward = v_forward;
81 e.camera_transform = WarpZone_camera_transform;
84 vector WarpZone_Camera_camera_transform(vector org, vector ang)
86 // a fixed camera view
87 if(self.warpzone_fadestart)
88 if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400)
90 // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
91 // unneeded on client, on server this helps a lot
92 trace_endpos = self.warpzone_origin;
93 makevectors(self.warpzone_angles);
94 return self.warpzone_origin;
97 void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang) // we assume that e.oldorigin and e.avelocity point to view origin and direction
99 e.warpzone_origin = my_org;
100 e.warpzone_angles = my_ang;
101 e.camera_transform = WarpZone_Camera_camera_transform;
106 vector WarpZoneLib_BoxTouchesBrush_mins;
107 vector WarpZoneLib_BoxTouchesBrush_maxs;
108 entity WarpZoneLib_BoxTouchesBrush_ent;
109 entity WarpZoneLib_BoxTouchesBrush_ignore;
110 float WarpZoneLib_BoxTouchesBrush_Recurse()
116 tracebox('0 0 0', WarpZoneLib_BoxTouchesBrush_mins, WarpZoneLib_BoxTouchesBrush_maxs, '0 0 0', MOVE_NOMONSTERS, WarpZoneLib_BoxTouchesBrush_ignore);
118 if (trace_networkentity)
120 dprint("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush\n");
121 // we cannot continue, as a player blocks us...
128 if (trace_ent == WarpZoneLib_BoxTouchesBrush_ent)
133 se.solid = SOLID_NOT;
134 f = WarpZoneLib_BoxTouchesBrush_Recurse();
140 float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
144 if(!e.modelindex || e.warpzone_isboxy)
149 WarpZoneLib_BoxTouchesBrush_mins = mi;
150 WarpZoneLib_BoxTouchesBrush_maxs = ma;
151 WarpZoneLib_BoxTouchesBrush_ent = e;
152 WarpZoneLib_BoxTouchesBrush_ignore = ig;
153 f = WarpZoneLib_BoxTouchesBrush_Recurse();
159 entity WarpZone_Find(vector mi, vector ma)
161 // if we are near any warpzone planes - MOVE AWAY (work around nearclip)
163 if(!warpzone_warpzones_exist)
165 for(e = world; (e = find(e, classname, "trigger_warpzone")); )
166 if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world))
171 void WarpZone_MakeAllSolid()
174 if(!warpzone_warpzones_exist)
176 for(e = world; (e = find(e, classname, "trigger_warpzone")); )
180 void WarpZone_MakeAllOther()
183 if(!warpzone_warpzones_exist)
185 for(e = world; (e = find(e, classname, "trigger_warpzone")); )
186 e.solid = SOLID_TRIGGER;
189 void WarpZone_Trace_InitTransform()
191 if(!WarpZone_trace_transform)
193 WarpZone_trace_transform = spawn();
194 WarpZone_trace_transform.classname = "warpzone_trace_transform";
196 WarpZone_Accumulator_Clear(WarpZone_trace_transform);
198 void WarpZone_Trace_AddTransform(entity wz)
200 WarpZone_Accumulator_Add(WarpZone_trace_transform, wz);
203 void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent, entity zone, WarpZone_trace_callback_t cb)
205 float nomonsters_adjusted;
212 WarpZone_trace_forent = forent;
213 WarpZone_trace_firstzone = world;
214 WarpZone_trace_lastzone = world;
215 WarpZone_Trace_InitTransform();
216 if(!warpzone_warpzones_exist)
218 if(nomonsters == MOVE_NOTHING)
223 cb(org, trace_endpos, end);
228 tracebox(org, mi, ma, end, nomonsters, WarpZone_trace_forent);
230 cb(org, trace_endpos, end);
245 nomonsters_adjusted = MOVE_NOMONSTERS;
248 nomonsters_adjusted = nomonsters;
251 if((contentshack = (WarpZone_trace_forent.dphitcontentsmask && !(WarpZone_trace_forent.dphitcontentsmask & DPCONTENTS_SOLID))))
252 BITSET_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
254 // if starting in warpzone, first transform
255 wz = WarpZone_Find(org + mi, org + ma);
258 WarpZone_trace_firstzone = wz;
259 WarpZone_trace_lastzone = wz;
260 if(zone && wz != zone)
262 // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
268 WarpZone_Trace_AddTransform(wz);
269 org = WarpZone_TransformOrigin(wz, org);
270 end = WarpZone_TransformOrigin(wz, end);
272 WarpZone_MakeAllSolid();
280 dprint("Too many warpzones in sequence, aborting trace.\n");
284 tracebox(org, mi, ma, end, nomonsters_adjusted, WarpZone_trace_forent);
286 cb(org, trace_endpos, end);
288 sol = trace_startsolid;
290 frac = trace_fraction = frac + (1 - frac) * trace_fraction;
291 if(trace_fraction >= 1)
293 if(trace_ent.classname != "trigger_warpzone")
295 if((nomonsters == MOVE_NOTHING) || ((nomonsters == MOVE_WORLDONLY) && trace_ent) || (contentshack && (trace_dphitcontents & WarpZone_trace_forent.dphitcontentsmask) == DPCONTENTS_SOLID))
297 // continue the trace, ignoring this hit (we only care for warpzones)
298 org = trace_endpos + normalize(end - org);
300 // we cannot do an inverted trace here, as we do care for further warpzones inside that "solid" to be found
301 // otherwise, players could block entrances that way
307 // FIXME can this check be removed? Do we really need it?
308 dprint("I transformed into the same zone again, wtf, aborting the trace\n");
313 if(!WarpZone_trace_firstzone)
314 WarpZone_trace_firstzone = wz;
315 WarpZone_trace_lastzone = wz;
316 if(zone && wz != zone)
318 WarpZone_Trace_AddTransform(wz);
319 // we hit a warpzone... so, let's perform the trace after the warp again
320 org = WarpZone_TransformOrigin(wz, trace_endpos);
321 end = WarpZone_TransformOrigin(wz, end);
323 // we got warped, so let's step back a bit
324 tracebox(org, mi, ma, org + normalize(org - end) * 32, nomonsters_adjusted, WarpZone_trace_forent);
327 WarpZone_MakeAllOther();
330 BITCLR_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
331 trace_startsolid = sol;
337 void WarpZone_TraceBox(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent)
339 WarpZone_TraceBox_ThroughZone(org, mi, ma, end, nomonsters, forent, world, WarpZone_trace_callback_t_null);
342 void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
344 WarpZone_TraceBox(org, '0 0 0', '0 0 0', end, nomonsters, forent);
347 void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZone_trace_callback_t cb)
350 vector vf, vr, vu, v0, o0;
355 g = cvar("sv_gravity") * e.gravity;
357 WarpZone_trace_forent = forent;
358 WarpZone_trace_firstzone = world;
359 WarpZone_trace_lastzone = world;
360 WarpZone_Trace_InitTransform();
361 WarpZone_tracetoss_time = 0;
362 if(!warpzone_warpzones_exist)
364 tracetoss(e, WarpZone_trace_forent);
366 cb(e.origin, trace_endpos, trace_endpos);
367 dt = vlen(e.origin - o0) / vlen(e.velocity);
368 WarpZone_tracetoss_time += dt;
369 e.velocity_z -= dt * g;
370 WarpZone_tracetoss_velocity = e.velocity;
379 // if starting in warpzone, first transform
380 wz = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
383 WarpZone_trace_firstzone = wz;
384 WarpZone_trace_lastzone = wz;
385 if(zone && wz != zone)
387 // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
389 WarpZone_tracetoss_time = 0;
393 WarpZone_Trace_AddTransform(wz);
394 setorigin(e, WarpZone_TransformOrigin(wz, e.origin));
395 e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
397 WarpZone_MakeAllSolid();
403 dprint("Too many warpzones in sequence, aborting trace.\n");
407 tracetoss(e, WarpZone_trace_forent);
409 cb(e.origin, trace_endpos, trace_endpos);
410 dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
411 WarpZone_tracetoss_time += dt;
412 e.origin = trace_endpos;
413 e.velocity_z -= dt * g;
414 if(trace_fraction >= 1)
416 if(trace_ent.classname != "trigger_warpzone")
420 // FIXME can this check be removed? Do we really need it?
421 dprint("I transformed into the same zone again, wtf, aborting the trace\n");
426 if(!WarpZone_trace_firstzone)
427 WarpZone_trace_firstzone = wz;
428 WarpZone_trace_lastzone = wz;
429 if(zone && wz != zone)
431 WarpZone_Trace_AddTransform(wz);
432 // we hit a warpzone... so, let's perform the trace after the warp again
433 e.origin = WarpZone_TransformOrigin(wz, e.origin);
434 e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
436 // we got warped, so let's step back a bit
437 e.velocity = -e.velocity;
438 tracetoss(e, WarpZone_trace_forent);
439 dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
440 WarpZone_tracetoss_time -= dt;
441 e.origin = trace_endpos;
442 e.velocity = -e.velocity;
444 WarpZone_MakeAllOther();
446 WarpZone_tracetoss_velocity = e.velocity;
450 // restore old entity data (caller just uses trace_endpos, WarpZone_tracetoss_velocity and the transform)
455 void WarpZone_TraceToss(entity e, entity forent)
457 WarpZone_TraceToss_ThroughZone(e, forent, world, WarpZone_trace_callback_t_null);
460 entity WarpZone_TrailParticles_trace_callback_own;
461 float WarpZone_TrailParticles_trace_callback_eff;
462 void WarpZone_TrailParticles_trace_callback(vector from, vector endpos, vector to)
464 trailparticles(WarpZone_TrailParticles_trace_callback_own, WarpZone_TrailParticles_trace_callback_eff, from, endpos);
467 void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
469 WarpZone_TrailParticles_trace_callback_own = own;
470 WarpZone_TrailParticles_trace_callback_eff = eff;
471 WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_trace_callback);
475 float WarpZone_TrailParticles_trace_callback_f;
476 float WarpZone_TrailParticles_trace_callback_flags;
477 void WarpZone_TrailParticles_WithMultiplier_trace_callback(vector from, vector endpos, vector to)
479 boxparticles(WarpZone_TrailParticles_trace_callback_eff, WarpZone_TrailParticles_trace_callback_own, from, endpos, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_f, WarpZone_TrailParticles_trace_callback_flags);
482 void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, int boxflags)
484 WarpZone_TrailParticles_trace_callback_own = own;
485 WarpZone_TrailParticles_trace_callback_eff = eff;
486 WarpZone_TrailParticles_trace_callback_f = f;
487 WarpZone_TrailParticles_trace_callback_flags = boxflags | PARTICLES_DRAWASTRAIL;
488 WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_WithMultiplier_trace_callback);
492 float WarpZone_PlaneDist(entity wz, vector v)
494 return (v - wz.warpzone_origin) * wz.warpzone_forward;
497 float WarpZone_TargetPlaneDist(entity wz, vector v)
499 return (v - wz.warpzone_targetorigin) * wz.warpzone_targetforward;
502 vector WarpZone_TransformOrigin(entity wz, vector v)
504 return wz.warpzone_shift + AnglesTransform_Apply(wz.warpzone_transform, v);
507 vector WarpZone_TransformVelocity(entity wz, vector v)
509 return AnglesTransform_Apply(wz.warpzone_transform, v);
512 vector WarpZone_TransformAngles(entity wz, vector v)
514 return AnglesTransform_ApplyToAngles(wz.warpzone_transform, v);
517 vector WarpZone_TransformVAngles(entity wz, vector ang)
525 ang = AnglesTransform_ApplyToVAngles(wz.warpzone_transform, ang);
528 ang = AnglesTransform_Normalize(ang, true);
529 ang = AnglesTransform_CancelRoll(ang);
532 ang = AnglesTransform_Normalize(ang, false);
538 vector WarpZone_UnTransformOrigin(entity wz, vector v)
540 return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v - wz.warpzone_shift);
543 vector WarpZone_UnTransformVelocity(entity wz, vector v)
545 return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v);
548 vector WarpZone_UnTransformAngles(entity wz, vector v)
550 return AnglesTransform_ApplyToAngles(AnglesTransform_Invert(wz.warpzone_transform), v);
553 vector WarpZone_UnTransformVAngles(entity wz, vector ang)
560 ang = AnglesTransform_ApplyToVAngles(AnglesTransform_Invert(wz.warpzone_transform), ang);
561 ang = AnglesTransform_Normalize(ang, true);
562 ang = AnglesTransform_CancelRoll(ang);
568 vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
571 nearest_x = bound(mi.x, org.x, ma.x);
572 nearest_y = bound(mi.y, org.y, ma.y);
573 nearest_z = bound(mi.z, org.z, ma.z);
577 .float WarpZone_findradius_hit;
578 .entity WarpZone_findradius_next;
579 void WarpZone_FindRadius_Recurse(vector org, float rad, vector org0, vector transform, vector shift, float needlineofsight)
580 // blast origin of current search original blast origin how to untransform (victim to blast system)
584 vector shift_new, transform_new;
590 e0 = findradius(org, rad);
593 for(e = e0; e; e = e.chain)
595 p = WarpZoneLib_NearestPointOnBox(e.origin + e.mins, e.origin + e.maxs, org0);
598 traceline(org, p, MOVE_NOMONSTERS, e);
599 if(trace_fraction < 1)
602 if(!e.WarpZone_findradius_hit || vlen(e.WarpZone_findradius_dist) > vlen(org0 - p))
604 e.WarpZone_findradius_nearest = p;
605 e.WarpZone_findradius_dist = org0 - p;
606 e.WarpZone_findradius_findorigin = org;
607 e.WarpZone_findradius_findradius = rad;
608 if(e.classname == "warpzone_refsys")
610 // ignore, especially: do not overwrite the refsys parameters
612 else if(e.classname == "trigger_warpzone")
614 e.WarpZone_findradius_next = wz;
616 e.WarpZone_findradius_hit = 1;
617 e.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
618 e.enemy.WarpZone_findradius_hit = 1;
622 e.warpzone_transform = transform;
623 e.warpzone_shift = shift;
624 e.WarpZone_findradius_hit = 1;
628 for(e = wz; e; e = e.WarpZone_findradius_next)
630 org0_new = WarpZone_TransformOrigin(e, org);
631 traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
632 org_new = trace_endpos;
634 transform_new = AnglesTransform_Multiply(e.warpzone_transform, transform);
635 shift_new = AnglesTransform_Multiply_GetPostShift(e.warpzone_transform, e.warpzone_shift, transform, shift);
636 WarpZone_FindRadius_Recurse(
638 bound(0, rad - vlen(org_new - org0_new), rad - 8),
640 transform_new, shift_new,
642 e.WarpZone_findradius_hit = 0;
643 e.enemy.WarpZone_findradius_hit = 0;
646 entity WarpZone_FindRadius(vector org, float rad, float needlineofsight)
649 WarpZone_FindRadius_Recurse(org, rad, org, '0 0 0', '0 0 0', needlineofsight);
650 e0 = findchainfloat(WarpZone_findradius_hit, 1);
651 for(e = e0; e; e = e.chain)
652 e.WarpZone_findradius_hit = 0;
656 .entity WarpZone_refsys;
657 void WarpZone_RefSys_GC()
659 // garbage collect unused reference systems
660 self.nextthink = time + 1;
661 if(self.owner.WarpZone_refsys != self)
664 void WarpZone_RefSys_CheckCreate(entity me)
666 if(me.WarpZone_refsys.owner != me)
668 me.WarpZone_refsys = spawn();
669 me.WarpZone_refsys.classname = "warpzone_refsys";
670 me.WarpZone_refsys.owner = me;
671 me.WarpZone_refsys.think = WarpZone_RefSys_GC;
672 me.WarpZone_refsys.nextthink = time + 1;
673 WarpZone_Accumulator_Clear(me.WarpZone_refsys);
676 void WarpZone_RefSys_Clear(entity me)
678 if(me.WarpZone_refsys)
680 remove(me.WarpZone_refsys);
681 me.WarpZone_refsys = world;
684 void WarpZone_RefSys_AddTransform(entity me, vector t, vector s)
686 if(t != '0 0 0' || s != '0 0 0')
688 WarpZone_RefSys_CheckCreate(me);
689 WarpZone_Accumulator_AddTransform(me.WarpZone_refsys, t, s);
692 void WarpZone_RefSys_Add(entity me, entity wz)
694 WarpZone_RefSys_AddTransform(me, wz.warpzone_transform, wz.warpzone_shift);
696 void WarpZone_RefSys_AddInverseTransform(entity me, vector t, vector s)
698 if(t != '0 0 0' || s != '0 0 0')
700 WarpZone_RefSys_CheckCreate(me);
701 WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, t, s);
704 void WarpZone_RefSys_AddInverse(entity me, entity wz)
706 WarpZone_RefSys_AddInverseTransform(me, wz.warpzone_transform, wz.warpzone_shift);
708 .vector WarpZone_refsys_incremental_shift;
709 .vector WarpZone_refsys_incremental_transform;
710 void WarpZone_RefSys_AddIncrementally(entity me, entity ref)
713 if(me.WarpZone_refsys_incremental_transform == ref.WarpZone_refsys.warpzone_transform)
714 if(me.WarpZone_refsys_incremental_shift == ref.WarpZone_refsys.warpzone_shift)
716 WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, me.WarpZone_refsys_incremental_transform, me.WarpZone_refsys_incremental_shift);
717 WarpZone_Accumulator_Add(me.WarpZone_refsys, ref.WarpZone_refsys);
718 me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
719 me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
721 void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref)
723 me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
724 me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
726 vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
728 if(from.WarpZone_refsys)
729 org = WarpZone_UnTransformOrigin(from.WarpZone_refsys, org);
730 if(to.WarpZone_refsys)
731 org = WarpZone_TransformOrigin(to.WarpZone_refsys, org);
734 vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
736 if(from.WarpZone_refsys)
737 vel = WarpZone_UnTransformVelocity(from.WarpZone_refsys, vel);
738 if(to.WarpZone_refsys)
739 vel = WarpZone_TransformVelocity(to.WarpZone_refsys, vel);
742 vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang)
744 if(from.WarpZone_refsys)
745 ang = WarpZone_UnTransformAngles(from.WarpZone_refsys, ang);
746 if(to.WarpZone_refsys)
747 ang = WarpZone_TransformAngles(to.WarpZone_refsys, ang);
750 vector WarpZone_RefSys_TransformVAngles(entity from, entity to, vector ang)
752 if(from.WarpZone_refsys)
753 ang = WarpZone_UnTransformVAngles(from.WarpZone_refsys, ang);
754 if(to.WarpZone_refsys)
755 ang = WarpZone_TransformVAngles(to.WarpZone_refsys, ang);
758 void WarpZone_RefSys_Copy(entity me, entity from)
760 if(from.WarpZone_refsys)
762 WarpZone_RefSys_CheckCreate(me);
763 me.WarpZone_refsys.warpzone_shift = from.WarpZone_refsys.warpzone_shift;
764 me.WarpZone_refsys.warpzone_transform = from.WarpZone_refsys.warpzone_transform;
767 WarpZone_RefSys_Clear(me);
769 entity WarpZone_RefSys_SpawnSameRefSys(entity me)
773 WarpZone_RefSys_Copy(e, me);