]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/warpzonelib/server.qc
Merge branch 'master' into terencehill/color_picker_carets
[xonotic/xonotic-data.pk3dir.git] / qcsrc / warpzonelib / server.qc
index da69a82e750f8a761afd6e3e675079da40f329cd..3d4a750455a3e5947b073e3c62e698a9d347ea74 100644 (file)
@@ -1,3 +1,5 @@
+#define REMOVEHACK
+
 // for think function
 .vector warpzone_save_origin;
 .vector warpzone_save_angles;
@@ -7,6 +9,7 @@
 // for all entities
 .vector warpzone_oldorigin, warpzone_oldvelocity, warpzone_oldangles;
 .float warpzone_teleport_time;
+.float warpzone_teleport_finishtime;
 .entity warpzone_teleport_zone;
 
 void WarpZone_StoreProjectileData(entity e)
@@ -18,7 +21,7 @@ void WarpZone_StoreProjectileData(entity e)
 
 void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity)
 {
-       setorigin (player, to);
+       setorigin (player, to); // NOTE: this also aborts the move, when this is called by touch
        player.oldorigin = to; // for DP's unsticking
        player.angles = to_angles;
        player.fixangle = TRUE;
@@ -41,39 +44,15 @@ float WarpZone_Teleported_Send(entity to, float sf)
        return TRUE;
 }
 
-#define WARPZONE_TELEPORT_FIXSOLID(ret) \
-       { \
-               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); \
-               } \
-       }
-#define WARPZONE_TELEPORT_DOTELEPORT() \
-       { \
-               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; \
-       }
-
 float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
 {
-       vector o0, a0, v0, o1, a1, v1;
+       vector o0, a0, v0, o1, a1, v1, o10;
 
        o0 = player.origin + player.view_ofs;
        v0 = player.velocity;
        a0 = player.angles;
 
-       o1 = WarpZone_TransformOrigin(wz, o0);
+       o10 = o1 = WarpZone_TransformOrigin(wz, o0);
        v1 = WarpZone_TransformVelocity(wz, v0);
        if(clienttype(player) != CLIENTTYPE_NOTACLIENT)
                a1 = WarpZone_TransformVAngles(wz, player.v_angle);
@@ -95,19 +74,44 @@ float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
                }
                o1 = trace_endpos + player.view_ofs;
 
-               float d, dv;
+               float d, dv, md;
+               md = max(vlen(player.mins), vlen(player.maxs));
                d = WarpZone_TargetPlaneDist(wz, o1);
                dv = WarpZone_TargetPlaneDist(wz, v1);
                if(d < 0)
                        o1 = o1 - v1 * (d / dv);
        }
 
-       // put him inside solid
+       // put him out of solid
        tracebox(o1 - player.view_ofs, player.mins, player.maxs, o1 - player.view_ofs, MOVE_NOMONSTERS, player);
        if(trace_startsolid)
-               WARPZONE_TELEPORT_FIXSOLID(0);
+       {
+               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 0;
+               }
+       }
+
+       // do the teleport
+       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_finishtime = time;
+       player.warpzone_teleport_zone = wz;
 
-       WARPZONE_TELEPORT_DOTELEPORT();
+       // prevent further teleports back
+       float dt = (o1 - o10) * v1 * (1 / (v1 * v1));
+       if(dt < sys_frametime)
+               player.warpzone_teleport_finishtime += sys_frametime - dt;
 
 #ifndef WARPZONE_USE_FIXANGLE
        if(player.classname == "player")
@@ -135,16 +139,16 @@ float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
 
 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
+       if(time <= other.warpzone_teleport_finishtime) // 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 || other.movetype == MOVETYPE_FOLLOW)
+       if(other.movetype == MOVETYPE_NONE || other.movetype == MOVETYPE_FOLLOW || other.tag_entity)
                return;
 
        if(WarpZoneLib_ExactTrigger_Touch())
@@ -153,7 +157,24 @@ void WarpZone_Touch (void)
        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))
+       float f;
+       // number of frames we need to go back:
+       //   dist = 16*sqrt(2) qu
+       //   dist ~ 24 qu
+       //   24 qu = v*t
+       //   24 qu = v*frametime*n
+       //       n = 24 qu/(v*frametime)
+       // for clients go only one frame though, may be too irritating otherwise
+       // but max 0.25 sec = 0.25/frametime frames
+       //       24/(0.25/frametime)
+       //       96*frametime
+       float d;
+       d = 24 + max(vlen(other.mins), vlen(other.maxs));
+       if(clienttype(other) == CLIENTTYPE_NOTACLIENT)
+               f = -d / bound(frametime * d * 1, frametime * vlen(other.velocity), d);
+       else
+               f = -1;
+       if(WarpZone_Teleport(self, other, f, 0))
        {
                string save1, save2;
                activator = other;
@@ -279,43 +300,70 @@ float WarpZone_Camera_Send(entity to, float sendflags)
        return TRUE;
 }
 
