+// for think function
+.vector warpzone_save_origin;
+.vector warpzone_save_angles;
+.vector warpzone_save_eorigin;
+.vector warpzone_save_eangles;
+
+// for all entities
.vector warpzone_oldorigin, warpzone_oldvelocity, warpzone_oldangles;
.float warpzone_teleport_time;
+.entity warpzone_teleport_zone;
void WarpZone_StoreProjectileData(entity e)
{
void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity)
{
- vector from;
-
- makevectors (to_angles);
-
- from = player.origin;
setorigin (player, to);
player.oldorigin = to; // for DP's unsticking
player.angles = to_angles;
player.fixangle = TRUE;
player.velocity = to_velocity;
- if(player.effects & EF_TELEPORT_BIT)
- player.effects &~= EF_TELEPORT_BIT;
- else
- player.effects |= EF_TELEPORT_BIT;
+ BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
if(player.classname == "player")
- player.flags &~= FL_ONGROUND;
+ BITCLR_ASSIGN(player.flags, FL_ONGROUND);
WarpZone_PostTeleportPlayer_Callback(player);
}
-float WarpZone_Teleport(entity player)
+float WarpZone_Teleported_Send(entity to, float sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED);
+ WriteCoord(MSG_ENTITY, self.angles_x);
+ WriteCoord(MSG_ENTITY, self.angles_y);
+ WriteCoord(MSG_ENTITY, self.angles_z);
+ return TRUE;
+}
+
+#define WARPZONE_TELEPORT_FIXSOLID(ret) \
+ do \
+ { \
+ setorigin(player, o1 - player.view_ofs); \
+ if(WarpZoneLib_MoveOutOfSolid(player)) \
+ { \
+ o1 = player.origin + player.view_ofs; \
+ setorigin(player, o0 - player.view_ofs); \
+ } \
+ else \
+ { \
+ print("would have to put player in solid, won't do that\n"); \
+ setorigin(player, o0 - player.view_ofs); \
+ return (ret); \
+ } \
+ } \
+ while(0)
+#define WARPZONE_TELEPORT_DOTELEPORT() \
+ do \
+ { \
+ WarpZone_RefSys_Add(player, wz); \
+ WarpZone_TeleportPlayer(wz, player, o1 - player.view_ofs, a1, v1); \
+ WarpZone_StoreProjectileData(player); \
+ player.warpzone_teleport_time = time; \
+ player.warpzone_teleport_zone = wz; \
+ } \
+ while(0)
+
+float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
{
vector o0, a0, v0, o1, a1, v1;
v0 = player.velocity;
a0 = player.angles;
- if(WarpZone_PlaneDist(self, o0) >= 0) // wrong side of the trigger_warpzone
- return 2;
- // no failure, we simply don't want to teleport yet; TODO in
- // this situation we may want to create a temporary clone
- // entity of the player to fix graphics glitch
-
- o1 = WarpZone_TransformOrigin(self, o0);
- v1 = WarpZone_TransformVelocity(self, v0);
- if(player.classname == "player")
- a1 = WarpZone_TransformVAngles(self, player.v_angle);
+ o1 = WarpZone_TransformOrigin(wz, o0);
+ v1 = WarpZone_TransformVelocity(wz, v0);
+ if(clienttype(player) != CLIENTTYPE_NOTACLIENT)
+ a1 = WarpZone_TransformVAngles(wz, player.v_angle);
else
- a1 = WarpZone_TransformAngles(self, a0);
+ a1 = WarpZone_TransformAngles(wz, a0);
- // put him inside solid
- tracebox(o1 - player.view_ofs, player.mins, player.maxs, o1 - player.view_ofs, MOVE_NOMONSTERS, player);
- if(trace_startsolid)
+ if(f0 != 0 || f1 != 0)
{
- vector mi, ma;
- mi = player.mins;
- ma = player.maxs;
- setsize(player, mi - player.view_ofs, ma - player.view_ofs);
- setorigin(player, o1);
- if(WarpZoneLib_MoveOutOfSolid(player))
- {
- o1 = player.origin;
- setsize(player, mi, ma);
- setorigin(player, o0);
- }
- else
+ // retry last move but behind the warpzone!
+ // we must first go back as far as we can, then forward again, to not cause double touch events!
+
+ tracebox(o1 - player.view_ofs + v1 * frametime * f1, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f0, MOVE_WORLDONLY, player);
{
- print("would have to put player in solid, won't do that\n");
- setsize(player, mi, ma);
- setorigin(player, o0 - player.view_ofs);
- return 0; // cannot fix
+ entity own;
+ own = player.owner;
+ player.owner = world;
+ tracebox(trace_endpos, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f1, MOVE_NORMAL, player); // this should get us through the warpzone
+ player.owner = own;
}
- }
+ o1 = trace_endpos + player.view_ofs;
- if(WarpZone_TargetPlaneDist(self, o1) <= 0)
- {
- print("inconsistent warp zones or evil roundoff error\n");
- return 0;
+ float d, dv;
+ d = WarpZone_TargetPlaneDist(wz, o1);
+ dv = WarpZone_TargetPlaneDist(wz, v1);
+ if(d < 0)
+ o1 = o1 - v1 * (d / dv);
}
- //print(sprintf("warpzone: %f %f %f -> %f %f %f\n", o0_x, o0_y, o0_z, o1_x, o1_y, o1_z));
+ // put him inside solid
+ tracebox(o1 - player.view_ofs, player.mins, player.maxs, o1 - player.view_ofs, MOVE_NOMONSTERS, player);
+ if(trace_startsolid)
+ WARPZONE_TELEPORT_FIXSOLID(0);
+
+ WARPZONE_TELEPORT_DOTELEPORT();
- //o1 = trace_endpos;
- WarpZone_RefSys_Add(player, self);
- WarpZone_TeleportPlayer(self, player, o1 - player.view_ofs, a1, v1);
- WarpZone_StoreProjectileData(player);
- player.warpzone_teleport_time = time;
+#ifndef WARPZONE_USE_FIXANGLE
+ if(player.classname == "player")
+ {
+ // instead of fixangle, send the transform to the client for smoother operation
+ player.fixangle = FALSE;
+
+ entity ts = spawn();
+ setmodel(ts, "null");
+ ts.SendEntity = WarpZone_Teleported_Send;
+ ts.SendFlags = 0xFFFFFF;
+ ts.drawonlytoclient = player;
+ ts.think = SUB_Remove;
+ ts.nextthink = time + 1;
+ ts.owner = player;
+ ts.enemy = wz;
+ ts.effects = EF_NODEPTHTEST;
+ ts.classname = "warpzone_teleported";
+ ts.angles = wz.warpzone_transform;
+ }
+#endif
return 1;
}
void WarpZone_Touch (void)
{
- entity oldself, e;
+ entity oldself;
if(other.classname == "trigger_warpzone")
return;
+ if(other.warpzone_teleport_time == time) // already teleported this frame
+ return;
+
// FIXME needs a better check to know what is safe to teleport and what not
- if(other.movetype == MOVETYPE_NONE)
+ if(other.movetype == MOVETYPE_NONE || other.movetype == MOVETYPE_FOLLOW)
return;
if(WarpZoneLib_ExactTrigger_Touch())
return;
- e = self.enemy;
- if(WarpZone_Teleport(other))
+ if(WarpZone_PlaneDist(self, other.origin + other.view_ofs) >= 0) // wrong side of the trigger_warpzone (don't teleport yet)
+ return;
+
+ if(WarpZone_Teleport(self, other, -1, 0))
{
- if(self.aiment.target)
- {
- oldself = self;
- activator = other;
- self = self.aiment;
- SUB_UseTargets();
- self = oldself;
- }
+ string save1, save2;
+ activator = other;
+
+ save1 = self.target; self.target = string_null;
+ save2 = self.target3; self.target3 = string_null;
+ SUB_UseTargets();
+ if not(self.target) self.target = save1;
+ if not(self.target3) self.target3 = save2;
+
+ oldself = self;
+ self = self.enemy;
+ save1 = self.target; self.target = string_null;
+ save2 = self.target2; self.target2 = string_null;
+ SUB_UseTargets();
+ if not(self.target) self.target = save1;
+ if not(self.target2) self.target2 = save2;
+ self = oldself;
}
else
{
float WarpZone_Send(entity to, float sendflags)
{
+ float f;
WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE);
+ // we must send this flag for clientside to match properly too
+ f = 0;
+ if(self.warpzone_isboxy)
+ BITSET_ASSIGN(f, 1);
+ if(self.warpzone_fadestart)
+ BITSET_ASSIGN(f, 2);
+ if(self.origin != '0 0 0')
+ BITSET_ASSIGN(f, 4);
+ WriteByte(MSG_ENTITY, f);
+
// we need THESE to render the warpzone (and cull properly)...
- WriteCoord(MSG_ENTITY, self.origin_x);
- WriteCoord(MSG_ENTITY, self.origin_y);
- WriteCoord(MSG_ENTITY, self.origin_z);
+ if(f & 4)
+ {
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+ }
WriteShort(MSG_ENTITY, self.modelindex);
WriteCoord(MSG_ENTITY, self.mins_x);
WriteCoord(MSG_ENTITY, self.warpzone_targetangles_y);
WriteCoord(MSG_ENTITY, self.warpzone_targetangles_z);
+ if(f & 2)
+ {
+ WriteShort(MSG_ENTITY, self.warpzone_fadestart);
+ WriteShort(MSG_ENTITY, self.warpzone_fadeend);
+ }
+
return TRUE;
}
float WarpZone_Camera_Send(entity to, float sendflags)
{
+ float f;
WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA);
+ if(self.warpzone_fadestart)
+ BITSET_ASSIGN(f, 2);
+ if(self.origin != '0 0 0')
+ BITSET_ASSIGN(f, 4);
+ WriteByte(MSG_ENTITY, f);
+
// we need THESE to render the warpzone (and cull properly)...
- WriteCoord(MSG_ENTITY, self.origin_x);
- WriteCoord(MSG_ENTITY, self.origin_y);
- WriteCoord(MSG_ENTITY, self.origin_z);
+ if(f & 4)
+ {
+ WriteCoord(MSG_ENTITY, self.origin_x);
+ WriteCoord(MSG_ENTITY, self.origin_y);
+ WriteCoord(MSG_ENTITY, self.origin_z);
+ }
WriteShort(MSG_ENTITY, self.modelindex);
WriteCoord(MSG_ENTITY, self.mins_x);
WriteCoord(MSG_ENTITY, self.enemy.angles_y);
WriteCoord(MSG_ENTITY, self.enemy.angles_z);
+ if(f & 2)
+ {
+ WriteShort(MSG_ENTITY, self.warpzone_fadestart);
+ WriteShort(MSG_ENTITY, self.warpzone_fadeend);
+ }
+
return TRUE;
}
-float WarpZone_CheckProjectileImpact()
+float WarpZone_CheckProjectileImpact(entity player)
{
- // if self hit a warpzone, abort
- vector o0, v0, a0;
- float mpd, pd, dpd;
+ vector o0, a0, v0;
+
+ o0 = player.origin + player.view_ofs;
+ v0 = player.velocity;
+ a0 = player.angles;
+
+ // if player hit a warpzone, abort
entity wz;
- wz = WarpZone_Find(self.origin + self.mins, self.origin + self.maxs);
+ wz = WarpZone_Find(o0 + player.mins, o0 + player.maxs);
if(!wz)
- return FALSE;
- o0 = self.origin;
- v0 = self.velocity;
- a0 = self.angles;
-
- // this approach transports the projectile at its full speed, but does
- // not properly retain the projectile trail (but we can't retain it
- // easily anyway without delaying the projectile by two frames, so who
- // cares)
- WarpZone_TraceBox_ThroughZone(self.warpzone_oldorigin, self.mins, self.maxs, self.warpzone_oldorigin + self.warpzone_oldvelocity * frametime, MOVE_NORMAL, self, wz, WarpZone_trace_callback_t_null); // this will get us through the warpzone
- setorigin(self, trace_endpos);
- self.angles = WarpZone_TransformAngles(WarpZone_trace_transform, self.angles);
- self.velocity = WarpZone_TransformVelocity(WarpZone_trace_transform, self.velocity);
-
- // in case we are in our warp zone post-teleport, shift the projectile forward a bit
- mpd = max(vlen(self.mins), vlen(self.maxs));
- pd = WarpZone_TargetPlaneDist(wz, self.origin);
- if(pd < mpd)
+ return 0;
+
+ print("impactfilter found something - and it even gets handled correctly - please tell divVerent that this code apparently gets triggered again\n");
+
+ // retry previous move
+ setorigin(player, player.warpzone_oldorigin);
+ player.velocity = player.warpzone_oldvelocity;
+ if(WarpZone_Teleport(wz, player, 0, 1))
{
- dpd = normalize(self.velocity) * self.warpzone_targetforward;
- setorigin(self, self.origin + normalize(self.velocity) * ((mpd - pd) / dpd));
- if(!WarpZoneLib_MoveOutOfSolid(self))
- {
- setorigin(self, o0);
- self.angles = a0;
- self.velocity = v0;
- return FALSE;
- }
+ entity oldself;
+ string save1, save2;
+
+ oldself = self;
+ self = wz;
+ other = player;
+ activator = player;
+
+ save1 = self.target; self.target = string_null;
+ save2 = self.target3; self.target3 = string_null;
+ SUB_UseTargets();
+ if not(self.target) self.target = save1;
+ if not(self.target3) self.target3 = save2;
+
+ self = self.enemy;
+ save1 = self.target; self.target = string_null;
+ save2 = self.target2; self.target2 = string_null;
+ SUB_UseTargets();
+ if not(self.target) self.target = save1;
+ if not(self.target2) self.target2 = save2;
+ self = oldself;
+ }
+ else
+ {
+ setorigin(player, o0);
+ player.velocity = v0;
}
- WarpZone_RefSys_Add(self, wz);
- WarpZone_StoreProjectileData(self);
- self.warpzone_teleport_time = time;
- return TRUE;
+ return +1;
}
float WarpZone_Projectile_Touch()
{
+ float f;
if(other.classname == "trigger_warpzone")
return TRUE;
- if(WarpZone_Projectile_Touch_ImpactFilter_Callback())
+
+ // no further impacts if we teleported this frame!
+ if(self.warpzone_teleport_time == time)
return TRUE;
- if(WarpZone_CheckProjectileImpact())
+
+ // this SEEMS to not happen at the moment, but if it did, it would be more reliable
+ {
+ float save_dpstartcontents;
+ float save_dphitcontents;
+ float save_dphitq3surfaceflags;
+ string save_dphittexturename;
+ float save_allsolid;
+ float save_startsolid;
+ float save_fraction;
+ vector save_endpos;
+ vector save_plane_normal;
+ float save_plane_dist;
+ entity save_ent;
+ float save_inopen;
+ float save_inwater;
+ save_dpstartcontents = trace_dpstartcontents;
+ save_dphitcontents = trace_dphitcontents;
+ save_dphitq3surfaceflags = trace_dphitq3surfaceflags;
+ save_dphittexturename = trace_dphittexturename;
+ save_allsolid = trace_allsolid;
+ save_startsolid = trace_startsolid;
+ save_fraction = trace_fraction;
+ save_endpos = trace_endpos;
+ save_plane_normal = trace_plane_normal;
+ save_plane_dist = trace_plane_dist;
+ save_ent = trace_ent;
+ save_inopen = trace_inopen;
+ save_inwater = trace_inwater;
+ if((f = WarpZone_CheckProjectileImpact(self)) != 0)
+ return (f > 0);
+ trace_dpstartcontents = save_dpstartcontents;
+ trace_dphitcontents = save_dphitcontents;
+ trace_dphitq3surfaceflags = save_dphitq3surfaceflags;
+ trace_dphittexturename = save_dphittexturename;
+ trace_allsolid = save_allsolid;
+ trace_startsolid = save_startsolid;
+ trace_fraction = save_fraction;
+ trace_endpos = save_endpos;
+ trace_plane_normal = save_plane_normal;
+ trace_plane_dist = save_plane_dist;
+ trace_ent = save_ent;
+ trace_inopen = save_inopen;
+ trace_inwater = save_inwater;
+ }
+
+ if(WarpZone_Projectile_Touch_ImpactFilter_Callback())
return TRUE;
- if(self.warpzone_teleport_time == time) // already got teleported this frame? no collision then please
+
+ if(self.warpzone_teleport_time == time)
{
+ // sequence: hit warpzone, get teleported, hit wall
+ // print("2 hits 1 frame\n");
setorigin(self, self.warpzone_oldorigin);
self.velocity = self.warpzone_oldvelocity;
self.angles = self.warpzone_oldangles;
return TRUE;
}
-
return FALSE;
}
error("Warp zone with nonexisting killtarget");
return;
}
+ self.killtarget = string_null;
}
}
self.enemy.aiment = self;
}
+void WarpZoneCamera_Think(void)
+{
+ if(self.warpzone_save_origin != self.origin
+ || self.warpzone_save_angles != self.angles
+ || self.warpzone_save_eorigin != self.enemy.origin
+ || self.warpzone_save_eangles != self.enemy.angles)
+ {
+ WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles);
+ self.warpzone_save_origin = self.origin;
+ self.warpzone_save_angles = self.angles;
+ self.warpzone_save_eorigin = self.enemy.origin;
+ self.warpzone_save_eangles = self.enemy.angles;
+ }
+ self.nextthink = time;
+}
+
void WarpZoneCamera_InitStep_FindTarget()
{
+ entity e;
+ float i;
if(self.target == "")
{
error("Camera with no target");
return;
}
- self.enemy = find(world, targetname, self.target);
+ self.enemy = world;
+ for(e = world, i = 0; (e = find(e, targetname, self.target)); )
+ if(random() * ++i < 1)
+ self.enemy = e;
if(self.enemy == world)
{
error("Camera with nonexisting target");
return;
}
+ warpzone_cameras_exist = 1;
WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles);
+ self.SendFlags = 0xFFFFFF;
+ if(self.spawnflags & 1)
+ {
+ self.think = WarpZoneCamera_Think;
+ self.nextthink = time;
+ }
+ else
+ self.nextthink = 0;
}
void WarpZone_InitStep_UpdateTransform()
tex = getsurfacetexture(self, i_s);
if not(tex)
break; // this is beyond the last one
- if(tex == "textures/common/trigger")
+ if(tex == "textures/common/trigger" || tex == "trigger")
continue;
n_t = getsurfacenumtriangles(self, i_s);
for(i_t = 0; i_t < n_t; ++i_t)
}
}
+void WarpZone_Think();
void WarpZone_InitStep_FinalizeTransform()
{
if(!self.enemy || self.enemy.enemy != self)
return;
}
+ warpzone_warpzones_exist = 1;
WarpZone_SetUp(self, self.warpzone_origin, self.warpzone_angles, self.enemy.warpzone_origin, self.enemy.warpzone_angles);
self.touch = WarpZone_Touch;
self.SendFlags = 0xFFFFFF;
+ if(self.spawnflags & 1)
+ {
+ self.think = WarpZone_Think;
+ self.nextthink = time;
+ }
+ else
+ self.nextthink = 0;
}
float warpzone_initialized;
// the map, with another killtarget to designate its
// orientation
+#ifndef WARPZONE_USE_FIXANGLE
+ // used when teleporting
+ precache_model("null");
+#endif
+
if(!self.scale)
self.scale = self.modelscale;
if(!self.scale)
setsize(self, self.mins, self.maxs);
self.SendEntity = WarpZone_Send;
self.SendFlags = 0xFFFFFF;
- self.effects |= EF_NODEPTHTEST;
+ BITSET_ASSIGN(self.effects, EF_NODEPTHTEST);
self.warpzone_next = warpzone_first;
warpzone_first = self;
}
WarpZone_InitStep_ClearTarget();
for(self = warpzone_first; self; self = self.warpzone_next)
WarpZone_InitStep_FindTarget();
+ for(self = warpzone_camera_first; self; self = self.warpzone_next)
+ WarpZoneCamera_InitStep_FindTarget();
for(self = warpzone_first; self; self = self.warpzone_next)
WarpZone_InitStep_FinalizeTransform();
self = e;
}
+void WarpZone_Think()
+{
+ if(self.warpzone_save_origin != self.origin
+ || self.warpzone_save_angles != self.angles
+ || self.warpzone_save_eorigin != self.enemy.origin
+ || self.warpzone_save_eangles != self.enemy.angles)
+ {
+ entity oldself;
+ oldself = self;
+ WarpZone_InitStep_UpdateTransform();
+ self = self.enemy;
+ WarpZone_InitStep_UpdateTransform();
+ self = oldself;
+ WarpZone_InitStep_FinalizeTransform();
+ self = self.enemy;
+ WarpZone_InitStep_FinalizeTransform();
+ self = oldself;
+ self.warpzone_save_origin = self.origin;
+ self.warpzone_save_angles = self.angles;
+ self.warpzone_save_eorigin = self.enemy.origin;
+ self.warpzone_save_eangles = self.enemy.angles;
+ }
+ self.nextthink = time;
+}
+
void WarpZone_StartFrame()
{
entity e;
WarpZone_InitStep_FindOriginTarget();
for(self = warpzone_position_first; self; self = self.warpzone_next)
WarpZonePosition_InitStep_FindTarget();
- for(self = warpzone_camera_first; self; self = self.warpzone_next)
- WarpZoneCamera_InitStep_FindTarget();
for(self = warpzone_first; self; self = self.warpzone_next)
WarpZone_InitStep_UpdateTransform();
self = e;
WarpZones_Reconnect();
}
- for(e = world; (e = nextent(e)); )
- WarpZone_StoreProjectileData(e);
+
+ if(warpzone_warpzones_exist)
+ {
+ entity oldself, oldother;
+ oldself = self;
+ oldother = other;
+ for(e = world; (e = nextent(e)); )
+ {
+ WarpZone_StoreProjectileData(e);
+ float f;
+ f = clienttype(e);
+ if(f == CLIENTTYPE_REAL)
+ {
+ if(e.solid != SOLID_NOT) // not spectating?
+ continue;
+ if(e.movetype != MOVETYPE_NOCLIP && e.movetype != MOVETYPE_FLY) // not spectating? (this is to catch observers)
+ continue;
+ self = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
+ if(!self)
+ continue;
+ other = e;
+ if(WarpZoneLib_ExactTrigger_Touch())
+ continue;
+ if(WarpZone_PlaneDist(self, e.origin + e.view_ofs) <= 0)
+ WarpZone_Teleport(self, e); // NOT triggering targets by this!
+ }
+ if(f == CLIENTTYPE_NOTACLIENT)
+ {
+ for(; (e = nextent(e)); )
+ WarpZone_StoreProjectileData(e);
+ break;
+ }
+ }
+ self = oldself;
+ other = oldother;
+ }
}
+.float warpzone_reconnecting;
+float visible_to_some_client(entity ent)
+{
+ entity e;
+ for(e = nextent(world); clienttype(e) != CLIENTTYPE_NOTACLIENT; e = nextent(e))
+ if(e.classname == "player" && clienttype(e) == CLIENTTYPE_REAL)
+ if(checkpvs(e.origin + e.view_ofs, ent))
+ return 1;
+ return 0;
+}
void trigger_warpzone_reconnect_use()
{
entity e;
// NOTE: this matches for target, not targetname, but of course
// targetname must be set too on the other entities
for(self = warpzone_first; self; self = self.warpzone_next)
- if(e.target == "" || self.target == e.target)
+ self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && (visible_to_some_client(self) || visible_to_some_client(self.enemy))));
+ for(self = warpzone_camera_first; self; self = self.warpzone_next)
+ self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && visible_to_some_client(self)));
+ for(self = warpzone_first; self; self = self.warpzone_next)
+ if(self.warpzone_reconnecting)
WarpZone_InitStep_ClearTarget();
for(self = warpzone_first; self; self = self.warpzone_next)
- if(e.target == "" || self.target == e.target)
+ if(self.warpzone_reconnecting)
WarpZone_InitStep_FindTarget();
+ for(self = warpzone_camera_first; self; self = self.warpzone_next)
+ if(self.warpzone_reconnecting)
+ WarpZoneCamera_InitStep_FindTarget();
for(self = warpzone_first; self; self = self.warpzone_next)
- if(e.target == "" || self.target == e.target || self.enemy.target == e.target)
+ if(self.warpzone_reconnecting || self.enemy.warpzone_reconnecting)
WarpZone_InitStep_FinalizeTransform();
self = e;
}
{
spawnfunc_trigger_warpzone_reconnect(); // both names make sense here :(
}
+
+void WarpZone_PlayerPhysics_FixVAngle(void)
+{
+#ifndef WARPZONE_DONT_FIX_VANGLE
+ if(clienttype(self) == CLIENTTYPE_REAL)
+ if(self.v_angle_z <= 360) // if not already adjusted
+ if(time - self.ping * 0.001 < self.warpzone_teleport_time)
+ {
+ self.v_angle = WarpZone_TransformVAngles(self.warpzone_teleport_zone, self.v_angle);
+ self.v_angle_z += 720; // mark as adjusted
+ }
+#endif
+}