diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 73b4c33620..f57e801658 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1137,46 +1137,6 @@ B --><-- A
if(location == src)
return 1
-/proc/add_to_proximity_list(atom/A, range)
- var/turf/T = get_turf(A)
- if(!T || !A.loc)
- throw EXCEPTION("Someone adding a prox sensor in nullspace")
- var/list/L = block(locate(T.x - range, T.y - range, T.z), locate(T.x + range, T.y + range, T.z))
- for(var/B in L)
- var/turf/C = B
- LAZYINITLIST(C.proximity_checkers)
- C.proximity_checkers[A] = TRUE
- return L
-
-/proc/remove_from_proximity_list(atom/A, range, oldloc = null)
- var/turf/T = get_turf(oldloc ? oldloc : A)
- var/list/L = block(locate(T.x - range, T.y - range, T.z), locate(T.x + range, T.y + range, T.z))
- for(var/B in L)
- var/turf/C = B
- if (!C.proximity_checkers)
- continue
- C.proximity_checkers.Remove(A)
-
-/proc/shift_proximity(atom/checker, atom/A, range, atom/B, newrange)
- var/turf/T = get_turf(A)
- var/turf/Q = get_turf(B)
- if(T == Q && range == newrange)
- return 0
- var/list/L = block(locate(T.x - range, T.y - range, T.z), locate(T.x + range, T.y + range, T.z))
- var/list/M = block(locate(Q.x - newrange, Q.y - newrange, Q.z), locate(Q.x + newrange, Q.y + newrange, Q.z))
- var/list/N = L - M
- var/list/O = M - L
- for(var/C in N)
- var/turf/D = C
- if (!D.proximity_checkers)
- continue
- D.proximity_checkers.Remove(checker)
- for(var/E in O)
- var/turf/F = E
- LAZYINITLIST(F.proximity_checkers)
- F.proximity_checkers[checker] = TRUE
- return 1
-
/proc/flick_overlay_static(image/I, atom/A, duration)
set waitfor = 0
if(!A || !I)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 8de954c5b6..6dc215bbcc 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -28,6 +28,8 @@
var/list/our_overlays //our local copy of (non-priority) overlays without byond magic. Use procs in SSoverlays to manipulate
var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4.
+ var/datum/proximity_monitor/proximity_monitor
+
/atom/New(loc, ...)
//atom creation method that preloads variables at creation
if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New()
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index fbfe6b5834..61942a9c58 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -120,6 +120,10 @@
if(flags & CLEAN_ON_MOVE)
clean_on_move()
+
+ var/datum/proximity_monitor/pc = proximity_monitor
+ if(pc)
+ pc.HandleMove()
return 1
/atom/movable/proc/clean_on_move()
@@ -170,6 +174,8 @@
if(stationloving && force)
STOP_PROCESSING(SSinbounds, src)
+
+ QDEL_NULL(proximity_monitor)
. = ..()
if(loc)
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 592a7b6967..080f85e977 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -46,7 +46,8 @@
assembly.state = 4
GLOB.cameranet.cameras += src
GLOB.cameranet.addCamera(src)
- add_to_proximity_list(src, 1) //1 was default of everything
+ proximity_monitor = new(src, 1)
+
/* // Use this to look for cameras that have the same c_tag.
for(var/obj/machinery/camera/C in cameranet.cameras)
var/list/tempnetwork = C.network&src.network
@@ -59,13 +60,8 @@
if(mapload && z == 1 && prob(3) && !start_active)
toggle_cam()
-/obj/machinery/camera/Move()
- remove_from_proximity_list(src, 1)
- return ..()
-
/obj/machinery/camera/Destroy()
toggle_cam(null, 0) //kick anyone viewing out
- remove_from_proximity_list(src, 1)
if(assembly)
qdel(assembly)
assembly = null
diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm
index c26094e2bd..6904067e2a 100644
--- a/code/game/machinery/flasher.dm
+++ b/code/game/machinery/flasher.dm
@@ -154,6 +154,10 @@
new /obj/item/stack/sheet/metal (loc, 2)
qdel(src)
+/obj/machinery/flasher/portable/Initialize()
+ . = ..()
+ proximity_monitor = new(src, 0)
+
/obj/machinery/flasher/portable/HasProximity(atom/movable/AM)
if (last_flash && world.time < last_flash + 150)
return
@@ -172,25 +176,17 @@
add_overlay("[base_state]-s")
anchored = 1
power_change()
- add_to_proximity_list(src, range)
+ proximity_monitor.SetRange(range)
else
to_chat(user, "[src] can now be moved.")
cut_overlays()
anchored = 0
power_change()
- remove_from_proximity_list(src, range)
+ proximity_monitor.SetRange(0)
else
return ..()
-/obj/machinery/flasher/portable/Destroy()
- remove_from_proximity_list(src, range)
- return ..()
-
-/obj/machinery/flasher/portable/Moved(oldloc)
- remove_from_proximity_list(oldloc, range)
- return ..()
-
/obj/item/wallframe/flasher
name = "mounted flash frame"
desc = "Used for building wall-mounted flashers."
diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm
index 6646735613..365d7f1c26 100644
--- a/code/game/objects/effects/effects.dm
+++ b/code/game/objects/effects/effects.dm
@@ -23,6 +23,12 @@
/obj/effect/blob_act()
return
+/obj/effect/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
+ return 0
+
+/obj/effect/experience_pressure_difference()
+ return
+
/obj/effect/ex_act(severity, target)
if(target == src)
qdel(src)
@@ -37,12 +43,15 @@
if(prob(25))
qdel(src)
-/obj/effect/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
- return 0
-
-/obj/effect/experience_pressure_difference()
- return
-
/obj/effect/singularity_act()
qdel(src)
- return 0
\ No newline at end of file
+ return 0
+
+/obj/effect/abstract/ex_act(severity, target)
+ return
+
+/obj/effect/abstract/singularity_pull()
+ return
+
+/obj/effect/abstract/singularity_act()
+ return
\ No newline at end of file
diff --git a/code/game/objects/effects/proximity.dm b/code/game/objects/effects/proximity.dm
new file mode 100644
index 0000000000..8fabe3fce0
--- /dev/null
+++ b/code/game/objects/effects/proximity.dm
@@ -0,0 +1,97 @@
+/datum/proximity_monitor
+ var/atom/host //the atom we are tracking
+ var/atom/last_host_loc
+ var/list/checkers //list of /obj/effect/abstract/proximity_checkers
+ var/current_range
+ var/ignore_if_not_on_turf //don't check turfs in range if the host's loc isn't a turf
+
+/datum/proximity_monitor/New(atom/_host, range, _ignore_if_not_on_turf = TRUE)
+ host = _host
+ last_host_loc = _host.loc
+ ignore_if_not_on_turf = _ignore_if_not_on_turf
+ SetRange(range)
+
+/datum/proximity_monitor/Destroy()
+ host = null
+ QDEL_LIST(checkers)
+ return ..()
+
+/datum/proximity_monitor/proc/HandleMove()
+ var/atom/_host = host
+ var/atom/new_host_loc = _host.loc
+ if(last_host_loc != new_host_loc)
+ last_host_loc = new_host_loc //hopefully this won't cause GC issues with containers
+ var/curr_range = current_range
+ SetRange(curr_range, TRUE)
+ if(curr_range)
+ testing("HasProx: [host] -> [host]")
+ _host.HasProximity(host) //if we are processing, we're guaranteed to be a movable
+
+/datum/proximity_monitor/proc/SetRange(range, force_rebuild = FALSE)
+ if(!force_rebuild && range == current_range)
+ return FALSE
+ . = TRUE
+
+ current_range = range
+
+ var/list/old_checkers = checkers
+ var/old_checkers_len = LAZYLEN(old_checkers)
+
+ var/atom/host_loc = host.loc
+
+ var/atom/loc_to_use = ignore_if_not_on_turf ? host_loc : get_turf(host)
+ if(!isturf(loc_to_use)) //only check the host's loc
+ if(range)
+ var/obj/effect/abstract/proximity_checker/pc
+ if(old_checkers_len)
+ pc = old_checkers[old_checkers_len]
+ --old_checkers.len
+ else
+ pc = new(host_loc, src)
+
+ checkers = list(pc) //only check the host's loc
+ return
+
+ var/list/turfs = RANGE_TURFS(range, loc_to_use)
+ var/old_checkers_used = min(turfs.len, old_checkers_len)
+
+ //reuse what we can
+ for(var/I in 1 to old_checkers_len)
+ if(I <= old_checkers_used)
+ var/obj/effect/abstract/proximity_checker/pc = old_checkers[I]
+ pc.loc = turfs[I]
+ else
+ qdel(old_checkers[I]) //delete the leftovers
+
+ LAZYCLEARLIST(old_checkers)
+
+ //create what we lack
+ var/list/checkers_local = list()
+ for(var/I in (old_checkers_used + 1) to turfs.len)
+ checkers_local += new /obj/effect/abstract/proximity_checker(turfs[I], src)
+
+ checkers = checkers_local
+
+/obj/effect/abstract/proximity_checker
+ var/datum/proximity_monitor/monitor
+
+/obj/effect/abstract/proximity_checker/Initialize(mapload, datum/proximity_monitor/_monitor)
+ . = ..()
+ if(_monitor)
+ monitor = _monitor
+ else
+ stack_trace("proximity_checker created without proximity_monitor")
+ qdel(src)
+
+/obj/effect/abstract/proximity_checker/Destroy()
+ monitor = null
+ return ..()
+
+/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM)
+ set waitfor = FALSE
+ var/datum/proximity_monitor/M = monitor
+ if(!M.current_range)
+ return
+ var/atom/H = M.host
+ testing("HasProx: [H] -> [AM]")
+ H.HasProximity(AM)
\ No newline at end of file
diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm
index cd5a72d308..d46136a9ae 100644
--- a/code/game/objects/structures/aliens.dm
+++ b/code/game/objects/structures/aliens.dm
@@ -227,7 +227,6 @@
layer = MOB_LAYER
var/obj/item/clothing/mask/facehugger/child
-
/obj/structure/alien/egg/Initialize(mapload)
..()
update_icon()
@@ -235,15 +234,10 @@
child = new(src)
if(status == GROWING)
addtimer(CALLBACK(src, .proc/Grow), rand(MIN_GROWTH_TIME, MAX_GROWTH_TIME))
- if(status == GROWN)
- add_to_proximity_list(src, 1)
+ proximity_monitor = new(src, status == GROWN ? 1 : 0)
if(status == BURST)
obj_integrity = integrity_failure
-/obj/structure/alien/egg/Destroy()
- remove_from_proximity_list(src, 1)
- . = ..()
-
/obj/structure/alien/egg/update_icon()
..()
switch(status)
@@ -283,12 +277,12 @@
/obj/structure/alien/egg/proc/Grow()
status = GROWN
update_icon()
- add_to_proximity_list(src, 1)
+ proximity_monitor.SetRange(1)
//drops and kills the hugger if any is remaining
/obj/structure/alien/egg/proc/Burst(kill = TRUE)
if(status == GROWN || status == GROWING)
- remove_from_proximity_list(src, 1)
+ proximity_monitor.SetRange(0)
status = BURST
update_icon()
flick("egg_opening", src)
@@ -307,12 +301,6 @@
child.Attach(M)
break
-/obj/structure/alien/egg/Moved(oldloc)
- remove_from_proximity_list(oldloc, 1)
- if(status == GROWN)
- add_to_proximity_list(src, 1)
- return ..()
-
/obj/structure/alien/egg/obj_break(damage_flag)
if(!(flags & NODECONSTRUCT))
if(status != BURST)
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index b6ed50c576..10eefc4b14 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -13,8 +13,6 @@
flags = CAN_BE_DIRTY
- var/list/proximity_checkers
-
var/image/obscured //camerachunks
var/list/image/blueprint_data //for the station blueprints, images of objects eg: pipes
@@ -156,10 +154,6 @@
return 1 //Nothing found to block so return success!
/turf/Entered(atom/movable/AM)
- for(var/A in proximity_checkers)
- var/atom/B = A
- B.HasProximity(AM)
-
if(explosion_level && AM.ex_check(explosion_id))
AM.ex_act(explosion_level)
diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm
index 8375fa3e56..1856313b36 100644
--- a/code/modules/assembly/proximity.dm
+++ b/code/modules/assembly/proximity.dm
@@ -10,8 +10,6 @@
var/timing = 0
var/time = 10
var/sensitivity = 1
- var/atom/oldloc
- var/list/turfs_around = list()
/obj/item/device/assembly/prox_sensor/proc/toggle_scan()
@@ -19,22 +17,15 @@
/obj/item/device/assembly/prox_sensor/proc/sense()
-/obj/item/device/assembly/prox_sensor/New()
- ..()
- START_PROCESSING(SSobj, src)
- oldloc = loc
+/obj/item/device/assembly/prox_sensor/Initialize()
+ . = ..()
+ proximity_monitor = new(src, 0)
/obj/item/device/assembly/prox_sensor/describe()
if(timing)
return "The proximity sensor is arming."
return "The proximity sensor is [scanning?"armed":"disarmed"]."
-/obj/item/device/assembly/prox_sensor/on_attach(datum/wires/w)
- handle_move(w.holder)
-
-/obj/item/device/assembly/prox_sensor/on_detach(datum/wires/w)
- handle_move(w.holder.loc)
-
/obj/item/device/assembly/prox_sensor/activate()
if(!..())
return 0//Cooldown check
@@ -42,12 +33,15 @@
update_icon()
return 1
-
/obj/item/device/assembly/prox_sensor/toggle_secure()
secured = !secured
if(!secured)
- scanning = 0
+ if(scanning)
+ toggle_scan()
+ proximity_monitor.host = src
timing = 0
+ else
+ proximity_monitor.host = loc
update_icon()
return secured
@@ -73,36 +67,19 @@
timing = 0
toggle_scan(1)
time = initial(time)
- handle_move(loc)
-
-/obj/item/device/assembly/prox_sensor/dropped()
- ..()
- if(scanning)
- INVOKE_ASYNC(src, .proc/sense)
-
-/obj/item/device/assembly/prox_sensor/Destroy()
- if(scanning)
- remove_from_proximity_list(src, sensitivity, oldloc)
- return ..()
/obj/item/device/assembly/prox_sensor/toggle_scan(scan)
if(!secured)
return 0
scanning = scan
- if(scanning)
- add_to_proximity_list(src, sensitivity)
- else
- remove_from_proximity_list(src, sensitivity)
- oldloc = get_turf(loc)
+ proximity_monitor.SetRange(scanning ? sensitivity : 0)
update_icon()
/obj/item/device/assembly/prox_sensor/proc/sensitivity_change(value)
var/sense = min(max(sensitivity + value, 0), 5)
- if(scanning)
- if(shift_proximity(src, oldloc, sensitivity, loc, sense))
- sense()
- oldloc = loc
sensitivity = sense
+ if(scanning && proximity_monitor.SetRange(sense))
+ sense()
/obj/item/device/assembly/prox_sensor/update_icon()
cut_overlays()
@@ -117,17 +94,6 @@
holder.update_icon()
return
-/obj/item/device/assembly/prox_sensor/proc/handle_move(atom/newloc)
- if(scanning)
- if(shift_proximity(src, oldloc, sensitivity, newloc, sensitivity) || newloc != oldloc)
- sense()
- oldloc = newloc
-
-/obj/item/device/assembly/prox_sensor/Moved()
- ..()
- handle_move(loc)
-
-
/obj/item/device/assembly/prox_sensor/interact(mob/user)//TODO: Change this to the wires thingy
if(is_secured(user))
var/second = time % 60
diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm
index c148f83d17..e7b0c12aac 100644
--- a/code/modules/mining/machine_stacking.dm
+++ b/code/modules/mining/machine_stacking.dm
@@ -10,14 +10,13 @@
var/machinedir = SOUTHEAST
speed_process = 1
-/obj/machinery/mineral/stacking_unit_console/New()
- ..()
- spawn(7)
- src.machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
- if (machine)
- machine.CONSOLE = src
- else
- qdel(src)
+/obj/machinery/mineral/stacking_unit_console/Initialize()
+ . = ..()
+ machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
+ if (machine)
+ machine.CONSOLE = src
+ else
+ qdel(src)
/obj/machinery/mineral/stacking_unit_console/attack_hand(mob/user)
@@ -70,6 +69,14 @@
var/stack_amt = 50; //ammount to stack before releassing
input_dir = EAST
output_dir = WEST
+
+/obj/machinery/mineral/stacking_machine/Initialize()
+ . = ..()
+ proximity_monitor = new(src, 1)
+
+/obj/machinery/mineral/stacking_machine/HasProximity(atom/movable/AM)
+ if(istype(AM, /obj/item/stack/sheet) && AM.loc == get_step(src, input_dir))
+ process_sheet(AM)
/obj/machinery/mineral/stacking_machine/proc/process_sheet(obj/item/stack/sheet/inp)
if(!(inp.type in stack_list)) //It's the first of this sheet added
@@ -83,10 +90,4 @@
var/obj/item/stack/sheet/out = new inp.type()
out.amount = stack_amt
unload_mineral(out)
- storage.amount -= stack_amt
-
-/obj/machinery/mineral/stacking_machine/process()
- var/turf/T = get_step(src, input_dir)
- if(T)
- for(var/obj/item/stack/sheet/S in T)
- process_sheet(S)
+ storage.amount -= stack_amt
\ No newline at end of file
diff --git a/tgstation.dme b/tgstation.dme
index fc5dbae6f4..97e665b378 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -686,6 +686,7 @@
#include "code\game\objects\effects\mines.dm"
#include "code\game\objects\effects\misc.dm"
#include "code\game\objects\effects\overlays.dm"
+#include "code\game\objects\effects\proximity.dm"
#include "code\game\objects\effects\portals.dm"
#include "code\game\objects\effects\spiders.dm"
#include "code\game\objects\effects\step_triggers.dm"