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/vorestation.dme b/vorestation.dme
index 17910d9afb..3944950a57 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -194,6 +194,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"