]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Predict teleporters (yay)
authorMario <mario@smbclan.net>
Sun, 29 Nov 2015 14:24:23 +0000 (00:24 +1000)
committerMario <mario@smbclan.net>
Sun, 29 Nov 2015 14:24:23 +0000 (00:24 +1000)
qcsrc/common/stats.qh
qcsrc/common/triggers/misc/teleport_dest.qc
qcsrc/common/triggers/teleporters.qc
qcsrc/common/triggers/teleporters.qh
qcsrc/common/triggers/trigger/jumppads.qc
qcsrc/common/triggers/trigger/teleport.qc
qcsrc/common/triggers/triggers.qc

index 81da6e23de73e544b32c3f02ebda1b887833c164..6825ff76b6a89548570ff92e3d0df7287d83d40e 100644 (file)
@@ -207,6 +207,9 @@ REGISTER_STAT(DOM_PPS_BLUE, float)
 REGISTER_STAT(DOM_PPS_YELLOW, float)
 REGISTER_STAT(DOM_PPS_PINK, float)
 
+REGISTER_STAT(TELEPORT_MAXSPEED, float, autocvar_g_teleport_maxspeed)
+REGISTER_STAT(TELEPORT_TELEFRAG_AVOID, int, autocvar_g_telefrags_avoid)
+
 #ifdef SVQC
 #include "movetypes/movetypes.qh"
 #endif
index 00752cfa59c5faa92a39756d31272ceec224e03a..a53b5c056c89c848ace83738b71a70e0dfcd7e61 100644 (file)
@@ -1,5 +1,31 @@
+REGISTER_NET_LINKED(ENT_CLIENT_TELEPORT_DEST)
+
 #ifdef SVQC
 
+bool teleport_dest_send(entity this, entity to, float sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TELEPORT_DEST);
+
+       WriteByte(MSG_ENTITY, self.cnt);
+       WriteCoord(MSG_ENTITY, self.speed);
+       WriteString(MSG_ENTITY, self.targetname);
+       WriteCoord(MSG_ENTITY, self.origin_x);
+       WriteCoord(MSG_ENTITY, self.origin_y);
+       WriteCoord(MSG_ENTITY, self.origin_z);
+
+       WriteAngle(MSG_ENTITY, self.mangle_x);
+       WriteAngle(MSG_ENTITY, self.mangle_y);
+       WriteAngle(MSG_ENTITY, self.mangle_z);
+
+       return true;
+}
+
+void teleport_dest_link()
+{SELFPARAM();
+       Net_LinkEntity(self, false, 0, teleport_dest_send);
+       //self.SendFlags |= 1; // update
+}
+
 spawnfunc(info_teleport_destination)
 {
        self.classname = "info_teleport_destination";
@@ -15,6 +41,8 @@ spawnfunc(info_teleport_destination)
        }
        else
                objerror ("^3Teleport destination without a targetname");
+
+       teleport_dest_link();
 }
 
 spawnfunc(misc_teleporter_dest)
@@ -27,4 +55,39 @@ spawnfunc(target_teleporter)
        spawnfunc_info_teleport_destination(this);
 }
 
+#elif defined(CSQC)
+
+void teleport_dest_remove()
+{SELFPARAM();
+       //if(self.classname)
+               //strunzone(self.classname);
+       //self.classname = string_null;
+
+       if(self.targetname)
+               strunzone(self.targetname);
+       self.targetname = string_null;
+}
+
+NET_HANDLE(ENT_CLIENT_TELEPORT_DEST, bool isnew)
+{
+       self.classname = "info_teleport_destination";
+       self.cnt = ReadByte();
+       self.speed = ReadCoord();
+       self.targetname = strzone(ReadString());
+       self.origin_x = ReadCoord();
+       self.origin_y = ReadCoord();
+       self.origin_z = ReadCoord();
+
+       self.mangle_x = ReadAngle();
+       self.mangle_y = ReadAngle();
+       self.mangle_z = ReadAngle();
+
+       return = true;
+
+       setorigin(self, self.origin);
+
+       self.drawmask = MASK_NORMAL;
+       self.entremove = teleport_dest_remove;
+}
+
 #endif
