From 01da8413de404caf832f349b79012231815490c6 Mon Sep 17 00:00:00 2001
From: SteelSlayer <42044220+SteelSlayer@users.noreply.github.com>
Date: Sun, 20 Sep 2020 12:31:16 -0500
Subject: [PATCH] Adds the proximity monitor component. Performance improvement
for turf/Entered (#14196)
* proximity monitor
* Update code/__HELPERS/unsorted.dm
Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>
* farie review tweaks
* actually I need this
Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>
---
code/__HELPERS/unsorted.dm | 21 +++
code/datums/components/proximity_monitor.dm | 139 ++++++++++++++++++
code/game/area/ai_monitored.dm | 1 +
code/game/machinery/camera/motion.dm | 2 +-
code/game/machinery/flasher.dm | 15 +-
code/game/objects/effects/effects.dm | 36 +++++
.../objects/items/devices/transfer_valve.dm | 3 +
code/game/objects/items/weapons/caution.dm | 6 +-
.../items/weapons/grenades/chem_grenade.dm | 5 +
code/game/objects/structures/aliens.dm | 2 +
code/game/turfs/turf.dm | 7 -
code/modules/assembly/bomb.dm | 4 +
code/modules/assembly/holder.dm | 10 +-
code/modules/assembly/proximity.dm | 4 +
code/modules/clothing/masks/miscellaneous.dm | 4 +-
.../living/carbon/alien/special/facehugger.dm | 7 +-
.../reagent_containers/glass_containers.dm | 5 +-
code/modules/reagents/reagent_dispenser.dm | 4 +-
paradise.dme | 1 +
19 files changed, 252 insertions(+), 24 deletions(-)
create mode 100644 code/datums/components/proximity_monitor.dm
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 2a337c44563..e7c4089812c 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1997,5 +1997,26 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
return TRUE
return FALSE
+/**
+ * Proc which gets all adjacent turfs to `src`, including the turf that `src` is on.
+ *
+ * This is similar to doing `for(var/turf/T in range(1, src))`. However it is slightly more performant.
+ * Additionally, the above proc becomes more costly the more atoms there are nearby. This proc does not care about that.
+ */
+/atom/proc/get_all_adjacent_turfs()
+ var/turf/src_turf = get_turf(src)
+ var/list/_list = list(
+ src_turf,
+ get_step(src_turf, NORTH),
+ get_step(src_turf, NORTHEAST),
+ get_step(src_turf, NORTHWEST),
+ get_step(src_turf, SOUTH),
+ get_step(src_turf, SOUTHEAST),
+ get_step(src_turf, SOUTHWEST),
+ get_step(src_turf, EAST),
+ get_step(src_turf, WEST)
+ )
+ return _list
+
/// Waits at a line of code until X is true
#define UNTIL(X) while(!(X)) stoplag()
diff --git a/code/datums/components/proximity_monitor.dm b/code/datums/components/proximity_monitor.dm
new file mode 100644
index 00000000000..cf5de38b387
--- /dev/null
+++ b/code/datums/components/proximity_monitor.dm
@@ -0,0 +1,139 @@
+/**
+ * # Proximity monitor component
+ *
+ * Attaching this component to an atom means that the atom will be able to detect mobs/objs moving within a 1 tile of it.
+ *
+ * The component creates several `obj/effect/abstract/proximity_checker` objects, which follow the parent atom around, always making sure it's at the center.
+ * When something crosses one of these `proximiy_checker`s, the parent has the `HasProximity()` proc called on it, with the crossing mob/obj as the argument.
+ */
+/datum/component/proximity_monitor
+ var/atom/owner
+ /// A list of currently created `/obj/effect/abstract/proximity_checker`s in use with this component.
+ var/list/proximity_checkers
+
+/datum/component/proximity_monitor/Initialize()
+ . = ..()
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+ owner = parent
+ create_prox_checkers()
+
+/datum/component/proximity_monitor/Destroy(force, silent)
+ QDEL_LIST(proximity_checkers)
+ owner = null
+ return ..()
+
+/datum/component/proximity_monitor/RegisterWithParent()
+ . = ..()
+ if(ismovable(parent))
+ RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/HandleMove)
+
+/datum/component/proximity_monitor/UnregisterFromParent()
+ . = ..()
+ if(ismovable(parent))
+ UnregisterSignal(parent, COMSIG_MOVABLE_MOVED)
+
+/**
+ * Called when the `parent` receives the `COMSIG_MOVABLE_MOVED` signal, which occurs when it `Move()`s
+ *
+ * Code is only ran when there is no `Dir`, which occurs when the parent is teleported, gets placed into a storage item, dropped, or picked up.
+ * Normal movement, for example moving 1 tile to the west, is handled by the `proximity_checker` objects.
+ *
+ * Arguments:
+ * * source - this will be the `parent`
+ * * OldLoc - the location the parent just moved from
+ * * Dir - the direction the parent just moved in
+ * * forced - if we were forced to move
+ */
+/datum/component/proximity_monitor/proc/HandleMove(datum/source, atom/OldLoc, Dir, forced)
+ if(!Dir) // No dir means the parent teleported, or moved in a non-standard way like getting placed into disposals, onto a table, dropped, picked up, etc.
+ recenter_prox_checkers()
+
+/**
+ * Called in Initialize(). Generates a set of `/obj/effect/abstract/proximity_checker` objects around the parent, and registers signals to them.
+ */
+/datum/component/proximity_monitor/proc/create_prox_checkers()
+ proximity_checkers = list()
+ for(var/turf/T in range(1, get_turf(parent)))
+ var/obj/effect/abstract/proximity_checker/P = new(T, parent)
+ proximity_checkers += P
+ // Basic movement for the proximity_checker objects. The objects will move 1 tile in the direction the parent just moved.
+ P.RegisterSignal(parent, COMSIG_MOVABLE_MOVED, /obj/effect/abstract/proximity_checker/.proc/HandleMove)
+
+/**
+ * Re-centers all of the parent's `proximity_checker`s around its current location.
+ */
+/datum/component/proximity_monitor/proc/recenter_prox_checkers()
+ var/list/prox_checkers = owner.get_all_adjacent_turfs()
+ for(var/checker in proximity_checkers)
+ var/obj/effect/abstract/proximity_checker/P = checker
+ P.loc = pick_n_take(prox_checkers)
+
+/**
+ * # Proximity checker abstract object
+ *
+ * Inteded for use with the proximity checker component (/datum/component/proximity_monitor).
+ * Whenever a movable atom crosses this object, it calls `HasProximity()` on the object which is listening for proximity (`hasprox_receiver`).
+ */
+/obj/effect/abstract/proximity_checker
+ name = "Proximity checker"
+ /// Whether or not the proximity checker is listening for things crossing it.
+ var/active
+ /// The linked atom which has the proximity_monitor component, and will recieve the `HasProximity()` calls.
+ var/atom/hasprox_receiver
+
+// If this object is initialized without a `_hasprox_receiver` arg, it is qdel'd.
+/obj/effect/abstract/proximity_checker/Initialize(mapload, atom/_hasprox_receiver)
+ if(_hasprox_receiver)
+ hasprox_receiver = _hasprox_receiver
+ RegisterSignal(hasprox_receiver, COMSIG_PARENT_QDELETING, .proc/OnParentDeletion)
+ if(isturf(hasprox_receiver.loc)) // if the reciever is inside a locker/crate/etc, they don't detect proximity
+ active = TRUE
+ else
+ stack_trace("/obj/effect/abstract/proximity_checker created without a receiver")
+ return INITIALIZE_HINT_QDEL
+ return ..()
+
+/obj/effect/abstract/proximity_checker/Destroy()
+ hasprox_receiver = null
+ return ..()
+
+/**
+ * Called when the `hasprox_receiver` receives the `COMSIG_PARENT_QDELETING` signal. When the receiver is deleted, so is this object.
+ *
+ * Arugments:
+ * * source - this will be the `hasprox_receiver`
+ * * force - the force flag taken from the qdel proc currently running on `hasprox_receiver`
+ */
+/obj/effect/abstract/proximity_checker/proc/OnParentDeletion(datum/source, force = FALSE)
+ qdel(src)
+
+/**
+ * Something crossed over the proximity_checker. Notify the `hasprox_receiver` it has proximity with something. Only fires if the checker is `active`.
+ */
+/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM, oldloc)
+ set waitfor = FALSE
+ if(active)
+ hasprox_receiver.HasProximity(AM)
+
+/**
+ * Moves the proximity_checker 1 tile in the `Dir` direction.
+ *
+ * If `Dir` is null it will be recentered around the receiver via the `recenter_prox_checkers()` proc.
+ * If the new location of the receiver is NOT a turf, set `active` to FALSE, so that it does not receive proximity calls.
+ * If the new location of the receiver IS a turf, set `active` to TRUE, so that it can receive proximity calls again.
+ *
+ * Arguments:
+ * * source - this will be the `hasprox_receiver`
+ * * OldLoc - the location the `hasprox_receiver` just moved from
+ * * Dir - the direction the `hasprox_receiver` just moved in
+ * * forced - if we were forced to move
+ */
+/obj/effect/abstract/proximity_checker/proc/HandleMove(datum/source, atom/OldLoc, Dir, forced)
+ if(Dir)
+ loc = get_step(src, Dir) // Basic movement 1 tile in some direction.
+ return
+ if(!isturf(hasprox_receiver.loc))
+ active = FALSE // Receiver shouldn't detect proximity while picked up, in a backpack, closet, etc.
+ else
+ active = TRUE // Receiver can detect proximity again because it's on a turf.
diff --git a/code/game/area/ai_monitored.dm b/code/game/area/ai_monitored.dm
index 723574ee949..abfcb7210b0 100644
--- a/code/game/area/ai_monitored.dm
+++ b/code/game/area/ai_monitored.dm
@@ -9,6 +9,7 @@
for(var/obj/machinery/camera/M in src)
if(M.isMotion())
motioncameras.Add(M)
+ M.AddComponent(/datum/component/proximity_monitor)
M.set_area_motion(src)
/area/ai_monitored/Entered(atom/movable/O)
diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm
index 7d33361e4b9..8a32c6d6374 100644
--- a/code/game/machinery/camera/motion.dm
+++ b/code/game/machinery/camera/motion.dm
@@ -58,7 +58,7 @@
detectTime = -1
return TRUE
-/obj/machinery/camera/HasProximity(atom/movable/AM as mob|obj)
+/obj/machinery/camera/HasProximity(atom/movable/AM)
// Motion cameras outside of an "ai monitored" area will use this to detect stuff.
if(!area_motion)
if(isliving(AM))
diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm
index 37766db58fb..369d43e5d94 100644
--- a/code/game/machinery/flasher.dm
+++ b/code/game/machinery/flasher.dm
@@ -25,20 +25,17 @@
base_state = "pflash"
density = 1
-/*
-/obj/machinery/flasher/New()
- sleep(4) //<--- What the fuck are you doing? D=
- sd_set_light(2)
-*/
+/obj/machinery/flasher/portable/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/proximity_monitor)
+
/obj/machinery/flasher/power_change()
if( powered() )
stat &= ~NOPOWER
icon_state = "[base_state]1"
-// sd_set_light(2)
else
stat |= ~NOPOWER
icon_state = "[base_state]1-p"
-// sd_set_light(0)
//Let the AI trigger them directly.
/obj/machinery/flasher/attack_ai(mob/user)
@@ -81,7 +78,7 @@
flash()
..(severity)
-/obj/machinery/flasher/portable/HasProximity(atom/movable/AM as mob|obj)
+/obj/machinery/flasher/portable/HasProximity(atom/movable/AM)
if((disable) || (last_flash && world.time < last_flash + 150))
return
@@ -109,7 +106,7 @@
if(anchored)
WRENCH_ANCHOR_MESSAGE
overlays.Cut()
- else if(anchored)
+ else
WRENCH_UNANCHOR_MESSAGE
overlays += "[base_state]-s"
diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm
index 7497b148788..625d2ad8fd9 100644
--- a/code/game/objects/effects/effects.dm
+++ b/code/game/objects/effects/effects.dm
@@ -45,6 +45,42 @@
if(prob(25))
qdel(src)
+/**
+ * # The abstract object
+ *
+ * This is an object that is intended to able to be placed, but that is completely invisible.
+ * The object should be immune to all forms of damage, or things that can delete it, such as the singularity, or explosions.
+ */
+/obj/effect/abstract
+ name = "Abstract object"
+ invisibility = INVISIBILITY_ABSTRACT
+ layer = TURF_LAYER
+ density = FALSE
+ icon = null
+ icon_state = null
+
+// Most of these overrides procs below are overkill, but better safe than sorry.
+/obj/effect/abstract/swarmer_act()
+ return
+
+/obj/effect/abstract/bullet_act(obj/item/projectile/P)
+ return
+
+/obj/effect/abstract/decompile_act(obj/item/matter_decompiler/C, mob/user)
+ return
+
+/obj/effect/abstract/tesla_act(power)
+ return
+
+/obj/effect/abstract/singularity_act()
+ return
+
+/obj/effect/abstract/narsie_act()
+ return
+
+/obj/effect/abstract/ex_act(severity)
+ return
+
/obj/effect/decal
plane = FLOOR_PLANE
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index 1eba4e54056..261b6ba109b 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -62,6 +62,8 @@
to_chat(user, "You attach the [A] to the valve controls and secure it.")
A.holder = src
A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb).
+ if(istype(attached_device, /obj/item/assembly/prox_sensor))
+ AddComponent(/datum/component/proximity_monitor)
investigate_log("[key_name(user)] attached a [A] to a transfer valve.", INVESTIGATE_BOMB)
add_attack_logs(user, src, "attached [A] to a transfer valve", ATKLOG_FEW)
@@ -137,6 +139,7 @@
attached_device.forceMove(get_turf(src))
attached_device.holder = null
attached_device = null
+ qdel(GetComponent(/datum/component/proximity_monitor))
update_icon()
else
. = FALSE
diff --git a/code/game/objects/items/weapons/caution.dm b/code/game/objects/items/weapons/caution.dm
index b1b573f77ad..b84f8eba6f4 100644
--- a/code/game/objects/items/weapons/caution.dm
+++ b/code/game/objects/items/weapons/caution.dm
@@ -15,6 +15,10 @@
var/armed = 0
var/timepassed = 0
+/obj/item/caution/proximity_sign/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/proximity_monitor)
+
/obj/item/caution/proximity_sign/attack_self(mob/user as mob)
if(ishuman(user))
var/mob/living/carbon/human/H = user
@@ -40,7 +44,7 @@
armed = 1
timing = 0
-/obj/item/caution/proximity_sign/HasProximity(atom/movable/AM as mob|obj)
+/obj/item/caution/proximity_sign/HasProximity(atom/movable/AM)
if(armed)
if(istype(AM, /mob/living/carbon) && !istype(AM, /mob/living/carbon/brain))
var/mob/living/carbon/C = AM
diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm
index 3aa658b0812..f756929e5ab 100644
--- a/code/game/objects/items/weapons/grenades/chem_grenade.dm
+++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm
@@ -190,6 +190,8 @@
user.drop_item()
nadeassembly = A
+ if(nadeassembly.has_prox_sensors())
+ AddComponent(/datum/component/proximity_monitor)
A.master = src
A.loc = src
assemblyattacher = user.ckey
@@ -219,6 +221,7 @@
nadeassembly.loc = get_turf(src)
nadeassembly.master = null
nadeassembly = null
+ qdel(GetComponent(/datum/component/proximity_monitor))
if(beakers.len)
for(var/obj/O in beakers)
O.loc = get_turf(src)
@@ -304,6 +307,8 @@
/obj/item/grenade/chem_grenade/proc/CreateDefaultTrigger(var/typekey)
if(ispath(typekey,/obj/item/assembly))
nadeassembly = new(src)
+ if(nadeassembly.has_prox_sensors())
+ AddComponent(/datum/component/proximity_monitor)
nadeassembly.a_left = new /obj/item/assembly/igniter(nadeassembly)
nadeassembly.a_left.holder = nadeassembly
nadeassembly.a_left.secured = 1
diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm
index 033787cce75..4661ff125cc 100644
--- a/code/game/objects/structures/aliens.dm
+++ b/code/game/objects/structures/aliens.dm
@@ -280,12 +280,14 @@
/obj/structure/alien/egg/proc/Grow()
icon_state = "egg"
status = GROWN
+ AddComponent(/datum/component/proximity_monitor)
/obj/structure/alien/egg/proc/Burst(kill = TRUE) //drops and kills the hugger if any is remaining
if(status == GROWN || status == GROWING)
icon_state = "egg_hatched"
flick("egg_opening", src)
status = BURSTING
+ qdel(GetComponent(/datum/component/proximity_monitor))
spawn(15)
status = BURST
var/obj/item/clothing/mask/facehugger/child = GetFacehugger()
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 2f90e4d7cc4..8170f9fbe5f 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -166,13 +166,6 @@
if(!O.lastarea)
O.lastarea = get_area(O.loc)
- var/loopsanity = 100
- for(var/atom/A in range(1))
- if(loopsanity == 0)
- break
- loopsanity--
- A.HasProximity(M)
-
// If an opaque movable atom moves around we need to potentially update visibility.
if(M.opacity)
has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case.
diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm
index 33755fc54e8..855c113a71a 100644
--- a/code/modules/assembly/bomb.dm
+++ b/code/modules/assembly/bomb.dm
@@ -12,6 +12,10 @@
var/obj/item/tank/bombtank = null //the second part of the bomb is a plasma tank
origin_tech = "materials=1;engineering=1"
+/obj/item/onetankbomb/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/proximity_monitor)
+
/obj/item/onetankbomb/examine(mob/user)
. = ..()
. += bombtank.examine(user)
diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm
index 6a6cd7e8d8e..87fefe4fc65 100644
--- a/code/modules/assembly/holder.dm
+++ b/code/modules/assembly/holder.dm
@@ -41,19 +41,25 @@
if(!A1.remove_item_from_storage(src))
if(user)
user.remove_from_mob(A1)
- A1.loc = src
+ A1.forceMove(src)
if(!A2.remove_item_from_storage(src))
if(user)
user.remove_from_mob(A2)
- A2.loc = src
+ A2.forceMove(src)
A1.holder = src
A2.holder = src
a_left = A1
a_right = A2
+ if(has_prox_sensors())
+ AddComponent(/datum/component/proximity_monitor)
name = "[A1.name]-[A2.name] assembly"
update_icon()
return TRUE
+/obj/item/assembly_holder/proc/has_prox_sensors()
+ if(istype(a_left, /obj/item/assembly/prox_sensor) || istype(a_right, /obj/item/assembly/prox_sensor))
+ return TRUE
+ return FALSE
/obj/item/assembly_holder/update_icon()
overlays.Cut()
diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm
index caefabcb1f8..ced9fbca932 100644
--- a/code/modules/assembly/proximity.dm
+++ b/code/modules/assembly/proximity.dm
@@ -13,6 +13,10 @@
var/timing = 0
var/time = 10
+/obj/item/assembly/prox_sensor/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/proximity_monitor)
+
/obj/item/assembly/prox_sensor/describe()
if(timing)
return "The proximity sensor is arming."
diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm
index 5cc891b56af..15895046dbc 100644
--- a/code/modules/clothing/masks/miscellaneous.dm
+++ b/code/modules/clothing/masks/miscellaneous.dm
@@ -146,6 +146,7 @@
trigger.forceMove(src)
trigger.master = src
trigger.holder = src
+ AddComponent(/datum/component/proximity_monitor)
to_chat(user, "You attach the [W] to [src].")
return TRUE
else if(istype(W, /obj/item/assembly))
@@ -165,6 +166,7 @@
trigger.master = null
trigger.holder = null
trigger = null
+ qdel(GetComponent(/datum/component/proximity_monitor))
/obj/item/clothing/mask/muzzle/safety/shock/proc/can_shock(obj/item/clothing/C)
if(istype(C))
@@ -186,7 +188,7 @@
M.Jitter(20)
return
-/obj/item/clothing/mask/muzzle/safety/shock/HasProximity(atom/movable/AM as mob|obj)
+/obj/item/clothing/mask/muzzle/safety/shock/HasProximity(atom/movable/AM)
if(trigger)
trigger.HasProximity(AM)
diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm
index 1dcd76c0358..b3f6d73a163 100644
--- a/code/modules/mob/living/carbon/alien/special/facehugger.dm
+++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm
@@ -28,6 +28,10 @@
var/attached = 0
+/obj/item/clothing/mask/facehugger/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/proximity_monitor)
+
/obj/item/clothing/mask/facehugger/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
..()
if(obj_integrity < 90)
@@ -78,7 +82,7 @@
return HasProximity(finder)
return 0
-/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM as mob|obj)
+/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM)
if(CanHug(AM) && Adjacent(AM))
return Attach(AM)
return 0
@@ -210,6 +214,7 @@
icon_state = "[initial(icon_state)]_dead"
item_state = "facehugger_inactive"
stat = DEAD
+ qdel(GetComponent(/datum/component/proximity_monitor))
visible_message("[src] curls up into a ball!")
diff --git a/code/modules/reagents/reagent_containers/glass_containers.dm b/code/modules/reagents/reagent_containers/glass_containers.dm
index 175ae757df4..48534c7ab73 100644
--- a/code/modules/reagents/reagent_containers/glass_containers.dm
+++ b/code/modules/reagents/reagent_containers/glass_containers.dm
@@ -179,6 +179,7 @@
to_chat(usr, "You detach [assembly] from [src]")
usr.put_in_hands(assembly)
assembly = null
+ qdel(GetComponent(/datum/component/proximity_monitor))
update_icon()
else
to_chat(usr, "There is no assembly to remove.")
@@ -194,7 +195,9 @@
return ..()
assembly = W
user.drop_item()
- W.loc = src
+ W.forceMove(src)
+ if(assembly.has_prox_sensors())
+ AddComponent(/datum/component/proximity_monitor)
overlays += "assembly"
else
..()
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index ff01fc34506..79ba8deccbd 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -126,6 +126,7 @@
usr.visible_message("[usr] detaches [rig] from [src].", "You detach [rig] from [src].")
rig.forceMove(get_turf(usr))
rig = null
+ qdel(GetComponent(/datum/component/proximity_monitor))
lastrigger = null
overlays.Cut()
@@ -148,7 +149,8 @@
rig = H
user.drop_item()
H.forceMove(src)
-
+ if(rig.has_prox_sensors())
+ AddComponent(/datum/component/proximity_monitor)
var/icon/test = getFlatIcon(H)
test.Shift(NORTH, 1)
test.Shift(EAST, 6)
diff --git a/paradise.dme b/paradise.dme
index b7e13ffe768..efddfaea144 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -307,6 +307,7 @@
#include "code\datums\components\label.dm"
#include "code\datums\components\material_container.dm"
#include "code\datums\components\paintable.dm"
+#include "code\datums\components\proximity_monitor.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\spawner.dm"
#include "code\datums\components\spooky.dm"