mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-01-29 10:41:34 +00:00
Refactored (second passage) how movement works, now it's mostly in line with TG handling and avoids calling 3 gazillion Cross() Uncross() etc. on every atom in a turf. Fixed EMP protection from species not actually protecting (this includes the surge prevention for IPCs). Fixed EMP 3D calculation runtiming because I forgot to make the value absolute and it was doing the square root of a negative number. It's now possible to queue the round to start with the Start Round verb even while the system is initializing, for an even faster pain train to enter the round and test things.
129 lines
4.9 KiB
Plaintext
129 lines
4.9 KiB
Plaintext
/**
|
|
* Register to listen for a signal from the passed in target
|
|
*
|
|
* This sets up a listening relationship such that when the target object emits a signal
|
|
* the source datum this proc is called upon, will receive a callback to the given proctype
|
|
* Use PROC_REF(procname), TYPE_PROC_REF(type,procname) or GLOBAL_PROC_REF(procname) macros to validate the passed in proc at compile time.
|
|
* PROC_REF for procs defined on current type or its ancestors, TYPE_PROC_REF for procs defined on unrelated type and GLOBAL_PROC_REF for global procs.
|
|
* Return values from procs registered must be a bitfield
|
|
*
|
|
* Arguments:
|
|
* * datum/target The target to listen for signals from
|
|
* * signal_type A signal name
|
|
* * proctype The proc to call back when the signal is emitted
|
|
* * override If a previous registration exists you must explicitly set this
|
|
*/
|
|
/datum/proc/RegisterSignal(datum/target, signal_type, proctype, override = FALSE)
|
|
if(QDELETED(src) || QDELETED(target))
|
|
return
|
|
|
|
if (islist(signal_type))
|
|
var/static/list/known_failures = list()
|
|
var/list/signal_type_list = signal_type
|
|
var/message = "([target.type]) is registering [signal_type_list.Join(", ")] as a list, the older method. Change it to RegisterSignals."
|
|
|
|
if (!(message in known_failures))
|
|
known_failures[message] = TRUE
|
|
stack_trace("[target] [message]")
|
|
|
|
RegisterSignals(target, signal_type, proctype, override)
|
|
return
|
|
|
|
var/list/procs = (_signal_procs ||= list())
|
|
var/list/target_procs = (procs[target] ||= list())
|
|
var/list/lookup = (target._listen_lookup ||= list())
|
|
|
|
var/exists = target_procs[signal_type]
|
|
target_procs[signal_type] = proctype
|
|
|
|
if(exists)
|
|
if(!override)
|
|
var/override_message = "[signal_type] overridden. Use override = TRUE to suppress this warning.\nTarget: [target] ([target.type]) Existing Proc: [exists] New Proc: [proctype]"
|
|
log_signal(override_message)
|
|
stack_trace(override_message)
|
|
return
|
|
|
|
var/list/looked_up = lookup[signal_type]
|
|
|
|
if(isnull(looked_up)) // Nothing has registered here yet
|
|
lookup[signal_type] = src
|
|
else if(!islist(looked_up)) // One other thing registered here
|
|
lookup[signal_type] = list(looked_up, src)
|
|
else // Many other things have registered here
|
|
looked_up += src
|
|
|
|
/// Registers multiple signals to the same proc.
|
|
/datum/proc/RegisterSignals(datum/target, list/signal_types, proctype, override = FALSE)
|
|
for (var/signal_type in signal_types)
|
|
RegisterSignal(target, signal_type, proctype, override)
|
|
|
|
/**
|
|
* Stop listening to a given signal from target
|
|
*
|
|
* Breaks the relationship between target and source datum, removing the callback when the signal fires
|
|
*
|
|
* Doesn't care if a registration exists or not
|
|
*
|
|
* Arguments:
|
|
* * datum/target Datum to stop listening to signals from
|
|
* * sig_typeor_types Signal string key or list of signal keys to stop listening to specifically
|
|
*/
|
|
/datum/proc/UnregisterSignal(datum/target, sig_type_or_types)
|
|
var/list/lookup = target._listen_lookup
|
|
if(!_signal_procs || !_signal_procs[target] || !lookup)
|
|
return
|
|
if(!islist(sig_type_or_types))
|
|
sig_type_or_types = list(sig_type_or_types)
|
|
for(var/sig in sig_type_or_types)
|
|
if(!_signal_procs[target][sig])
|
|
if(!istext(sig))
|
|
stack_trace("We're unregistering with something that isn't a valid signal \[[sig]\], you fucked up")
|
|
continue
|
|
switch(length(lookup[sig]))
|
|
if(2)
|
|
lookup[sig] = (lookup[sig]-src)[1]
|
|
if(1)
|
|
stack_trace("[target] ([target.type]) somehow has single length list inside _listen_lookup")
|
|
if(src in lookup[sig])
|
|
lookup -= sig
|
|
if(!length(lookup))
|
|
target._listen_lookup = null
|
|
break
|
|
if(0)
|
|
if(lookup[sig] != src)
|
|
continue
|
|
lookup -= sig
|
|
if(!length(lookup))
|
|
target._listen_lookup = null
|
|
break
|
|
else
|
|
lookup[sig] -= src
|
|
|
|
_signal_procs[target] -= sig_type_or_types
|
|
if(!_signal_procs[target].len)
|
|
_signal_procs -= target
|
|
|
|
/**
|
|
* Internal proc to handle most all of the signaling procedure
|
|
*
|
|
* Will runtime if used on datums with an empty lookup list
|
|
*
|
|
* Use the [SEND_SIGNAL] define instead
|
|
*/
|
|
/datum/proc/_SendSignal(sigtype, list/arguments)
|
|
var/target = _listen_lookup[sigtype]
|
|
if(!length(target))
|
|
var/datum/listening_datum = target
|
|
return NONE | call(listening_datum, listening_datum._signal_procs[src][sigtype])(arglist(arguments))
|
|
. = NONE
|
|
// This exists so that even if one of the signal receivers unregisters the signal,
|
|
// all the objects that are receiving the signal get the signal this final time.
|
|
// AKA: No you can't cancel the signal reception of another object by doing an unregister in the same signal.
|
|
var/list/queued_calls = list()
|
|
// This should be faster than doing `var/datum/listening_datum as anything in target` as it does not implicitly copy the list
|
|
for(var/i in 1 to length(target))
|
|
var/datum/listening_datum = target[i]
|
|
queued_calls.Add(listening_datum, listening_datum._signal_procs[src][sigtype])
|
|
for(var/i in 1 to length(queued_calls) step 2)
|
|
. |= call(queued_calls[i], queued_calls[i + 1])(arglist(arguments))
|