o1 = WarpZone_TransformOrigin(self, o0);
v1 = WarpZone_TransformVelocity(self, v0);
- if(player.classname == "player")
+ if(clienttype(player) != CLIENTTYPE_NOTACLIENT)
a1 = WarpZone_TransformVAngles(self, player.v_angle);
else
a1 = WarpZone_TransformAngles(self, a0);
e = self.enemy;
if(WarpZone_Teleport(other))
{
- 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)
+ f |= 1;
+ if(self.warpzone_fadestart)
+ f |= 2;
+ if(self.origin != '0 0 0')
+ 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)
+ f |= 2;
+ if(self.origin != '0 0 0')
+ 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;
}
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);
+ self.velocity = WarpZone_TransformVelocity(WarpZone_trace_transform, self.warpzone_oldvelocity);
// in case we are in our warp zone post-teleport, shift the projectile forward a bit
mpd = max(vlen(self.mins), vlen(self.maxs));
return FALSE;
}
-void WarpZone_InitStep_FindTarget()
+void WarpZone_InitStep_FindOriginTarget()
{
- entity e;
-
if(self.killtarget != "")
{
self.aiment = find(world, targetname, self.killtarget);
error("Warp zone with nonexisting killtarget");
return;
}
- }
-
- // this way only one of the two ents needs to target
- if(self.target != "")
- {
- e = find(world, targetname, self.target);
- if(e)
- {
- self.enemy = e;
- self.enemy.enemy = self;
- }
+ self.killtarget = string_null;
}
}
void WarpZonePosition_InitStep_FindTarget()
{
- entity e;
-
if(self.target == "")
{
error("Warp zone position with no target");
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;
+ WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles);
+ self.SendFlags = 0xFFFFFF;
}
void WarpZone_InitStep_UpdateTransform()
float i_s, i_t, n_t;
string tex;
- if(!self.enemy || self.enemy.enemy != self)
- {
- error("Invalid warp zone detected. Killed.");
- return;
- }
-
org = self.origin;
if(org == '0 0 0')
org = 0.5 * (self.mins + self.maxs);
tex = getsurfacetexture(self, i_s);
if not(tex)
break; // this is beyond the last one
- if(tex != "textures/common/warpzone")
+ if(tex == "textures/common/trigger")
continue;
n_t = getsurfacenumtriangles(self, i_s);
for(i_t = 0; i_t < n_t; ++i_t)
self.warpzone_origin = org;
self.warpzone_angles = ang;
}
+
+void WarpZone_InitStep_ClearTarget()
+{
+ if(self.enemy)
+ self.enemy.enemy = world;
+ self.enemy = world;
+}
+
+entity warpzone_first; .entity warpzone_next;
+void WarpZone_InitStep_FindTarget()
+{
+ float i;
+ entity e, e2;
+
+ if(self.enemy)
+ return;
+
+ // this way only one of the two ents needs to target
+ if(self.target != "")
+ {
+ self.enemy = self; // so the if(!e.enemy) check also skips self, saves one IF
+
+ e2 = world;
+ for(e = world, i = 0; (e = find(e, targetname, self.target)); )
+ if(!e.enemy)
+ if(e.classname == self.classname) // possibly non-warpzones may use the same targetname!
+ if(random() * ++i < 1)
+ e2 = e;
+ if(!e2)
+ {
+ self.enemy = world;
+ error("Warpzone with non-existing target");
+ return;
+ }
+ self.enemy = e2;
+ e2.enemy = self;
+ }
+}
+
void WarpZone_InitStep_FinalizeTransform()
{
+ if(!self.enemy || self.enemy.enemy != self)
+ {
+ error("Invalid warp zone detected. Killed.");
+ return;
+ }
+
+ ++warpzone_warpzones_exist;
WarpZone_SetUp(self, self.warpzone_origin, self.warpzone_angles, self.enemy.warpzone_origin, self.enemy.warpzone_angles);
self.touch = WarpZone_Touch;
+ self.SendFlags = 0xFFFFFF;
}
float warpzone_initialized;
self.warpzone_next = warpzone_camera_first;
warpzone_camera_first = self;
}
+void WarpZones_Reconnect()
+{
+ entity e;
+ e = self;
+ for(self = warpzone_first; self; self = self.warpzone_next)
+ 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_StartFrame()
{
entity e;
warpzone_initialized = 1;
e = self;
for(self = warpzone_first; self; self = self.warpzone_next)
- WarpZone_InitStep_FindTarget();
+ 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();
- for(self = warpzone_first; self; self = self.warpzone_next)
- WarpZone_InitStep_FinalizeTransform();
self = e;
+ WarpZones_Reconnect();
}
for(e = world; (e = nextent(e)); )
WarpZone_StoreProjectileData(e);
}
+
+.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;
+ e = self;
+ // 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)
+ 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(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(self.warpzone_reconnecting || self.enemy.warpzone_reconnecting)
+ WarpZone_InitStep_FinalizeTransform();
+ self = e;
+}
+
+void spawnfunc_trigger_warpzone_reconnect()
+{
+ self.use = trigger_warpzone_reconnect_use;
+}
+
+void spawnfunc_target_warpzone_reconnect()
+{
+ spawnfunc_trigger_warpzone_reconnect(); // both names make sense here :(
+}