-float WarpZone_CheckProjectileImpact()
+float WarpZone_CheckProjectileImpact(entity player)
 {
-       entity player;
-       player = self;
-       vector o0, a0, v0, o1, a1, v1;
+       vector o0, v0;
 
        o0 = player.origin + player.view_ofs;
        v0 = player.velocity;
-       a0 = player.angles;
+
+       // if we teleported shortly before, abort
+       if(time <= player.warpzone_teleport_finishtime + 0.1)
+               return 0;
 
        // if player hit a warpzone, abort
-       float mpd, pd, dpd;
        entity wz;
        wz = WarpZone_Find(o0 + player.mins, o0 + player.maxs);
        if(!wz)
                return 0;
-       if(player.warpzone_teleport_time == time)
-       {
-               // just ignore if we got teleported this frame already and now hit a wall and are in a warpzone again (this will cause a detonation)
-               // print("2 warps 1 frame\n");
-               return -1;
-       }
 
+#ifdef REMOVEHACK
+       print("impactfilter found something - and it no longer gets handled correctly - please tell divVerent whether anything behaves broken now\n");
+#else
+       print("impactfilter found something - and it even gets handled correctly - please tell divVerent that this code apparently gets triggered again\n");
+#endif
+       print("Entity type: ", player.classname, "\n");
+       print("Origin: ", vtos(player.origin), "\n");
+       print("Velocity: ", vtos(player.velocity), "\n");
+
+#ifdef REMOVEHACK
+       return 0;
+#else
        // retry previous move
        setorigin(player, player.warpzone_oldorigin);
        player.velocity = player.warpzone_oldvelocity;
        if(WarpZone_Teleport(wz, player, 0, 1))
        {
-               print(sprintf("teleported by impact filter!\n"));
+               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);
+               setorigin(player, o0 - player.view_ofs);
                player.velocity = v0;
        }
 
        return +1;
+#endif
 }
 float WarpZone_Projectile_Touch()
 {
@@ -324,10 +372,10 @@ float WarpZone_Projectile_Touch()
                return TRUE;
 
        // no further impacts if we teleported this frame!
-       if(self.warpzone_teleport_time == time)
+       if(time == self.warpzone_teleport_time)
                return TRUE;
 
-#if 0
+       // this SEEMS to not happen at the moment, but if it did, it would be more reliable
        {
                float save_dpstartcontents;
                float save_dphitcontents;
@@ -355,7 +403,7 @@ float WarpZone_Projectile_Touch()
                save_ent = trace_ent;
                save_inopen = trace_inopen;
                save_inwater = trace_inwater;
-               if((f = WarpZone_CheckProjectileImpact()) != 0)
+               if((f = WarpZone_CheckProjectileImpact(self)) != 0)
                        return (f > 0);
                trace_dpstartcontents = save_dpstartcontents;
                trace_dphitcontents = save_dphitcontents;
@@ -371,20 +419,10 @@ float WarpZone_Projectile_Touch()
                trace_inopen = save_inopen;
                trace_inwater = save_inwater;
        }
-#endif
 
        if(WarpZone_Projectile_Touch_ImpactFilter_Callback())
                return TRUE;
 
-       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;
 }
 
@@ -747,43 +785,50 @@ void WarpZone_StartFrame()
                        WarpZone_InitStep_UpdateTransform();
                self = e;
                WarpZones_Reconnect();
+               WarpZone_PostInitialize_Callback();
        }
 
-       if(warpzone_warpzones_exist)
+       entity oldself, oldother;
+       oldself = self;
+       oldother = other;
+       for(e = world; (e = nextent(e)); )
        {
-               entity oldself, oldother;
-               oldself = self;
-               oldother = other;
-               for(e = world; (e = nextent(e)); )
+               if(warpzone_warpzones_exist) { WarpZone_StoreProjectileData(e); }
+               
+               float f = clienttype(e);
+               if(f == CLIENTTYPE_REAL)
                {
-                       WarpZone_StoreProjectileData(e);
-                       float f;
-                       f = clienttype(e);
-                       if(f == CLIENTTYPE_REAL)
+                       if(e.solid == SOLID_NOT) // not spectating?
+                       if(e.movetype == MOVETYPE_NOCLIP || e.movetype == MOVETYPE_FLY || e.movetype == MOVETYPE_FLY_WORLDONLY) // not spectating? (this is to catch observers)
                        {
-                               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!
+                               other = e; // player
+                       
+                               // warpzones
+                               if(warpzone_warpzones_exist) { 
+                               self = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs); 
+                               if(self)
+                               if(!WarpZoneLib_ExactTrigger_Touch())
+                                       if(WarpZone_PlaneDist(self, e.origin + e.view_ofs) <= 0)
+                                               WarpZone_Teleport(self, e, -1, 0); } // NOT triggering targets by this!
+                       
+                               // teleporters
+                               self = Teleport_Find(e.origin + e.mins, e.origin + e.maxs);
+                               if(self)
+                               if(!WarpZoneLib_ExactTrigger_Touch())
+                                       Simple_TeleportPlayer(self, other); // NOT triggering targets by this!
                        }
-                       if(f == CLIENTTYPE_NOTACLIENT)
-                       {
+               }
+               
+               if(f == CLIENTTYPE_NOTACLIENT)
+               {
+                       if(warpzone_warpzones_exist)
                                for(; (e = nextent(e)); )
                                        WarpZone_StoreProjectileData(e);
-                               break;
-                       }
+                       break;
                }
-               self = oldself;
-               other = oldother;
        }
+       self = oldself;
+       other = oldother;
 }
 
 .float warpzone_reconnecting;