From 8c09d39ef139fe7d3fd63386b25daf6f215a678f Mon Sep 17 00:00:00 2001 From: Leshana Date: Sat, 27 Jan 2018 15:42:16 -0500 Subject: [PATCH] Convert ZAS "Airflow" into a subsystem plus fixes * Port of the "Airflow" portions of Yonaguni/EuropaStation#618 * The "airflow" part of ZAS used to be handled by a sleep'd loop. This has the potential to bunch up and lag. Switching to a StonedMC managed subsystem improves it. * Fixed to ensure that zshadow mobs cannot be blown around by the wind no matter how fierce. * Added a message to mobs informing them when their boots save them from being wind-thwapped. * Check w_class on non-item objects if they have it defined (might as well since var/w_class is on /obj) * Tiny optimization of c_airblock --- code/ZAS/Airflow.dm | 133 +++----------------- code/ZAS/Atom.dm | 3 +- code/controllers/subsystems/airflow.dm | 163 +++++++++++++++++++++++++ polaris.dme | 1 + 4 files changed, 181 insertions(+), 119 deletions(-) create mode 100644 code/controllers/subsystems/airflow.dm diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm index fde7b78aca..e5d2b7eb11 100644 --- a/code/ZAS/Airflow.dm +++ b/code/ZAS/Airflow.dm @@ -26,15 +26,17 @@ mob/living/simple_animal/slime/airflow_stun() return mob/living/carbon/human/airflow_stun() - if(shoes) - if(shoes.item_flags & NOSLIP) return 0 + if(shoes && (shoes.item_flags & NOSLIP)) + to_chat(src, "Air suddenly rushes past you!") + return 0 ..() atom/movable/proc/check_airflow_movable(n) + if(!simulated) return 0 if(anchored && !ismob(src)) return 0 - if(!istype(src,/obj/item) && n < vsc.airflow_dense_pressure) return 0 + if(!isobj(src) && n < vsc.airflow_dense_pressure) return 0 return 1 @@ -50,15 +52,20 @@ mob/living/silicon/check_airflow_movable() return 0 -obj/item/check_airflow_movable(n) - . = ..() +obj/check_airflow_movable(n) + if (!(. = ..())) + return 0 + if(isnull(w_class)) + if(n < vsc.airflow_dense_pressure) return 0 //most non-item objs don't have a w_class yet switch(w_class) - if(2) + if(ITEMSIZE_TINY,ITEMSIZE_SMALL) if(n < vsc.airflow_lightest_pressure) return 0 - if(3) + if(ITEMSIZE_NORMAL) if(n < vsc.airflow_light_pressure) return 0 - if(4,5) + if(ITEMSIZE_LARGE,ITEMSIZE_HUGE) if(n < vsc.airflow_medium_pressure) return 0 + else + if(n < vsc.airflow_dense_pressure) return 0 /atom/movable/var/tmp/turf/airflow_dest /atom/movable/var/tmp/airflow_speed = 0 @@ -78,116 +85,6 @@ obj/item/check_airflow_movable(n) return 0 return 1 -/atom/movable/proc/GotoAirflowDest(n) - if(!airflow_dest) return - if(airflow_speed < 0) return - if(last_airflow > world.time - vsc.airflow_delay) return - if(airflow_speed) - airflow_speed = n/max(get_dist(src,airflow_dest),1) - return - if(airflow_dest == loc) - step_away(src,loc) - if(!src.AirflowCanMove(n)) - return - if(ismob(src)) - src << "You are sucked away by airflow!" - last_airflow = world.time - var/airflow_falloff = 9 - sqrt((x - airflow_dest.x) ** 2 + (y - airflow_dest.y) ** 2) - if(airflow_falloff < 1) - airflow_dest = null - return - airflow_speed = min(max(n * (9/airflow_falloff),1),9) - var - xo = airflow_dest.x - src.x - yo = airflow_dest.y - src.y - od = 0 - airflow_dest = null - if(!density) - density = 1 - od = 1 - while(airflow_speed > 0) - if(airflow_speed <= 0) break - airflow_speed = min(airflow_speed,15) - airflow_speed -= vsc.airflow_speed_decay - if(airflow_speed > 7) - if(airflow_time++ >= airflow_speed - 7) - if(od) - density = 0 - sleep(1 * tick_multiplier) - else - if(od) - density = 0 - sleep(max(1,10-(airflow_speed+3)) * tick_multiplier) - if(od) - density = 1 - if ((!( src.airflow_dest ) || src.loc == src.airflow_dest)) - src.airflow_dest = locate(min(max(src.x + xo, 1), world.maxx), min(max(src.y + yo, 1), world.maxy), src.z) - if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy)) - break - if(!istype(loc, /turf)) - break - step_towards(src, src.airflow_dest) - var/mob/M = src - if(istype(M) && M.client) - M.setMoveCooldown(vsc.airflow_mob_slowdown) - airflow_dest = null - airflow_speed = 0 - airflow_time = 0 - if(od) - density = 0 - - -/atom/movable/proc/RepelAirflowDest(n) - if(!airflow_dest) return - if(airflow_speed < 0) return - if(last_airflow > world.time - vsc.airflow_delay) return - if(airflow_speed) - airflow_speed = n/max(get_dist(src,airflow_dest),1) - return - if(airflow_dest == loc) - step_away(src,loc) - if(!src.AirflowCanMove(n)) - return - if(ismob(src)) - src << "You are pushed away by airflow!" - last_airflow = world.time - var/airflow_falloff = 9 - sqrt((x - airflow_dest.x) ** 2 + (y - airflow_dest.y) ** 2) - if(airflow_falloff < 1) - airflow_dest = null - return - airflow_speed = min(max(n * (9/airflow_falloff),1),9) - var - xo = -(airflow_dest.x - src.x) - yo = -(airflow_dest.y - src.y) - od = 0 - airflow_dest = null - if(!density) - density = 1 - od = 1 - while(airflow_speed > 0) - if(airflow_speed <= 0) return - airflow_speed = min(airflow_speed,15) - airflow_speed -= vsc.airflow_speed_decay - if(airflow_speed > 7) - if(airflow_time++ >= airflow_speed - 7) - sleep(1 * tick_multiplier) - else - sleep(max(1,10-(airflow_speed+3)) * tick_multiplier) - if ((!( src.airflow_dest ) || src.loc == src.airflow_dest)) - src.airflow_dest = locate(min(max(src.x + xo, 1), world.maxx), min(max(src.y + yo, 1), world.maxy), src.z) - if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy)) - return - if(!istype(loc, /turf)) - return - step_towards(src, src.airflow_dest) - if(ismob(src) && src:client) - src:client:move_delay = world.time + vsc.airflow_mob_slowdown - airflow_dest = null - airflow_speed = 0 - airflow_time = 0 - if(od) - density = 0 - /atom/movable/Bump(atom/A) if(airflow_speed > 0 && airflow_dest) airflow_hit(A) diff --git a/code/ZAS/Atom.dm b/code/ZAS/Atom.dm index 4961355940..63ed9cf090 100644 --- a/code/ZAS/Atom.dm +++ b/code/ZAS/Atom.dm @@ -76,7 +76,8 @@ turf/c_airblock(turf/other) return AIR_BLOCKED var/result = 0 - for(var/atom/movable/M in contents) + for(var/mm in contents) + var/atom/movable/M = mm result |= M.c_airblock(other) if(result == BLOCKED) return BLOCKED return result diff --git a/code/controllers/subsystems/airflow.dm b/code/controllers/subsystems/airflow.dm new file mode 100644 index 0000000000..9db8138826 --- /dev/null +++ b/code/controllers/subsystems/airflow.dm @@ -0,0 +1,163 @@ +#define CLEAR_OBJECT(TARGET) \ + processing -= TARGET; \ + TARGET.airflow_dest = null; \ + TARGET.airflow_speed = 0; \ + TARGET.airflow_time = 0; \ + TARGET.airflow_skip_speedcheck = FALSE; \ + if (TARGET.airflow_od) { \ + TARGET.density = 0; \ + } + +// No point in making this a processing substem, it overrides fire() and handles its own processing list! +SUBSYSTEM_DEF(airflow) + name = "Airflow" + wait = 2 + flags = SS_NO_INIT + runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + priority = 15 + + var/list/processing = list() + var/list/currentrun = list() + +/datum/controller/subsystem/airflow/fire(resumed = FALSE) + if (!resumed) + currentrun = processing.Copy() + + var/mywait = wait + var/list/curr = currentrun // Cache for sanic speed + while (curr.len) + var/atom/movable/target = curr[curr.len] + curr.len-- + if(QDELETED(target)) + processing -= target + if (MC_TICK_CHECK) + return + continue + + if (target.airflow_speed <= 0) + CLEAR_OBJECT(target) + if (MC_TICK_CHECK) + return + continue + + if (target.airflow_process_delay > 0) + target.airflow_process_delay -= mywait + if (MC_TICK_CHECK) + return + continue + else if (target.airflow_process_delay) + target.airflow_process_delay = 0 + + target.airflow_speed = min(target.airflow_speed, 15) + target.airflow_speed -= vsc.airflow_speed_decay + if (!target.airflow_skip_speedcheck) + if (target.airflow_speed > 7) + if (target.airflow_time++ >= target.airflow_speed - 7) + if (target.airflow_od) + target.density = 0 + target.airflow_skip_speedcheck = TRUE + + if (MC_TICK_CHECK) + return + continue + else + if (target.airflow_od) + target.density = 0 + target.airflow_process_delay = max(1, 10 - (target.airflow_speed + 3)) + target.airflow_skip_speedcheck = TRUE + + if (MC_TICK_CHECK) + return + continue + + target.airflow_skip_speedcheck = FALSE + + if (target.airflow_od) + target.density = 1 + + if (!target.airflow_dest || target.loc == target.airflow_dest) + target.airflow_dest = locate(min(max(target.x + target.airflow_xo, 1), world.maxx), min(max(target.y + target.airflow_yo, 1), world.maxy), target.z) + + if ((target.x == 1) || (target.x == world.maxx) || (target.y == 1) || (target.y == world.maxy)) + CLEAR_OBJECT(target) + if (MC_TICK_CHECK) + return + continue + + if (!isturf(target.loc)) + CLEAR_OBJECT(target) + if (MC_TICK_CHECK) + return + continue + + step_towards(target, target.airflow_dest) + var/mob/M = target + if (ismob(target) && M.client) + M.setMoveCooldown(vsc.airflow_mob_slowdown) + + if (MC_TICK_CHECK) + return + +#undef CLEAR_OBJECT + +/atom/movable + var/tmp/airflow_xo + var/tmp/airflow_yo + var/tmp/airflow_od + var/tmp/airflow_process_delay + var/tmp/airflow_skip_speedcheck + +/atom/movable/proc/prepare_airflow(n) + if (!airflow_dest || airflow_speed < 0 || last_airflow > world.time - vsc.airflow_delay) + return FALSE + if (airflow_speed) + airflow_speed = n / max(get_dist(src, airflow_dest), 1) + return FALSE + + if (airflow_dest == loc) + step_away(src, loc) + + if (!src.AirflowCanMove(n)) + return FALSE + + if (ismob(src)) + to_chat(src,"You are pushed away by airflow!") + + last_airflow = world.time + var/airflow_falloff = 9 - sqrt((x - airflow_dest.x) ** 2 + (y - airflow_dest.y) ** 2) + + if (airflow_falloff < 1) + airflow_dest = null + return FALSE + + airflow_speed = min(max(n * (9 / airflow_falloff), 1), 9) + + airflow_od = 0 + + if (!density) + density = 1 + airflow_od = 1 + + return TRUE + +/atom/movable/proc/GotoAirflowDest(n) + if (!prepare_airflow(n)) + return + + airflow_xo = airflow_dest.x - src.x + airflow_yo = airflow_dest.y - src.y + + airflow_dest = null + + SSairflow.processing += src + +/atom/movable/proc/RepelAirflowDest(n) + if (!prepare_airflow(n)) + return + + airflow_xo = -(airflow_dest.x - src.x) + airflow_yo = -(airflow_dest.y - src.y) + + airflow_dest = null + + SSairflow.processing += src diff --git a/polaris.dme b/polaris.dme index 8558ceb5a9..62625bf570 100644 --- a/polaris.dme +++ b/polaris.dme @@ -173,6 +173,7 @@ #include "code\controllers\ProcessScheduler\core\process.dm" #include "code\controllers\ProcessScheduler\core\processScheduler.dm" #include "code\controllers\subsystems\air.dm" +#include "code\controllers\subsystems\airflow.dm" #include "code\controllers\subsystems\creation.dm" #include "code\controllers\subsystems\garbage.dm" #include "code\controllers\subsystems\lighting.dm"