index 1f0c00e5e8e2d36211cffe95d5bd1b26390b7771..f990cd1d529d281270026082dd53f6ac6d24916b 100644 (file)
     #include "../../server/anticheat.qh"
 #endif
 
-#ifdef SVQC
-
 float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax)
 {
-       if (IS_PLAYER(player) && player.health >= 1)
+       if (IS_PLAYER(player) && !PHYS_DEAD(player))
        {
                TDEATHLOOP(org)
                {
+               #ifdef SVQC
                        if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
+               #endif
                                if(IS_PLAYER(head))
-                                       if(head.health >= 1)
+                                       if(!PHYS_DEAD(head))
                                                return 1;
                }
        }
        return 0;
 }
 
+#ifdef SVQC
+
+void trigger_teleport_link(entity this);
+
 void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax)
 {
        TDEATHLOOP(player.origin)
@@ -61,6 +65,8 @@ void spawn_tdeath(vector v0, entity e, vector v)
        tdeath(e, e, e, '0 0 0', '0 0 0');
 }
 
+#endif
+
 void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags)
 {SELFPARAM();
        entity telefragger;
@@ -73,6 +79,7 @@ void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angle
 
        makevectors (to_angles);
 
+#ifdef SVQC
        if(player.teleportable == TELEPORT_NORMAL) // don't play sounds or show particles for anything that isn't a player, maybe change later to block only observers
        {
                if(self.pushltime < time) // only show one teleport effect per teleporter per 0.2 seconds, for better fps
@@ -87,9 +94,11 @@ void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angle
                        self.pushltime = time + 0.2;
                }
        }
+#endif
 
        // Relocate the player
        // assuming to allows PL_MIN to PL_MAX box and some more
+#ifdef SVQC
        from = player.origin;
        setorigin (player, to);
        player.oldorigin = to; // don't undo the teleport by unsticking
@@ -101,7 +110,22 @@ void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angle
        makevectors(player.angles);
        Reset_ArcBeam(player, v_forward);
        UpdateCSQCProjectileAfterTeleport(player);
+#elif defined(CSQC)
+       from = player.move_origin;
+       player.move_origin = to;
+       player.move_angles = to_angles;
+       player.move_velocity = to_velocity;
+       player.move_flags &= ~FL_ONGROUND;
+       player.iflags |= IFLAG_TELEPORTED | IFLAG_V_ANGLE | IFLAG_ANGLES;
+       player.csqcmodel_teleported = 1;
+       player.v_angle = to_angles;
+       setproperty(VF_ANGLES, player.move_angles);
+       setproperty(VF_CL_VIEWANGLES, player.move_angles);
+
+       makevectors(player.move_angles);
+#endif
 
+#ifdef SVQC
        if(IS_PLAYER(player))
        {
                if(tflags & TELEPORT_FLAG_TDEATH)
@@ -129,6 +153,7 @@ void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angle
 
                player.lastteleporttime = time;
        }
+#endif
 }
 
 entity Simple_TeleportPlayer(entity teleporter, entity player)
@@ -148,9 +173,13 @@ entity Simple_TeleportPlayer(entity teleporter, entity player)
                for(e = world; (e = find(e, targetname, teleporter.target)); )
                {
                        p = 1;
-                       if(autocvar_g_telefrags_avoid)
+                       if(STAT(TELEPORT_TELEFRAG_AVOID, player))
                        {
+                       #ifdef SVQC
                                locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+                       #elif defined(CSQC)
+                               locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+                       #endif
                                if(check_tdeath(player, locout, '0 0 0', '0 0 0'))
                                        p = 0;
                        }
@@ -159,37 +188,60 @@ entity Simple_TeleportPlayer(entity teleporter, entity player)
                e = RandomSelection_chosen_ent;
        }
 
+#ifdef SVQC
        if(!e) { sprint(player, "Teleport destination vanished. Sorry... please complain to the mapper.\n"); }
+#elif defined(CSQC)
+       if(!e) { LOG_INFO("Teleport destination could not be found from CSQC.\n"); }
+#endif
 
        makevectors(e.mangle);
 
