}
void WarpZone_Accumulator_Add(entity acc, entity wz)
{
- vector t, st;
- t = AnglesTransform_Multiply(wz.warpzone_transform, acc.warpzone_transform);
- st = AnglesTransform_Multiply_GetPostShift(wz.warpzone_transform, wz.warpzone_shift, acc.warpzone_transform, acc.warpzone_shift);
- acc.warpzone_transform = t;
- acc.warpzone_shift = st;
+ WarpZone_Accumulator_AddTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
+}
+void WarpZone_Accumulator_AddInverseTransform(entity acc, vector t, vector s)
+{
+ vector tt, ss;
+ tt = AnglesTransform_Invert(t);
+ ss = AnglesTransform_PrePostShift_GetPostShift(s, tt, '0 0 0');
+ WarpZone_Accumulator_AddTransform(acc, tt, ss);
+ // yes, this probably can be done simpler... but this way is "obvious" :)
+}
+void WarpZone_Accumulator_AddInverse(entity acc, entity wz)
+{
+ WarpZone_Accumulator_AddInverseTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
}
.vector(vector, vector) camera_transform;
void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
{
- e.warpzone_transform = AnglesTransform_Divide(other_ang, AnglesTransform_TurnDirectionFR(my_ang));
+ e.warpzone_transform = AnglesTransform_RightDivide(other_ang, AnglesTransform_TurnDirectionFR(my_ang));
e.warpzone_shift = AnglesTransform_PrePostShift_GetPostShift(my_org, e.warpzone_transform, other_org);
e.warpzone_origin = my_org;
e.warpzone_targetorigin = other_org;
entity wz;
vector vf, vr, vu;
+ WarpZone_trace_forent = forent;
WarpZone_trace_firstzone = world;
+ WarpZone_trace_lastzone = world;
WarpZone_Trace_InitTransform();
if(!warpzone_warpzones_exist)
{
}
else
{
- tracebox(org, mi, ma, end, nomonsters, forent);
+ tracebox(org, mi, ma, end, nomonsters, WarpZone_trace_forent);
if(cb)
cb(org, trace_endpos, end);
return;
nomonsters_adjusted = nomonsters;
break;
}
- if((contentshack = (forent.dphitcontentsmask && !(forent.dphitcontentsmask & DPCONTENTS_SOLID))))
- forent.dphitcontentsmask |= DPCONTENTS_SOLID;
+ if((contentshack = (WarpZone_trace_forent.dphitcontentsmask && !(WarpZone_trace_forent.dphitcontentsmask & DPCONTENTS_SOLID))))
+ BITSET_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
// if starting in warpzone, first transform
wz = WarpZone_Find(org + mi, org + ma);
if(wz)
{
WarpZone_trace_firstzone = wz;
+ WarpZone_trace_lastzone = wz;
if(zone && wz != zone)
{
// we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
trace_ent = world;
break;
}
- tracebox(org, mi, ma, end, nomonsters_adjusted, forent);
+ tracebox(org, mi, ma, end, nomonsters_adjusted, WarpZone_trace_forent);
if(cb)
cb(org, trace_endpos, end);
if(sol < 0)
break;
if(trace_ent.classname != "trigger_warpzone")
{
- if((nomonsters == MOVE_NOTHING) || ((nomonsters == MOVE_WORLDONLY) && trace_ent) || (contentshack && (trace_dphitcontents & forent.dphitcontentsmask) == DPCONTENTS_SOLID))
+ if((nomonsters == MOVE_NOTHING) || ((nomonsters == MOVE_WORLDONLY) && trace_ent) || (contentshack && (trace_dphitcontents & WarpZone_trace_forent.dphitcontentsmask) == DPCONTENTS_SOLID))
{
// continue the trace, ignoring this hit (we only care for warpzones)
org = trace_endpos + normalize(end - org);
break;
}
wz = trace_ent;
- WarpZone_trace_firstzone = wz;
+ if(!WarpZone_trace_firstzone)
+ WarpZone_trace_firstzone = wz;
+ WarpZone_trace_lastzone = wz;
if(zone && wz != zone)
break;
WarpZone_Trace_AddTransform(wz);
// we hit a warpzone... so, let's perform the trace after the warp again
org = WarpZone_TransformOrigin(wz, trace_endpos);
end = WarpZone_TransformOrigin(wz, end);
+
+ // we got warped, so let's step back a bit
+ tracebox(org, mi, ma, org + normalize(org - end) * 32, nomonsters_adjusted, WarpZone_trace_forent);
+ org = trace_endpos;
}
WarpZone_MakeAllOther();
:fail
if(contentshack)
- forent.dphitcontentsmask &~= DPCONTENTS_SOLID;
+ BITCLR_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
trace_startsolid = sol;
v_forward = vf;
v_right = vr;
o0 = e.origin;
v0 = e.velocity;
+ g = cvar("sv_gravity") * e.gravity;
- WarpZone_Trace_InitTransform();
+ WarpZone_trace_forent = forent;
WarpZone_trace_firstzone = world;
+ WarpZone_trace_lastzone = world;
+ WarpZone_Trace_InitTransform();
WarpZone_tracetoss_time = 0;
if(!warpzone_warpzones_exist)
{
- tracetoss(e, forent);
+ tracetoss(e, WarpZone_trace_forent);
if(cb)
cb(e.origin, trace_endpos, trace_endpos);
dt = vlen(e.origin - o0) / vlen(e.velocity);
if(wz)
{
WarpZone_trace_firstzone = wz;
+ WarpZone_trace_lastzone = wz;
if(zone && wz != zone)
{
// we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
}
WarpZone_MakeAllSolid();
- g = cvar("sv_gravity") * e.gravity;
i = 16;
for(;;)
{
trace_ent = world;
break;
}
- tracetoss(e, forent);
+ tracetoss(e, WarpZone_trace_forent);
if(cb)
cb(e.origin, trace_endpos, trace_endpos);
- e.origin = trace_endpos;
- dt = vlen(e.origin - o0) / vlen(e.velocity);
+ dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
WarpZone_tracetoss_time += dt;
+ e.origin = trace_endpos;
e.velocity_z -= dt * g;
if(trace_fraction >= 1)
break;
break;
}
wz = trace_ent;
- WarpZone_trace_firstzone = wz;
+ if(!WarpZone_trace_firstzone)
+ WarpZone_trace_firstzone = wz;
+ WarpZone_trace_lastzone = wz;
if(zone && wz != zone)
break;
WarpZone_Trace_AddTransform(wz);
// we hit a warpzone... so, let's perform the trace after the warp again
e.origin = WarpZone_TransformOrigin(wz, e.origin);
e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
+
+ // we got warped, so let's step back a bit
+ e.velocity = -e.velocity;
+ tracetoss(e, WarpZone_trace_forent);
+ dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
+ WarpZone_tracetoss_time -= dt;
+ e.origin = trace_endpos;
+ e.velocity = -e.velocity;
}
WarpZone_MakeAllOther();
:fail
if(self.owner.WarpZone_refsys != self)
remove(self);
}
-void WarpZone_RefSys_Add(entity me, entity wz)
+void WarpZone_RefSys_CheckCreate(entity me)
{
if(me.WarpZone_refsys.owner != me)
{
me.WarpZone_refsys.nextthink = time + 1;
WarpZone_Accumulator_Clear(me.WarpZone_refsys);
}
- if(wz)
- WarpZone_Accumulator_Add(me.WarpZone_refsys, wz);
+}
+void WarpZone_RefSys_Clear(entity me)
+{
+ if(me.WarpZone_refsys)
+ {
+ remove(me.WarpZone_refsys);
+ me.WarpZone_refsys = world;
+ }
+}
+void WarpZone_RefSys_AddTransform(entity me, vector t, vector s)
+{
+ if(t != '0 0 0' || s != '0 0 0')
+ {
+ WarpZone_RefSys_CheckCreate(me);
+ WarpZone_Accumulator_AddTransform(me.WarpZone_refsys, t, s);
+ }
+}
+void WarpZone_RefSys_Add(entity me, entity wz)
+{
+ WarpZone_RefSys_AddTransform(me, wz.warpzone_transform, wz.warpzone_shift);
+}
+void WarpZone_RefSys_AddInverseTransform(entity me, vector t, vector s)
+{
+ if(t != '0 0 0' || s != '0 0 0')
+ {
+ WarpZone_RefSys_CheckCreate(me);
+ WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, t, s);
+ }
+}
+void WarpZone_RefSys_AddInverse(entity me, entity wz)
+{
+ WarpZone_RefSys_AddInverseTransform(me, wz.warpzone_transform, wz.warpzone_shift);
}
.vector WarpZone_refsys_incremental_shift;
.vector WarpZone_refsys_incremental_transform;
if(me.WarpZone_refsys_incremental_transform == ref.WarpZone_refsys.warpzone_transform)
if(me.WarpZone_refsys_incremental_shift == ref.WarpZone_refsys.warpzone_shift)
return;
- if(me.WarpZone_refsys.owner != me)
- {
- me.WarpZone_refsys = spawn();
- me.WarpZone_refsys.classname = "warpzone_refsys";
- me.WarpZone_refsys.owner = me;
- me.WarpZone_refsys.think = WarpZone_RefSys_GC;
- me.WarpZone_refsys.nextthink = time + 1;
- WarpZone_Accumulator_Clear(me.WarpZone_refsys);
- }
- t = AnglesTransform_Invert(me.WarpZone_refsys_incremental_transform);
- s = AnglesTransform_PrePostShift_GetPostShift(me.WarpZone_refsys_incremental_shift, t, '0 0 0');
- WarpZone_Accumulator_AddTransform(me.WarpZone_refsys, t, s);
- WarpZone_Accumulator_Add(me.WarpZone_refsys, ref);
+ WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, me.WarpZone_refsys_incremental_transform, me.WarpZone_refsys_incremental_shift);
+ WarpZone_Accumulator_Add(me.WarpZone_refsys, ref.WarpZone_refsys);
me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
}
ang = WarpZone_TransformVAngles(to.WarpZone_refsys, ang);
return ang;
}
+void WarpZone_RefSys_Copy(entity me, entity from)
+{
+ if(from.WarpZone_refsys)
+ {
+ WarpZone_RefSys_CheckCreate(me);
+ me.WarpZone_refsys.warpzone_shift = from.WarpZone_refsys.warpzone_shift;
+ me.WarpZone_refsys.warpzone_transform = from.WarpZone_refsys.warpzone_transform;
+ }
+ else
+ WarpZone_RefSys_Clear(me);
+}
entity WarpZone_RefSys_SpawnSameRefSys(entity me)
{
entity e;
e = spawn();
- if(me.WarpZone_refsys)
- {
- e.WarpZone_refsys = spawn();
- e.WarpZone_refsys.classname = "warpzone_refsys";
- e.WarpZone_refsys.owner = e;
- e.WarpZone_refsys.think = WarpZone_RefSys_GC;
- e.WarpZone_refsys.nextthink = time + 1;
- e.WarpZone_refsys.warpzone_shift = me.WarpZone_refsys.warpzone_shift;
- e.WarpZone_refsys.warpzone_transform = me.WarpZone_refsys.warpzone_transform;
- }
+ WarpZone_RefSys_Copy(e, me);
return e;
}