mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
108 lines
4.3 KiB
Plaintext
108 lines
4.3 KiB
Plaintext
/**
|
|
* This component behaves similar to connect_loc_behalf but for all turfs in range, hooking into a signal on each of them.
|
|
* Just like connect_loc_behalf, It can react to that signal on behalf of a seperate listener.
|
|
* Good for components, though it carries some overhead. Can't be an element as that may lead to bugs.
|
|
*/
|
|
/datum/component/connect_range
|
|
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
|
|
|
/// An assoc list of signal -> procpath to register to the loc this object is on.
|
|
var/list/connections
|
|
/**
|
|
* The atom the component is tracking. The component will delete itself if the tracked is deleted.
|
|
* Signals will also be updated whenever it moves (if it's a movable).
|
|
*/
|
|
var/atom/tracked
|
|
|
|
/// The component will hook into signals only on turfs not farther from tracked than this.
|
|
var/range
|
|
/// Whether the component works when the movable isn't directly located on a turf.
|
|
var/works_in_containers
|
|
|
|
/datum/component/connect_range/Initialize(atom/tracked, list/connections, range, works_in_containers = TRUE)
|
|
if(!isatom(tracked) || isarea(tracked) || range < 0)
|
|
return COMPONENT_INCOMPATIBLE
|
|
src.connections = connections
|
|
src.range = range
|
|
set_tracked(tracked)
|
|
src.works_in_containers = works_in_containers
|
|
|
|
/datum/component/connect_range/Destroy()
|
|
set_tracked(null)
|
|
return ..()
|
|
|
|
/datum/component/connect_range/InheritComponent(datum/component/component, original, atom/tracked, list/connections, range, works_in_containers)
|
|
// Not equivalent. Checks if they are not the same list via shallow comparison.
|
|
if(!compare_list(src.connections, connections))
|
|
stack_trace("connect_range component attached to [parent] tried to inherit another connect_range component with different connections")
|
|
return
|
|
if(src.tracked != tracked)
|
|
set_tracked(tracked)
|
|
if(src.range == range && src.works_in_containers == works_in_containers)
|
|
return
|
|
//Unregister the signals with the old settings.
|
|
unregister_signals(isturf(tracked) ? tracked : tracked.loc)
|
|
src.range = range
|
|
src.works_in_containers = works_in_containers
|
|
//Re-register the signals with the new settings.
|
|
update_signals(src.tracked)
|
|
|
|
/datum/component/connect_range/proc/set_tracked(atom/new_tracked)
|
|
if(tracked) //Unregister the signals from the old tracked and its surroundings
|
|
unregister_signals(isturf(tracked) ? tracked : tracked.loc)
|
|
UnregisterSignal(tracked, list(
|
|
COMSIG_MOVABLE_MOVED,
|
|
COMSIG_PARENT_QDELETING,
|
|
))
|
|
tracked = new_tracked
|
|
if(!tracked)
|
|
return
|
|
//Register signals on the new tracked atom and its surroundings.
|
|
RegisterSignal(tracked, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
|
RegisterSignal(tracked, COMSIG_PARENT_QDELETING, PROC_REF(handle_tracked_qdel))
|
|
update_signals(tracked)
|
|
|
|
/datum/component/connect_range/proc/handle_tracked_qdel()
|
|
SIGNAL_HANDLER
|
|
qdel(src)
|
|
|
|
/datum/component/connect_range/proc/update_signals(atom/target, atom/old_loc, forced = FALSE)
|
|
var/turf/current_turf = get_turf(target)
|
|
var/on_same_turf = current_turf == get_turf(old_loc) //Only register/unregister turf signals if it's moved to a new turf.
|
|
unregister_signals(old_loc, on_same_turf)
|
|
|
|
if(isnull(current_turf))
|
|
return
|
|
|
|
if(ismovable(target.loc))
|
|
if(!works_in_containers)
|
|
return
|
|
//Keep track of possible movement of all movables the target is in.
|
|
for(var/atom/movable/container as anything in get_nested_locs(target))
|
|
RegisterSignal(container, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
|
|
|
if(on_same_turf && !forced)
|
|
return
|
|
for(var/turf/target_turf in RANGE_TURFS(range, current_turf))
|
|
for(var/signal in connections)
|
|
parent.RegisterSignal(target_turf, signal, connections[signal])
|
|
|
|
/datum/component/connect_range/proc/unregister_signals(atom/location, on_same_turf = FALSE)
|
|
//The location is null or is a container and the component shouldn't have register signals on it
|
|
if(isnull(location) || (!works_in_containers && !isturf(location)))
|
|
return
|
|
|
|
if(ismovable(location))
|
|
for(var/atom/movable/target as anything in (get_nested_locs(location) + location))
|
|
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
|
|
|
|
if(on_same_turf)
|
|
return
|
|
var/turf/previous_turf = get_turf(location)
|
|
for(var/turf/target_turf in RANGE_TURFS(range, previous_turf))
|
|
parent.UnregisterSignal(target_turf, connections)
|
|
|
|
/datum/component/connect_range/proc/on_moved(atom/movable/movable, atom/old_loc)
|
|
SIGNAL_HANDLER
|
|
update_signals(movable, old_loc)
|