diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm index 4bb27d56d6..78ade5c650 100644 --- a/code/__DEFINES/components.dm +++ b/code/__DEFINES/components.dm @@ -6,9 +6,10 @@ // How multiple components of the exact same type are handled in the same datum -#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default) -#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed -#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted +#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default) +#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed +#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted +#define COMPONENT_DUPE_UNIQUE_PASSARGS 4 //old component is given the initialization args of the new // All signals. Format: // When the signal is called: (signal arguments) diff --git a/code/datums/components/README.md b/code/datums/components/README.md index 574e628741..026b387e27 100644 --- a/code/datums/components/README.md +++ b/code/datums/components/README.md @@ -40,6 +40,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo * `COMPONENT_DUPE_HIGHLANDER` (default): Old component will be deleted, new component will first have `/datum/component/proc/InheritComponent(datum/component/old, FALSE)` on it * `COMPONENT_DUPE_ALLOWED`: The components will be treated as separate, `GetComponent()` will return the first added * `COMPONENT_DUPE_UNIQUE`: New component will be deleted, old component will first have `/datum/component/proc/InheritComponent(datum/component/new, TRUE)` on it + * `COMPONENT_DUPE_UNIQUE_PASSARGS`: New component will never exist and instead its initialization arguments will be passed on to the old component. 1. `/datum/component/var/dupe_type` (protected, type) * Definition of a duplicate component type * `null` means exact match on `type` (default) @@ -66,6 +67,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo * All components a datum owns are deleted with 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 an 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 1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final) * Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead 1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async) @@ -104,9 +106,8 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo * Allows the component to react to ownership transfers 1. `/datum/component/proc/_RemoveFromParent()` (private, final) * Clears `parent` and removes the component from it's component list -1. `/datum/component/proc/_CheckDupesAndJoinParent` (private, final) +1. `/datum/component/proc/_JoinParent` (private, final) * Tries to add the component to it's `parent`s `datum_components` list - * Properly handles duplicate situations based on the `dupe_mode` var 1. `/datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz) * If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments * Makes a component listen for the specified `signal` on it's `parent` datum. diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm index c54376d787..fcd4651459 100644 --- a/code/datums/components/_component.dm +++ b/code/datums/components/_component.dm @@ -6,54 +6,16 @@ var/datum/parent /datum/component/New(datum/P, ...) - if(type == /datum/component) - qdel(src) - CRASH("[type] instantiated!") - - //check for common mishaps - if(!isnum(dupe_mode)) - qdel(src) - CRASH("[type]: Invalid dupe_mode!") - var/dt = dupe_type - if(dt && !ispath(dt)) - qdel(src) - CRASH("[type]: Invalid dupe_type!") - parent = P var/list/arguments = args.Copy(2) if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE) qdel(src, TRUE, TRUE) return - _CheckDupesAndJoinParent(P) + _JoinParent(P) -/datum/component/proc/_CheckDupesAndJoinParent() +/datum/component/proc/_JoinParent() var/datum/P = parent - var/dm = dupe_mode - - var/datum/component/old - if(dm != COMPONENT_DUPE_ALLOWED) - var/dt = dupe_type - if(!dt) - old = P.GetExactComponent(type) - else - old = P.GetComponent(dt) - if(old) - //One or the other has to die - switch(dm) - if(COMPONENT_DUPE_UNIQUE) - old.InheritComponent(src, TRUE) - qdel(src, TRUE, TRUE) - return - if(COMPONENT_DUPE_HIGHLANDER) - InheritComponent(old, FALSE) - qdel(old, FALSE, TRUE) - - //provided we didn't eat someone - if(!old) - //let the others know - P.SendSignal(COMSIG_COMPONENT_ADDED, src) - //lazy init the parent's dc list var/list/dc = P.datum_components if(!dc) @@ -212,10 +174,59 @@ return list(.) /datum/proc/AddComponent(new_type, ...) - var/nt = new_type + var/datum/component/nt = new_type + var/dm = initial(nt.dupe_mode) + var/dt = initial(nt.dupe_type) + + var/datum/component/old_comp + var/datum/component/new_comp + + if(ispath(nt)) + if(nt == /datum/component) + CRASH("[nt] attempted instantiation!") + if(!isnum(dm)) + CRASH("[nt]: Invalid dupe_mode ([dm])!") + if(dt && !ispath(dt)) + CRASH("[nt]: Invalid dupe_type ([dt])!") + else + new_comp = nt + args[1] = src - var/datum/component/C = new nt(arglist(args)) - return QDELING(C) ? GetExactComponent(new_type) : C + + if(dm != COMPONENT_DUPE_ALLOWED) + if(!dt) + old_comp = GetExactComponent(nt) + else + old_comp = GetComponent(dt) + if(old_comp) + switch(dm) + if(COMPONENT_DUPE_UNIQUE) + if(!new_comp) + new_comp = new nt(arglist(args)) + if(!QDELETED(new_comp)) + old_comp.InheritComponent(new_comp, TRUE) + qdel(new_comp) + if(COMPONENT_DUPE_HIGHLANDER) + if(!new_comp) + new_comp = new nt(arglist(args)) + if(!QDELETED(new_comp)) + new_comp.InheritComponent(old_comp, FALSE) + qdel(old_comp) + if(COMPONENT_DUPE_UNIQUE_PASSARGS) + if(!new_comp) + var/list/arguments = args.Copy(2) + old_comp.InheritComponent(null, TRUE, arguments) + else + old_comp.InheritComponent(new_comp, TRUE) + else if(!new_comp) + new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal + else if(!new_comp) + new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal + + if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy + SendSignal(COMSIG_COMPONENT_ADDED, new_comp) + return new_comp + return old_comp /datum/proc/LoadComponent(component_type, ...) . = GetComponent(component_type) @@ -235,7 +246,8 @@ C._RemoveFromParent() helicopter.SendSignal(COMSIG_COMPONENT_REMOVING, C) C.parent = src - C._CheckDupesAndJoinParent() + if(C == AddComponent(C)) + C._JoinParent() /datum/proc/TransferComponents(datum/target) var/list/dc = datum_components diff --git a/code/datums/components/radioactive.dm b/code/datums/components/radioactive.dm index c149fd8492..fc0456ad10 100644 --- a/code/datums/components/radioactive.dm +++ b/code/datums/components/radioactive.dm @@ -4,7 +4,7 @@ #define RAD_AMOUNT_EXTREME 1000 /datum/component/radioactive - dupe_mode = COMPONENT_DUPE_UNIQUE + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS var/source @@ -47,13 +47,16 @@ if(strength <= RAD_BACKGROUND_RADIATION) return PROCESS_KILL -/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original) +/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, list/arguments) if(!i_am_original) return if(!hl3_release_date) // Permanently radioactive things don't get to grow stronger return - var/datum/component/radioactive/other = C - strength = max(strength, other.strength) + if(C) + var/datum/component/radioactive/other = C + strength = max(strength, other.strength) + else + strength = max(strength, arguments[1]) /datum/component/radioactive/proc/rad_examine(mob/user, atom/thing) var/atom/master = parent diff --git a/code/datums/components/thermite.dm b/code/datums/components/thermite.dm index f76178213d..11611cadfb 100644 --- a/code/datums/components/thermite.dm +++ b/code/datums/components/thermite.dm @@ -1,5 +1,5 @@ /datum/component/thermite - dupe_mode = COMPONENT_DUPE_UNIQUE + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS var/amount var/overlay @@ -46,10 +46,13 @@ master.cut_overlay(overlay) return ..() -/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original) +/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original, list/arguments) if(!i_am_original) return - amount += newC.amount + if(newC) + amount += newC.amount + else + amount += arguments[1] /datum/component/thermite/proc/thermite_melt(mob/user) var/turf/master = parent