+#ifdef SVQC
        if(e.speed)
                if(vlen(player.velocity) > e.speed)
                        player.velocity = normalize(player.velocity) * max(0, e.speed);
+#elif defined(CSQC)
+       if(e.speed)
+               if(vlen(player.move_velocity) > e.speed)
+                       player.move_velocity = normalize(player.move_velocity) * max(0, e.speed);
+#endif
 
-       if(autocvar_g_teleport_maxspeed)
-               if(vlen(player.velocity) > autocvar_g_teleport_maxspeed)
-                       player.velocity = normalize(player.velocity) * max(0, autocvar_g_teleport_maxspeed);
+#ifdef SVQC
+       if(STAT(TELEPORT_MAXSPEED, player))
+               if(vlen(player.velocity) > STAT(TELEPORT_MAXSPEED, player))
+                       player.velocity = normalize(player.velocity) * max(0, STAT(TELEPORT_MAXSPEED, player));
+#elif defined(CSQC)
+       if(STAT(TELEPORT_MAXSPEED, player))
+               if(vlen(player.move_velocity) > STAT(TELEPORT_MAXSPEED, player))
+                       player.move_velocity = normalize(player.move_velocity) * max(0, STAT(TELEPORT_MAXSPEED, player));
+#endif
 
+#ifdef SVQC
        locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+
        TeleportPlayer(teleporter, player, locout, e.mangle, v_forward * vlen(player.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
+#elif defined(CSQC)
+       locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+
+       TeleportPlayer(teleporter, player, locout, e.mangle, v_forward * vlen(player.move_velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
+#endif
 
        return e;
 }
 
-void teleport_findtarget ()
-{SELFPARAM();
+void teleport_findtarget()
+{
+       int n = 0;
        entity e;
-       float n;
-
-       n = 0;
        for(e = world; (e = find(e, targetname, self.target)); )
        {
                ++n;
+#ifdef SVQC
                if(e.movetype == MOVETYPE_NONE)
                        waypoint_spawnforteleporter(self, e.origin, 0);
                if(e.classname != "info_teleport_destination")
                        LOG_INFO("^3MAPPER ERROR: teleporter does target an invalid teleport destination entity. Angles will not work.\n");
+#endif
        }
 
        if(n == 0)
@@ -210,7 +262,13 @@ void teleport_findtarget ()
        }
 
        // now enable touch
+#ifdef SVQC
        self.touch = Teleport_Touch;
+
+       trigger_teleport_link(self);
+#elif defined(CSQC)
+       self.move_touch = Teleport_Touch;
+#endif
 }
 
 entity Teleport_Find(vector mi, vector ma)
@@ -222,6 +280,7 @@ entity Teleport_Find(vector mi, vector ma)
        return world;
 }
 
+#ifdef SVQC
 void WarpZone_PostTeleportPlayer_Callback(entity pl)
 {SELFPARAM();
        makevectors(pl.angles);
index 01e738e43de17e3be53160ea1b91866c5cfb14cb..fb31785e7fdc0901448110a45e109ee1c2eb0fe3 100644 (file)
@@ -1,6 +1,33 @@
 #ifndef T_TELEPORTERS_H
 #define T_TELEPORTERS_H
 
+.entity pusher;
+const float TELEPORT_FLAG_SOUND = 1;
+const float TELEPORT_FLAG_PARTICLES = 2;
+const float TELEPORT_FLAG_TDEATH = 4;
+const float TELEPORT_FLAG_FORCE_TDEATH = 8;
+
+#define TELEPORT_FLAGS_WARPZONE   0
+#define TELEPORT_FLAGS_PORTAL     (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH | TELEPORT_FLAG_FORCE_TDEATH)
+#define TELEPORT_FLAGS_TELEPORTER (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH)
+
+// types for .teleportable entity setting
+const float TELEPORT_NORMAL = 1; // play sounds/effects etc
+const float TELEPORT_SIMPLE = 2; // only do teleport, nothing special
+
+entity Simple_TeleportPlayer(entity teleporter, entity player);
+
+void Teleport_Touch ();
+
+void teleport_findtarget();
+
+entity Teleport_Find(vector mi, vector ma);
+
+void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags);
+
+entity teleport_first;
+.entity teleport_next;
+
 #ifdef SVQC
 
 void trigger_teleport_use();
@@ -27,42 +54,39 @@ void trigger_teleport_use();
                        if(head.takedamage) \
                                if(boxesoverlap(deathmin, deathmax, head.absmin, head.absmax))
 
-
 float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax);
 float tdeath_hit;
 void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax);
 
 void spawn_tdeath(vector v0, entity e, vector v);
 
