mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2025-12-20 07:12:55 +00:00
* 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>
140 lines
5.9 KiB
Plaintext
140 lines
5.9 KiB
Plaintext
/**
|
|
* # 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.
|