From ac0ab7e8b52ac931e7275bcbffe1aebe4259317f Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 30 Nov 2015 00:24:23 +1000 Subject: [PATCH] Predict teleporters (yay) --- qcsrc/common/stats.qh | 3 + qcsrc/common/triggers/misc/teleport_dest.qc | 63 +++++++++++++++ qcsrc/common/triggers/teleporters.qc | 85 +++++++++++++++++---- qcsrc/common/triggers/teleporters.qh | 78 ++++++++++++------- qcsrc/common/triggers/trigger/jumppads.qc | 4 +- qcsrc/common/triggers/trigger/teleport.qc | 85 +++++++++++++++++++-- qcsrc/common/triggers/triggers.qc | 6 ++ 7 files changed, 277 insertions(+), 47 deletions(-) diff --git a/qcsrc/common/stats.qh b/qcsrc/common/stats.qh index 81da6e23d..6825ff76b 100644 --- a/qcsrc/common/stats.qh +++ b/qcsrc/common/stats.qh @@ -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 diff --git a/qcsrc/common/triggers/misc/teleport_dest.qc b/qcsrc/common/triggers/misc/teleport_dest.qc index 00752cfa5..a53b5c056 100644 --- a/qcsrc/common/triggers/misc/teleport_dest.qc +++ b/qcsrc/common/triggers/misc/teleport_dest.qc @@ -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 diff --git a/qcsrc/common/triggers/teleporters.qc b/qcsrc/common/triggers/teleporters.qc index 1f0c00e5e..f990cd1d5 100644 --- a/qcsrc/common/triggers/teleporters.qc +++ b/qcsrc/common/triggers/teleporters.qc @@ -20,23 +20,27 @@ #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); diff --git a/qcsrc/common/triggers/teleporters.qh b/qcsrc/common/triggers/teleporters.qh index 01e738e43..fb31785e7 100644 --- a/qcsrc/common/triggers/teleporters.qh +++ b/qcsrc/common/triggers/teleporters.qh @@ -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 diff --git a/qcsrc/common/triggers/trigger/jumppads.qc b/qcsrc/common/triggers/trigger/jumppads.qc index c6ba73b73..6a4332681 100644 --- a/qcsrc/common/triggers/trigger/jumppads.qc +++ b/qcsrc/common/triggers/trigger/jumppads.qc @@ -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)) diff --git a/qcsrc/common/triggers/trigger/teleport.qc b/qcsrc/common/triggers/trigger/teleport.qc index 652266920..88bf33b8a 100644 --- a/qcsrc/common/triggers/trigger/teleport.qc +++ b/qcsrc/common/triggers/trigger/teleport.qc @@ -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 diff --git a/qcsrc/common/triggers/triggers.qc b/qcsrc/common/triggers/triggers.qc index 41180dd2c..cce879eed 100644 --- a/qcsrc/common/triggers/triggers.qc +++ b/qcsrc/common/triggers/triggers.qc @@ -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()); } -- 2.39.2