-.entity pusher;
-const float TELEPORT_FLAG_SOUND = 1;
-const float TELEPORT_FLAG_PARTICLES = 2;
-const float TELEPORT_FLAG_TDEATH = 4;
-const float TELEPORT_FLAG_FORCE_TDEATH = 8;
-
-#define TELEPORT_FLAGS_WARPZONE   0
-#define TELEPORT_FLAGS_PORTAL     (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH | TELEPORT_FLAG_FORCE_TDEATH)
-#define TELEPORT_FLAGS_TELEPORTER (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH)
-
-// types for .teleportable entity setting
-const float TELEPORT_NORMAL = 1; // play sounds/effects etc
-const float TELEPORT_SIMPLE = 2; // only do teleport, nothing special
-
 void Reset_ArcBeam(entity player, vector forward);
-void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags);
-
-entity Simple_TeleportPlayer(entity teleporter, entity player);
-
-void Teleport_Touch ();
-
-void teleport_findtarget ();
-
-entity Teleport_Find(vector mi, vector ma);
-
-entity teleport_first;
-.entity teleport_next;
 
 void WarpZone_PostTeleportPlayer_Callback(entity pl);
 #endif
 
+#ifdef CSQC
+#define TDEATHLOOP(o) \
+       entity head; \
+       vector deathmin; \
+       vector deathmax; \
+       float deathradius; \
+       deathmin = (o) + player.mins; \
+       deathmax = (o) + player.maxs; \
+       if(telefragmin != telefragmax) \
+       { \
+               if(deathmin.x > telefragmin.x) deathmin.x = telefragmin.x; \
+               if(deathmin.y > telefragmin.y) deathmin.y = telefragmin.y; \
+               if(deathmin.z > telefragmin.z) deathmin.z = telefragmin.z; \
+               if(deathmax.x < telefragmax.x) deathmax.x = telefragmax.x; \
+               if(deathmax.y < telefragmax.y) deathmax.y = telefragmax.y; \
+               if(deathmax.z < telefragmax.z) deathmax.z = telefragmax.z; \
+       } \
+       deathradius = max(vlen(deathmin), vlen(deathmax)); \
+       for(head = findradius(o, deathradius); head; head = head.chain) \
+               if(head != player) \
+                       if(head.isplayermodel) \
+                               if(boxesoverlap(deathmin, deathmax, head.absmin, head.absmax))
+#endif
+
 #endif
index c6ba73b73c7c7225ea10e798d66224ce67489710..6a4332681bb89032a5297aa972c7eaa9f982f28b 100644 (file)
@@ -170,9 +170,11 @@ void trigger_push_touch()
                other.move_velocity = other.velocity;
        }
 
+#ifdef SVQC
        UNSET_ONGROUND(other);
-
+#elif defined(CSQC)
        other.move_flags &= ~FL_ONGROUND;
+#endif
 
 #ifdef SVQC
        if (IS_PLAYER(other))
index 6522669200dee79b380f9c9b9d26bbe94c973c24..88bf33b8addb581e0a69e5377760bf276cf150af 100644 (file)
@@ -1,3 +1,5 @@
+REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_TELEPORT)
+
 #ifdef SVQC
 void trigger_teleport_use()
 {SELFPARAM();
@@ -7,14 +9,14 @@ void trigger_teleport_use()
        self.SendFlags |= SF_TRIGGER_UPDATE;
 #endif
 }
