]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/warpzonelib/server.qc
also set SendFlags when updating a camera
[xonotic/xonotic-data.pk3dir.git] / qcsrc / warpzonelib / server.qc
index 44e696aece4e632077fa2519e3e1cfa14e6b2086..6e0ecb5b33811de1c266da4a90c617a84d16b2c3 100644 (file)
@@ -48,7 +48,7 @@ float WarpZone_Teleport(entity player)
 
        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);
@@ -111,14 +111,23 @@ void WarpZone_Touch (void)
        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
        {
@@ -128,12 +137,26 @@ void WarpZone_Touch (void)
 
 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);
@@ -158,17 +181,33 @@ float WarpZone_Send(entity to, float sendflags)
        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);
@@ -187,6 +226,12 @@ float WarpZone_Camera_Send(entity to, float sendflags)
        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;
 }
 
@@ -210,7 +255,7 @@ float WarpZone_CheckProjectileImpact()
        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));
@@ -252,10 +297,8 @@ float WarpZone_Projectile_Touch()
        return FALSE;
 }
 
-void WarpZone_InitStep_FindTarget()
+void WarpZone_InitStep_FindOriginTarget()
 {
-       entity e;
-
        if(self.killtarget != "")
        {
                self.aiment = find(world, targetname, self.killtarget);
@@ -264,24 +307,12 @@ void WarpZone_InitStep_FindTarget()
                        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");
@@ -305,18 +336,24 @@ void WarpZonePosition_InitStep_FindTarget()
 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()
@@ -327,12 +364,6 @@ 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);
@@ -344,7 +375,7 @@ void WarpZone_InitStep_UpdateTransform()
                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)
@@ -408,10 +439,57 @@ void WarpZone_InitStep_UpdateTransform()
        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;
@@ -487,6 +565,21 @@ void spawnfunc_func_camera(void)
        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;
@@ -495,17 +588,59 @@ void WarpZone_StartFrame()
                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 :(
+}