From 14aef0c52085bf8fce7b76b10d8862aabc43c6e4 Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 18 May 2020 22:10:24 +1000 Subject: [PATCH] Rewrite trigger_swamp to not require spawning new entities per player, implementation based on conveyor code. Removes need to network the swamp to the client, improving prediction and reducing network usage, also solves the swamp effect staying attached to the player for a second after they leave the swamp --- qcsrc/common/mapobjects/trigger/swamp.qc | 155 +++++++---------------- qcsrc/common/mapobjects/trigger/swamp.qh | 14 +- qcsrc/common/physics/player.qc | 2 +- qcsrc/ecs/systems/physics.qc | 2 +- qcsrc/server/client.qc | 5 +- 5 files changed, 52 insertions(+), 126 deletions(-) diff --git a/qcsrc/common/mapobjects/trigger/swamp.qc b/qcsrc/common/mapobjects/trigger/swamp.qc index 27940828e..495deb798 100644 --- a/qcsrc/common/mapobjects/trigger/swamp.qc +++ b/qcsrc/common/mapobjects/trigger/swamp.qc @@ -16,97 +16,47 @@ * 2005 11 29 */ - -/* -* Uses a entity calld swampslug to handle players in the swamp -* It works like this: When the plyer enters teh swamp the spawnfunc_trigger_swamp -* attaches a new "swampslug" to the player. As long as the plyer is inside -* the swamp the swamp gives the slug new health. But the slug slowly kills itself -* so when the player goes outside the swamp, it dies and releases the player from the -* swamps curses (dmg/slowdown) -* -* I do it this way becuz there is no "untouch" event. -*/ -void swampslug_think(entity this) -{ - //Slowly kill the slug - this.swamp_lifetime -= 1; - - //Slug dead? then remove curses. - if(this.swamp_lifetime <= 0) - { - if(this.owner.swampslug == this) - { - this.owner.in_swamp = false; - this.owner.swampslug = NULL; - } - delete(this); - //centerprint(this.owner,"Killing slug...\n"); - return; - } - - // Slug still alive, so we are still in the swamp - // Or we have exited it very recently. - // Do the damage and renew the timer. #ifdef SVQC - Damage (this.owner, this, this, this.dmg, DEATH_SWAMP.m_id, DMG_NOWEP, this.owner.origin, '0 0 0'); -#endif - - this.nextthink = time + this.swamp_interval; -} - -void swamp_touch(entity this, entity toucher) +void swamp_think(entity this) { - // If whatever thats touching the swamp is not a player - // or if its a dead player, just dont care abt it. - if(!IS_PLAYER(toucher) || IS_DEAD(toucher)) - return; - - EXACTTRIGGER_TOUCH(this, toucher); + // set myself as current swampslug where possible + IL_EACH(g_swamped, it.swampslug == this, + { + it.swampslug = NULL; + IL_REMOVE(g_swamped, it); + }); - // Chech if player alredy got a swampslug. - if(!toucher.in_swamp) + if(this.active == ACTIVE_ACTIVE) { - // If not attach one. - //centerprint(toucher,"Entering swamp!\n"); - if(!toucher.swampslug) // just incase - toucher.swampslug = spawn(); - toucher.swampslug.swamp_lifetime = 2; - setthink(toucher.swampslug, swampslug_think); - toucher.swampslug.nextthink = time; - toucher.swampslug.owner = toucher; - toucher.swampslug.dmg = this.dmg; - toucher.swampslug.swamp_interval = this.swamp_interval; - toucher.swamp_slowdown = this.swamp_slowdown; - toucher.in_swamp = true; - return; + FOREACH_ENTITY_RADIUS((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1, it.swampslug.active == ACTIVE_NOT && IS_PLAYER(it) && !IS_DEAD(it), + { + vector emin = it.absmin; + vector emax = it.absmax; + if(this.solid == SOLID_BSP) + { + emin -= '1 1 1'; + emax += '1 1 1'; + } + if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick + if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate + { + if(!it.swampslug) + IL_PUSH(g_swamped, it); + it.swampslug = this; + } + }); + + IL_EACH(g_swamped, it.swampslug == this, + { + if(time > it.swamp_interval) + { + Damage (it, this, this, this.dmg, DEATH_SWAMP.m_id, DMG_NOWEP, it.origin, '0 0 0'); + it.swamp_interval = time + this.swamp_interval; + } + }); } - //toucher.in_swamp = true; - - //Revitalize players swampslug - toucher.swampslug.swamp_lifetime = 2; -} - -REGISTER_NET_LINKED(ENT_CLIENT_SWAMP) - -#ifdef SVQC -float swamp_send(entity this, entity to, float sf) -{ - WriteHeader(MSG_ENTITY, ENT_CLIENT_SWAMP); - - WriteByte(MSG_ENTITY, this.dmg); // can probably get away with using a single byte here - WriteByte(MSG_ENTITY, this.swamp_slowdown); - WriteByte(MSG_ENTITY, this.swamp_interval); - - trigger_common_write(this, false); - - return true; -} - -void swamp_link(entity this) -{ - trigger_link(this, swamp_send); + this.nextthink = time; } /*QUAKED spawnfunc_trigger_swamp (.5 .5 .5) ? @@ -116,37 +66,18 @@ slowed down and damaged over time spawnfunc(trigger_swamp) { // Init stuff - trigger_init(this); - settouch(this, swamp_touch); + EXACTTRIGGER_INIT; + this.active = ACTIVE_ACTIVE; + //trigger_init(this); + setthink(this, swamp_think); + this.nextthink = time; // Setup default keys, if missing - if(this.dmg <= 0) + if(!this.dmg) this.dmg = 5; - if(this.swamp_interval <= 0) + if(!this.swamp_interval) this.swamp_interval = 1; - if(this.swamp_slowdown <= 0) + if(!this.swamp_slowdown) this.swamp_slowdown = 0.5; - - swamp_link(this); -} - -#elif defined(CSQC) - -NET_HANDLE(ENT_CLIENT_SWAMP, bool isnew) -{ - this.dmg = ReadByte(); - this.swamp_slowdown = ReadByte(); - this.swamp_interval = ReadByte(); - - trigger_common_read(this, false); - - return = true; - - this.classname = "trigger_swamp"; - this.solid = SOLID_TRIGGER; - settouch(this, swamp_touch); - this.drawmask = MASK_NORMAL; - this.move_time = time; - this.entremove = trigger_remove_generic; } #endif diff --git a/qcsrc/common/mapobjects/trigger/swamp.qh b/qcsrc/common/mapobjects/trigger/swamp.qh index bfe860ed0..acb0cb26a 100644 --- a/qcsrc/common/mapobjects/trigger/swamp.qh +++ b/qcsrc/common/mapobjects/trigger/swamp.qh @@ -1,17 +1,11 @@ #pragma once -.float swamp_interval; //Hurt players in swamp with this interval -.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?) +#ifdef SVQC +IntrusiveList g_swamped; +STATIC_INIT(g_swamped) { g_swamped = IL_NEW(); } -.bool in_swamp; .entity swampslug; // Uses this to release from swamp ("untouch" fix) .float swamp_interval; //Hurt players in swamp with this interval -.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?) -.float swamp_lifetime; // holds the points remaining until slug dies (not quite health!) - -#ifdef SVQC -spawnfunc(trigger_swamp); +.float swamp_slowdown; //Players in swamp get slowed down by this mutch 0-1 is slowdown 1-~ is speedup (!?) #endif -void swamp_touch(entity this, entity toucher); -void swampslug_think(entity this); diff --git a/qcsrc/common/physics/player.qc b/qcsrc/common/physics/player.qc index 5dce802a0..cba24ff8e 100644 --- a/qcsrc/common/physics/player.qc +++ b/qcsrc/common/physics/player.qc @@ -40,7 +40,7 @@ void Physics_UpdateStats(entity this) STAT(MOVEVARS_HIGHSPEED, this) = autocvar_g_movement_highspeed; MUTATOR_CALLHOOK(PlayerPhysics_UpdateStats, this); - float maxspd_mod = PHYS_HIGHSPEED(this); + float maxspd_mod = PHYS_HIGHSPEED(this) * ((this.swampslug.active) ? this.swampslug.swamp_slowdown : 1); STAT(MOVEVARS_MAXSPEED, this) = Physics_ClientOption(this, "maxspeed", autocvar_sv_maxspeed) * maxspd_mod; // also slow walking if (autocvar_g_movement_highspeed_q3_compat) { STAT(MOVEVARS_AIRACCEL_QW, this) = Physics_ClientOption(this, "airaccel_qw", autocvar_sv_airaccel_qw); diff --git a/qcsrc/ecs/systems/physics.qc b/qcsrc/ecs/systems/physics.qc index cd59c516c..41506ec31 100644 --- a/qcsrc/ecs/systems/physics.qc +++ b/qcsrc/ecs/systems/physics.qc @@ -47,7 +47,7 @@ void sys_phys_update(entity this, float dt) PM_check_blocked(this); - float maxspeed_mod = (!this.in_swamp) ? 1 : this.swamp_slowdown; // cvar("g_balance_swamp_moverate"); + float maxspeed_mod = 1; // conveyors: first fix velocity if (this.conveyor.active) { this.velocity -= this.conveyor.movedir; } diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index b4947635f..79dca0076 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -687,8 +687,9 @@ void PutPlayerInServer(entity this) IL_REMOVE(g_conveyed, this); this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player if(this.swampslug) - delete(this.swampslug); - this.in_swamp = false; + IL_REMOVE(g_swamped, this); + this.swampslug = NULL; + this.swamp_interval = 0; STAT(HUD, this) = HUD_NORMAL; this.event_damage = PlayerDamage; -- 2.39.2