+#endif
 
 void Teleport_Touch ()
 {SELFPARAM();
-       string s;
-
        if (self.active != ACTIVE_ACTIVE)
                return;
 
+#ifdef SVQC
        if (!other.teleportable)
                return;
 
@@ -24,27 +26,63 @@ void Teleport_Touch ()
 
        if(IS_TURRET(other))
                return;
+#endif
 
-       if(other.deadflag != DEAD_NO)
+       if(PHYS_DEAD(other))
                return;
 
        if(self.team)
-               if(((self.spawnflags & 4) == 0) == (self.team != other.team))
+               if(((self.spawnflags & 4) == 0) == (DIFF_TEAM(this, other)))
                        return;
 
        EXACTTRIGGER_TOUCH;
 
+#ifdef SVQC
        if(IS_PLAYER(other))
                RemoveGrapplingHook(other);
+#endif
 
-       entity e = Simple_TeleportPlayer(self, other);
+       entity e;
+       e = Simple_TeleportPlayer(self, other);
 
+#ifdef SVQC
        activator = other;
-       s = self.target; self.target = string_null;
+       string s = self.target; self.target = string_null;
        SUB_UseTargets();
        if (!self.target) self.target = s;
 
        WITH(entity, self, e, SUB_UseTargets());
+#endif
+}
+
+#ifdef SVQC
+float trigger_teleport_send(entity this, entity to, float sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_TELEPORT);
+       WriteByte(MSG_ENTITY, sf);
+
+       if(sf & 1)
+       {
+               WriteByte(MSG_ENTITY, self.team);
+               WriteInt24_t(MSG_ENTITY, self.spawnflags);
+               WriteByte(MSG_ENTITY, self.active);
+               WriteCoord(MSG_ENTITY, self.speed);
+
+               trigger_common_write(true);
+       }
+
+       if(sf & 2)
+       {
+               WriteByte(MSG_ENTITY, self.team);
+               WriteByte(MSG_ENTITY, self.active);
+       }
+
+       return true;
+}
+
+void trigger_teleport_link(entity this)
+{
+       Net_LinkEntity(this, false, 0, trigger_teleport_send);
 }
 
 spawnfunc(trigger_teleport)
@@ -69,4 +107,39 @@ spawnfunc(trigger_teleport)
        self.teleport_next = teleport_first;
        teleport_first = self;
 }
+#elif defined(CSQC)
+NET_HANDLE(ENT_CLIENT_TRIGGER_TELEPORT, bool isnew)
+{
+       int sf = ReadByte();
+
+       if(sf & 1)
+       {
+               self.classname = "trigger_teleport";
+               int mytm = ReadByte(); if(mytm) { self.team = mytm - 1; }
+               self.spawnflags = ReadInt24_t();
+               self.active = ReadByte();
+               self.speed = ReadCoord();
+
+               trigger_common_read(true);
+
+               self.entremove = trigger_remove_generic;
+               self.solid = SOLID_TRIGGER;
+               //self.draw = trigger_draw_generic;
+               //self.move_touch = trigger_push_touch;
+               self.drawmask = MASK_NORMAL;
+               self.move_time = time;
+               teleport_findtarget();
+
+               self.teleport_next = teleport_first;
+               teleport_first = self;
+       }
+
+       if(sf & 2)
+       {
+               self.team = ReadByte();
+               self.active = ReadByte();
+       }
+       return true;
+}
+
 #endif
index 41180dd2cc806b020a441b50f03cb2ff08f9f160..cce879eed9b7905c2792ed154fca116ef9ca3a65 100644 (file)
@@ -65,11 +65,17 @@ void trigger_common_read(bool withtarget)
 
        if(withtarget)
        {
+               if(self.target) { strunzone(self.target); }
                self.target = strzone(ReadString());
+               if(self.target2) { strunzone(self.target2); }
                self.target2 = strzone(ReadString());
+               if(self.target3) { strunzone(self.target3); }
                self.target3 = strzone(ReadString());
+               if(self.target4) { strunzone(self.target4); }
                self.target4 = strzone(ReadString());
+               if(self.targetname) { strunzone(self.targetname); }
                self.targetname = strzone(ReadString());
+               if(self.killtarget) { strunzone(self.killtarget); }
                self.killtarget = strzone(ReadString());
        }