mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 18:53:06 +00:00
@@ -1,14 +1,14 @@
|
||||
/**
|
||||
* # Component
|
||||
*
|
||||
* The component datum
|
||||
*
|
||||
* A component should be a single standalone unit
|
||||
* of functionality, that works by receiving signals from it's parent
|
||||
* object to provide some single functionality (i.e a slippery component)
|
||||
* that makes the object it's attached to cause people to slip over.
|
||||
* Useful when you want shared behaviour independent of type inheritance
|
||||
*/
|
||||
* # Component
|
||||
*
|
||||
* The component datum
|
||||
*
|
||||
* A component should be a single standalone unit
|
||||
* of functionality, that works by receiving signals from it's parent
|
||||
* object to provide some single functionality (i.e a slippery component)
|
||||
* that makes the object it's attached to cause people to slip over.
|
||||
* Useful when you want shared behaviour independent of type inheritance
|
||||
*/
|
||||
/datum/component
|
||||
/**
|
||||
* Defines how duplicate existing components are handled when added to a datum
|
||||
@@ -38,14 +38,17 @@
|
||||
*/
|
||||
var/can_transfer = FALSE
|
||||
|
||||
/// A lazy list of the sources for this component
|
||||
var/list/sources
|
||||
|
||||
/**
|
||||
* Create a new component.
|
||||
*
|
||||
* Additional arguments are passed to [Initialize()][/datum/component/proc/Initialize]
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/P the parent datum this component reacts to signals from
|
||||
*/
|
||||
* Create a new component.
|
||||
*
|
||||
* Additional arguments are passed to [Initialize()][/datum/component/proc/Initialize]
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/P the parent datum this component reacts to signals from
|
||||
*/
|
||||
/datum/component/New(list/raw_args)
|
||||
parent = raw_args[1]
|
||||
var/list/arguments = raw_args.Copy(2)
|
||||
@@ -57,50 +60,50 @@
|
||||
_JoinParent(parent)
|
||||
|
||||
/**
|
||||
* Called during component creation with the same arguments as in new excluding parent.
|
||||
*
|
||||
* Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
|
||||
*/
|
||||
* Called during component creation with the same arguments as in new excluding parent.
|
||||
*
|
||||
* Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
|
||||
*/
|
||||
/datum/component/proc/Initialize(...)
|
||||
return
|
||||
|
||||
/**
|
||||
* Properly removes the component from `parent` and cleans up references
|
||||
*
|
||||
* Arguments:
|
||||
* * force - makes it not check for and remove the component from the parent
|
||||
* * silent - deletes the component without sending a [COMSIG_COMPONENT_REMOVING] signal
|
||||
*/
|
||||
/datum/component/Destroy(force=FALSE, silent=FALSE)
|
||||
if(!force && parent)
|
||||
* Properly removes the component from `parent` and cleans up references
|
||||
*
|
||||
* Arguments:
|
||||
* * force - makes it not check for and remove the component from the parent
|
||||
*/
|
||||
/datum/component/Destroy(force = FALSE)
|
||||
if(!parent)
|
||||
return ..()
|
||||
if(!force)
|
||||
_RemoveFromParent()
|
||||
if(parent && !silent) //CHOMPEdit
|
||||
SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
|
||||
SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
|
||||
parent = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Internal proc to handle behaviour of components when joining a parent
|
||||
*/
|
||||
* Internal proc to handle behaviour of components when joining a parent
|
||||
*/
|
||||
/datum/component/proc/_JoinParent()
|
||||
var/datum/P = parent
|
||||
//lazy init the parent's dc list
|
||||
var/list/dc = P.datum_components
|
||||
var/list/dc = P._datum_components
|
||||
if(!dc)
|
||||
P.datum_components = dc = list()
|
||||
P._datum_components = dc = list()
|
||||
|
||||
//set up the typecache
|
||||
var/our_type = type
|
||||
for(var/I in _GetInverseTypeList(our_type))
|
||||
var/test = dc[I]
|
||||
if(test) //already another component of this type here
|
||||
if(test) //already another component of this type here
|
||||
var/list/components_of_type
|
||||
if(!length(test))
|
||||
components_of_type = list(test)
|
||||
dc[I] = components_of_type
|
||||
else
|
||||
components_of_type = test
|
||||
if(I == our_type) //exact match, take priority
|
||||
if(I == our_type) //exact match, take priority
|
||||
var/inserted = FALSE
|
||||
for(var/J in 1 to components_of_type.len)
|
||||
var/datum/component/C = components_of_type[J]
|
||||
@@ -110,198 +113,126 @@
|
||||
break
|
||||
if(!inserted)
|
||||
components_of_type += src
|
||||
else //indirect match, back of the line with ya
|
||||
else //indirect match, back of the line with ya
|
||||
components_of_type += src
|
||||
else //only component of this type, no list
|
||||
else //only component of this type, no list
|
||||
dc[I] = src
|
||||
|
||||
RegisterWithParent()
|
||||
|
||||
/**
|
||||
* Internal proc to handle behaviour when being removed from a parent
|
||||
*/
|
||||
* Internal proc to handle behaviour when being removed from a parent
|
||||
*/
|
||||
/datum/component/proc/_RemoveFromParent()
|
||||
var/datum/P = parent
|
||||
var/list/dc = P.datum_components
|
||||
var/datum/parent = src.parent
|
||||
var/list/parents_components = parent._datum_components
|
||||
for(var/I in _GetInverseTypeList())
|
||||
var/list/components_of_type = dc[I]
|
||||
if(length(components_of_type)) //
|
||||
var/list/components_of_type = parents_components[I]
|
||||
|
||||
if(length(components_of_type)) //
|
||||
var/list/subtracted = components_of_type - src
|
||||
if(subtracted.len == 1) //only 1 guy left
|
||||
dc[I] = subtracted[1] //make him special
|
||||
|
||||
if(subtracted.len == 1) //only 1 guy left
|
||||
parents_components[I] = subtracted[1] //make him special
|
||||
else
|
||||
dc[I] = subtracted
|
||||
else //just us
|
||||
dc -= I
|
||||
if(!dc.len)
|
||||
P.datum_components = null
|
||||
parents_components[I] = subtracted
|
||||
|
||||
else //just us
|
||||
parents_components -= I
|
||||
|
||||
if(!parents_components.len)
|
||||
parent._datum_components = null
|
||||
|
||||
UnregisterFromParent()
|
||||
|
||||
/**
|
||||
* Register the component with the parent object
|
||||
*
|
||||
* Use this proc to register with your parent object
|
||||
*
|
||||
* Overridable proc that's called when added to a new parent
|
||||
*/
|
||||
* Register the component with the parent object
|
||||
*
|
||||
* Use this proc to register with your parent object
|
||||
*
|
||||
* Overridable proc that's called when added to a new parent
|
||||
*/
|
||||
/datum/component/proc/RegisterWithParent()
|
||||
return
|
||||
|
||||
/**
|
||||
* Unregister from our parent object
|
||||
*
|
||||
* Use this proc to unregister from your parent object
|
||||
*
|
||||
* Overridable proc that's called when removed from a parent
|
||||
* *
|
||||
*/
|
||||
* Unregister from our parent object
|
||||
*
|
||||
* Use this proc to unregister from your parent object
|
||||
*
|
||||
* Overridable proc that's called when removed from a parent
|
||||
* *
|
||||
*/
|
||||
/datum/component/proc/UnregisterFromParent()
|
||||
return
|
||||
|
||||
/**
|
||||
* 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 recieve a callback to the given proctype
|
||||
* Return values from procs registered must be a bitfield
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/target The target to listen for signals from
|
||||
* * sig_type_or_types Either a string signal name, or a list of signal names (strings)
|
||||
* * 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, sig_type_or_types, proctype, override = FALSE)
|
||||
if(QDELETED(src) || QDELETED(target))
|
||||
return
|
||||
|
||||
var/list/procs = signal_procs
|
||||
if(!procs)
|
||||
signal_procs = procs = list()
|
||||
if(!procs[target])
|
||||
procs[target] = list()
|
||||
var/list/lookup = target.comp_lookup
|
||||
if(!lookup)
|
||||
target.comp_lookup = lookup = list()
|
||||
|
||||
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
|
||||
for(var/sig_type in sig_types)
|
||||
if(!override && procs[target][sig_type])
|
||||
var/trace_msg = "[sig_type] overridden. Use override = TRUE to suppress this warning."
|
||||
if(isatom(target))
|
||||
var/atom/A = target
|
||||
trace_msg += " [A.x],[A.y],[A.z]"
|
||||
stack_trace(trace_msg)
|
||||
|
||||
procs[target][sig_type] = proctype
|
||||
|
||||
if(!lookup[sig_type]) // Nothing has registered here yet
|
||||
lookup[sig_type] = src
|
||||
else if(lookup[sig_type] == src) // We already registered here
|
||||
continue
|
||||
else if(!length(lookup[sig_type])) // One other thing registered here
|
||||
lookup[sig_type] = list(lookup[sig_type]=TRUE)
|
||||
lookup[sig_type][src] = TRUE
|
||||
else // Many other things have registered here
|
||||
lookup[sig_type][src] = TRUE
|
||||
|
||||
signal_enabled = TRUE
|
||||
|
||||
//CHOMPAdd start
|
||||
/// 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)
|
||||
//CHOMPAdd end
|
||||
* Called when the component has a new source registered.
|
||||
* Return COMPONENT_INCOMPATIBLE to signal that the source is incompatible and should not be added
|
||||
*/
|
||||
/datum/component/proc/on_source_add(source, ...)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(dupe_mode != COMPONENT_DUPE_SOURCES)
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
LAZYOR(sources, source)
|
||||
|
||||
/**
|
||||
* 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_type_or_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?.comp_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])
|
||||
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 comp_lookup")
|
||||
if(src in lookup[sig])
|
||||
lookup -= sig
|
||||
if(!length(lookup))
|
||||
target.comp_lookup = null
|
||||
break
|
||||
if(0)
|
||||
lookup -= sig
|
||||
if(!length(lookup))
|
||||
target.comp_lookup = null
|
||||
break
|
||||
else
|
||||
lookup[sig] -= src
|
||||
|
||||
signal_procs[target] -= sig_type_or_types
|
||||
if(!signal_procs[target].len)
|
||||
signal_procs -= target
|
||||
* Called when the component has a source removed.
|
||||
* You probably want to call parent after you do your logic because at the end of this we qdel if we have no sources remaining!
|
||||
*/
|
||||
/datum/component/proc/on_source_remove(source)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(dupe_mode != COMPONENT_DUPE_SOURCES)
|
||||
CRASH("Component '[type]' does not use sources but is trying to remove a source")
|
||||
LAZYREMOVE(sources, source)
|
||||
if(!LAZYLEN(sources))
|
||||
qdel(src)
|
||||
|
||||
/**
|
||||
* Called on a component when a component of the same type was added to the same parent
|
||||
*
|
||||
* See [/datum/component/var/dupe_mode]
|
||||
*
|
||||
* `C`'s type will always be the same of the called component
|
||||
*/
|
||||
* Called on a component when a component of the same type was added to the same parent
|
||||
*
|
||||
* See [/datum/component/var/dupe_mode]
|
||||
*
|
||||
* `C`'s type will always be the same of the called component
|
||||
*/
|
||||
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
|
||||
return
|
||||
|
||||
|
||||
/**
|
||||
* Called on a component when a component of the same type was added to the same parent with [COMPONENT_DUPE_SELECTIVE]
|
||||
*
|
||||
* See [/datum/component/var/dupe_mode]
|
||||
*
|
||||
* `C`'s type will always be the same of the called component
|
||||
*
|
||||
* return TRUE if you are absorbing the component, otherwise FALSE if you are fine having it exist as a duplicate component
|
||||
*/
|
||||
* Called on a component when a component of the same type was added to the same parent with [COMPONENT_DUPE_SELECTIVE]
|
||||
*
|
||||
* See [/datum/component/var/dupe_mode]
|
||||
*
|
||||
* `C`'s type will always be the same of the called component
|
||||
*
|
||||
* return TRUE if you are absorbing the component, otherwise FALSE if you are fine having it exist as a duplicate component
|
||||
*/
|
||||
/datum/component/proc/CheckDupeComponent(datum/component/C, ...)
|
||||
return
|
||||
|
||||
|
||||
/**
|
||||
* Callback Just before this component is transferred
|
||||
*
|
||||
* Use this to do any special cleanup you might need to do before being deregged from an object
|
||||
*/
|
||||
* Callback Just before this component is transferred
|
||||
*
|
||||
* Use this to do any special cleanup you might need to do before being deregged from an object
|
||||
*/
|
||||
/datum/component/proc/PreTransfer()
|
||||
return
|
||||
|
||||
/**
|
||||
* Callback Just after a component is transferred
|
||||
*
|
||||
* Use this to do any special setup you need to do after being moved to a new object
|
||||
*
|
||||
* Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
|
||||
*/
|
||||
* Callback Just after a component is transferred
|
||||
*
|
||||
* Use this to do any special setup you need to do after being moved to a new object
|
||||
*
|
||||
* Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
|
||||
*/
|
||||
/datum/component/proc/PostTransfer()
|
||||
return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it
|
||||
|
||||
/**
|
||||
* Internal proc to create a list of our type and all parent types
|
||||
*/
|
||||
* Internal proc to create a list of our type and all parent types
|
||||
*/
|
||||
/datum/component/proc/_GetInverseTypeList(our_type = type)
|
||||
//we can do this one simple trick
|
||||
. = list(our_type)
|
||||
@@ -311,42 +242,20 @@
|
||||
. += current_type
|
||||
current_type = type2parent(current_type)
|
||||
|
||||
/**
|
||||
* Internal proc to handle most all of the signaling procedure
|
||||
*
|
||||
* Will runtime if used on datums with an empty component list
|
||||
*
|
||||
* Use the [SEND_SIGNAL] define instead
|
||||
*/
|
||||
/datum/proc/_SendSignal(sigtype, list/arguments)
|
||||
var/target = comp_lookup[sigtype]
|
||||
if(!length(target))
|
||||
var/datum/C = target
|
||||
if(!C.signal_enabled)
|
||||
return NONE
|
||||
var/proctype = C.signal_procs[src][sigtype]
|
||||
return NONE | CallAsync(C, proctype, arguments)
|
||||
. = NONE
|
||||
for(var/datum/C as anything in target)
|
||||
if(!C.signal_enabled)
|
||||
continue
|
||||
var/proctype = C.signal_procs[src][sigtype]
|
||||
. |= CallAsync(C, proctype, arguments)
|
||||
|
||||
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
|
||||
/**
|
||||
* Return any component assigned to this datum of the given type
|
||||
*
|
||||
* This will throw an error if it's possible to have more than one component of that type on the parent
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/component/c_type The typepath of the component you want to get a reference to
|
||||
*/
|
||||
* Return any component assigned to this datum of the given type
|
||||
*
|
||||
* This will throw an error if it's possible to have more than one component of that type on the parent
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/component/c_type The typepath of the component you want to get a reference to
|
||||
*/
|
||||
/datum/proc/GetComponent(datum/component/c_type)
|
||||
RETURN_TYPE(c_type)
|
||||
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED || initial(c_type.dupe_mode) == COMPONENT_DUPE_SELECTIVE)
|
||||
stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
|
||||
var/list/dc = datum_components
|
||||
var/list/dc = _datum_components
|
||||
if(!dc)
|
||||
return null
|
||||
. = dc[c_type]
|
||||
@@ -355,18 +264,18 @@
|
||||
|
||||
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
|
||||
/**
|
||||
* Return any component assigned to this datum of the exact given type
|
||||
*
|
||||
* This will throw an error if it's possible to have more than one component of that type on the parent
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/component/c_type The typepath of the component you want to get a reference to
|
||||
*/
|
||||
* Return any component assigned to this datum of the exact given type
|
||||
*
|
||||
* This will throw an error if it's possible to have more than one component of that type on the parent
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/component/c_type The typepath of the component you want to get a reference to
|
||||
*/
|
||||
/datum/proc/GetExactComponent(datum/component/c_type)
|
||||
RETURN_TYPE(c_type)
|
||||
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED || initial(c_type.dupe_mode) == COMPONENT_DUPE_SELECTIVE)
|
||||
stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
|
||||
var/list/dc = datum_components
|
||||
var/list/dc = _datum_components
|
||||
if(!dc)
|
||||
return null
|
||||
var/datum/component/C = dc[c_type]
|
||||
@@ -378,113 +287,154 @@
|
||||
return null
|
||||
|
||||
/**
|
||||
* Get all components of a given type that are attached to this datum
|
||||
*
|
||||
* Arguments:
|
||||
* * c_type The component type path
|
||||
*/
|
||||
* Get all components of a given type that are attached to this datum
|
||||
*
|
||||
* Arguments:
|
||||
* * c_type The component type path
|
||||
*/
|
||||
/datum/proc/GetComponents(c_type)
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
return null
|
||||
. = dc[c_type]
|
||||
if(!length(.))
|
||||
return list(.)
|
||||
var/list/components = _datum_components?[c_type]
|
||||
if(!components)
|
||||
return list()
|
||||
return islist(components) ? components : list(components)
|
||||
|
||||
/**
|
||||
* Creates an instance of `new_type` in the datum and attaches to it as parent
|
||||
*
|
||||
* Sends the [COMSIG_COMPONENT_ADDED] signal to the datum
|
||||
*
|
||||
* Returns the component that was created. Or the old component in a dupe situation where [COMPONENT_DUPE_UNIQUE] was set
|
||||
*
|
||||
* If this tries to add a component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
|
||||
*
|
||||
* Properly handles duplicate situations based on the `dupe_mode` var
|
||||
*/
|
||||
/datum/proc/_AddComponent(list/raw_args)
|
||||
var/new_type = raw_args[1]
|
||||
var/datum/component/nt = new_type
|
||||
var/dm = initial(nt.dupe_mode)
|
||||
var/dt = initial(nt.dupe_type)
|
||||
* Creates an instance of `new_type` in the datum and attaches to it as parent
|
||||
*
|
||||
* Sends the [COMSIG_COMPONENT_ADDED] signal to the datum
|
||||
*
|
||||
* Returns the component that was created. Or the old component in a dupe situation where [COMPONENT_DUPE_UNIQUE] was set
|
||||
*
|
||||
* If this tries to add a component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
|
||||
*
|
||||
* Properly handles duplicate situations based on the `dupe_mode` var
|
||||
*/
|
||||
/datum/proc/_AddComponent(list/raw_args, source)
|
||||
var/original_type = raw_args[1]
|
||||
var/datum/component/component_type = original_type
|
||||
|
||||
var/datum/component/old_comp
|
||||
var/datum/component/new_comp
|
||||
if(QDELING(src))
|
||||
CRASH("Attempted to add a new component of type \[[component_type]\] to a qdeleting parent of type \[[type]\]!")
|
||||
|
||||
if(ispath(nt))
|
||||
if(nt == /datum/component)
|
||||
CRASH("[nt] attempted instantiation!")
|
||||
else
|
||||
new_comp = nt
|
||||
nt = new_comp.type
|
||||
var/datum/component/new_component
|
||||
|
||||
if(!ispath(component_type, /datum/component))
|
||||
if(!istype(component_type, /datum/component))
|
||||
CRASH("Attempted to instantiate \[[component_type]\] as a component added to parent of type \[[type]\]!")
|
||||
else
|
||||
new_component = component_type
|
||||
component_type = new_component.type
|
||||
else if(component_type == /datum/component)
|
||||
CRASH("[component_type] attempted instantiation!")
|
||||
|
||||
var/dupe_mode = initial(component_type.dupe_mode)
|
||||
var/dupe_type = initial(component_type.dupe_type)
|
||||
var/uses_sources = (dupe_mode == COMPONENT_DUPE_SOURCES)
|
||||
if(uses_sources && !source)
|
||||
CRASH("Attempted to add a sourced component of type '[component_type]' to '[type]' without a source!")
|
||||
else if(!uses_sources && source)
|
||||
CRASH("Attempted to add a normal component of type '[component_type]' to '[type]' with a source!")
|
||||
|
||||
var/datum/component/old_component
|
||||
|
||||
raw_args[1] = src
|
||||
|
||||
if(dm != COMPONENT_DUPE_ALLOWED)
|
||||
if(!dt)
|
||||
old_comp = GetExactComponent(nt)
|
||||
if(dupe_mode != COMPONENT_DUPE_ALLOWED && dupe_mode != COMPONENT_DUPE_SELECTIVE && dupe_mode != COMPONENT_DUPE_SOURCES)
|
||||
if(!dupe_type)
|
||||
old_component = GetExactComponent(component_type)
|
||||
else
|
||||
old_comp = GetComponent(dt)
|
||||
if(old_comp)
|
||||
switch(dm)
|
||||
old_component = GetComponent(dupe_type)
|
||||
|
||||
if(old_component)
|
||||
switch(dupe_mode)
|
||||
if(COMPONENT_DUPE_UNIQUE)
|
||||
if(!new_comp)
|
||||
new_comp = new nt(raw_args)
|
||||
if(!QDELETED(new_comp))
|
||||
old_comp.InheritComponent(new_comp, TRUE)
|
||||
QDEL_NULL(new_comp)
|
||||
if(!new_component)
|
||||
new_component = new component_type(raw_args)
|
||||
if(!QDELETED(new_component))
|
||||
old_component.InheritComponent(new_component, TRUE)
|
||||
QDEL_NULL(new_component)
|
||||
|
||||
if(COMPONENT_DUPE_HIGHLANDER)
|
||||
if(!new_comp)
|
||||
new_comp = new nt(raw_args)
|
||||
if(!QDELETED(new_comp))
|
||||
new_comp.InheritComponent(old_comp, FALSE)
|
||||
QDEL_NULL(old_comp)
|
||||
if(!new_component)
|
||||
new_component = new component_type(raw_args)
|
||||
if(!QDELETED(new_component))
|
||||
new_component.InheritComponent(old_component, FALSE)
|
||||
QDEL_NULL(old_component)
|
||||
|
||||
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
|
||||
if(!new_comp)
|
||||
if(!new_component)
|
||||
var/list/arguments = raw_args.Copy(2)
|
||||
arguments.Insert(1, null, TRUE)
|
||||
old_comp.InheritComponent(arglist(arguments))
|
||||
old_component.InheritComponent(arglist(arguments))
|
||||
else
|
||||
old_comp.InheritComponent(new_comp, TRUE)
|
||||
if(COMPONENT_DUPE_SELECTIVE)
|
||||
var/list/arguments = raw_args.Copy()
|
||||
arguments[1] = new_comp
|
||||
var/make_new_component = TRUE
|
||||
for(var/datum/component/C as anything in GetComponents(new_type))
|
||||
if(C.CheckDupeComponent(arglist(arguments)))
|
||||
make_new_component = FALSE
|
||||
QDEL_NULL(new_comp)
|
||||
break
|
||||
if(!new_comp && make_new_component)
|
||||
new_comp = new nt(raw_args)
|
||||
else if(!new_comp)
|
||||
new_comp = new nt(raw_args) // There's a valid dupe mode but there's no old component, act like normal
|
||||
else if(!new_comp)
|
||||
new_comp = new nt(raw_args) // Dupes are allowed, act like normal
|
||||
old_component.InheritComponent(new_component, TRUE)
|
||||
|
||||
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
|
||||
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
|
||||
return new_comp
|
||||
return old_comp
|
||||
if(COMPONENT_DUPE_SOURCES)
|
||||
if(source in old_component.sources)
|
||||
return old_component // source already registered, no work to do
|
||||
|
||||
if(old_component.on_source_add(arglist(list(source) + raw_args.Copy(2))) == COMPONENT_INCOMPATIBLE)
|
||||
stack_trace("incompatible source added to a [old_component.type]. Args: [json_encode(raw_args)]")
|
||||
return null
|
||||
|
||||
else if(!new_component)
|
||||
new_component = new component_type(raw_args) // There's a valid dupe mode but there's no old component, act like normal
|
||||
|
||||
else if(dupe_mode == COMPONENT_DUPE_SELECTIVE)
|
||||
var/list/arguments = raw_args.Copy()
|
||||
arguments[1] = new_component
|
||||
var/make_new_component = TRUE
|
||||
for(var/datum/component/existing_component as anything in GetComponents(original_type))
|
||||
if(existing_component.CheckDupeComponent(arglist(arguments)))
|
||||
make_new_component = FALSE
|
||||
QDEL_NULL(new_component)
|
||||
break
|
||||
if(!new_component && make_new_component)
|
||||
new_component = new component_type(raw_args)
|
||||
|
||||
else if(dupe_mode == COMPONENT_DUPE_SOURCES)
|
||||
new_component = new component_type(raw_args)
|
||||
if(new_component.on_source_add(arglist(list(source) + raw_args.Copy(2))) == COMPONENT_INCOMPATIBLE)
|
||||
stack_trace("incompatible source added to a [new_component.type]. Args: [json_encode(raw_args)]")
|
||||
return null
|
||||
|
||||
else if(!new_component)
|
||||
new_component = new component_type(raw_args) // Dupes are allowed, act like normal
|
||||
|
||||
if(!old_component && !QDELETED(new_component)) // Nothing related to duplicate components happened and the new component is healthy
|
||||
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_component)
|
||||
return new_component
|
||||
|
||||
return old_component
|
||||
|
||||
/**
|
||||
* Get existing component of type, or create it and return a reference to it
|
||||
*
|
||||
* Use this if the item needs to exist at the time of this call, but may not have been created before now
|
||||
*
|
||||
* Arguments:
|
||||
* * component_type The typepath of the component to create or return
|
||||
* * ... additional arguments to be passed when creating the component if it does not exist
|
||||
*/
|
||||
/datum/proc/LoadComponent(component_type, ...)
|
||||
. = GetComponent(component_type)
|
||||
* Removes a component source from this datum
|
||||
*/
|
||||
/datum/proc/RemoveComponentSource(source, datum/component/component_type)
|
||||
if(ispath(component_type))
|
||||
component_type = GetExactComponent(component_type)
|
||||
if(!component_type)
|
||||
return
|
||||
component_type.on_source_remove(source)
|
||||
|
||||
/**
|
||||
* Get existing component of type, or create it and return a reference to it
|
||||
*
|
||||
* Use this if the item needs to exist at the time of this call, but may not have been created before now
|
||||
*
|
||||
* Arguments:
|
||||
* * component_type The typepath of the component to create or return
|
||||
* * ... additional arguments to be passed when creating the component if it does not exist
|
||||
*/
|
||||
/datum/proc/_LoadComponent(list/arguments)
|
||||
. = GetComponent(arguments[1])
|
||||
if(!.)
|
||||
return _AddComponent(args)
|
||||
return _AddComponent(arguments)
|
||||
|
||||
/**
|
||||
* Removes the component from parent, ends up with a null parent
|
||||
*/
|
||||
/datum/component/proc/RemoveComponent()
|
||||
* Removes the component from parent, ends up with a null parent
|
||||
* Used as a helper proc by the component transfer proc, does not clean up the component like Destroy does
|
||||
*/
|
||||
/datum/component/proc/ClearFromParent()
|
||||
if(!parent)
|
||||
return
|
||||
var/datum/old_parent = parent
|
||||
@@ -494,18 +444,18 @@
|
||||
SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src)
|
||||
|
||||
/**
|
||||
* Transfer this component to another parent
|
||||
*
|
||||
* Component is taken from source datum
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/component/target Target datum to transfer to
|
||||
*/
|
||||
* Transfer this component to another parent
|
||||
*
|
||||
* Component is taken from source datum
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/component/target Target datum to transfer to
|
||||
*/
|
||||
/datum/proc/TakeComponent(datum/component/target)
|
||||
if(!target || target.parent == src)
|
||||
return
|
||||
if(target.parent)
|
||||
target.RemoveComponent()
|
||||
target.ClearFromParent()
|
||||
target.parent = src
|
||||
var/result = target.PostTransfer()
|
||||
switch(result)
|
||||
@@ -518,29 +468,30 @@
|
||||
target._JoinParent()
|
||||
|
||||
/**
|
||||
* Transfer all components to target
|
||||
*
|
||||
* All components from source datum are taken
|
||||
*
|
||||
* Arguments:
|
||||
* * /datum/target the target to move the components to
|
||||
*/
|
||||
* Transfer all components to target
|
||||
*
|
||||
* All components from source datum are taken
|
||||
*
|
||||
* Arguments:
|
||||
* * /datum/target the target to move the components to
|
||||
*/
|
||||
/datum/proc/TransferComponents(datum/target)
|
||||
var/list/dc = datum_components
|
||||
var/list/dc = _datum_components
|
||||
if(!dc)
|
||||
return
|
||||
var/comps = dc[/datum/component]
|
||||
if(islist(comps))
|
||||
for(var/datum/component/I in comps)
|
||||
if(I.can_transfer)
|
||||
target.TakeComponent(I)
|
||||
else
|
||||
var/datum/component/C = comps
|
||||
if(C.can_transfer)
|
||||
target.TakeComponent(comps)
|
||||
for(var/component_key in dc)
|
||||
var/component_or_list = dc[component_key]
|
||||
if(islist(component_or_list))
|
||||
for(var/datum/component/I in component_or_list)
|
||||
if(I.can_transfer)
|
||||
target.TakeComponent(I)
|
||||
else
|
||||
var/datum/component/C = component_or_list
|
||||
if(C.can_transfer)
|
||||
target.TakeComponent(C)
|
||||
|
||||
/**
|
||||
* Return the object that is the host of any UI's that this component has
|
||||
*/
|
||||
* Return the object that is the host of any UI's that this component has
|
||||
*/
|
||||
/datum/component/tgui_host()
|
||||
return parent
|
||||
|
||||
Reference in New Issue
Block a user