From f5be2c5020e246e4baefe45a2200ce9eca59b78c Mon Sep 17 00:00:00 2001 From: CHOMPStation2StaffMirrorBot <94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com> Date: Wed, 10 Dec 2025 07:25:33 -0700 Subject: [PATCH] [MIRROR] Countdown effect + couple of components (#12093) Co-authored-by: Guti <32563288+TheCaramelion@users.noreply.github.com> Co-authored-by: Cameron Lennox --- ...containers_ch.dm => connect_containers.dm} | 12 +-- code/datums/components/effect_remover.dm | 66 +++++++++++++ code/datums/elements/connect_loc.dm | 43 +++++++++ code/game/objects/effects/countdown.dm | 94 +++++++++++++++++++ vorestation.dme | 5 +- 5 files changed, 213 insertions(+), 7 deletions(-) rename code/datums/components/{connect_containers_ch.dm => connect_containers.dm} (84%) create mode 100644 code/datums/components/effect_remover.dm create mode 100644 code/datums/elements/connect_loc.dm create mode 100644 code/game/objects/effects/countdown.dm diff --git a/code/datums/components/connect_containers_ch.dm b/code/datums/components/connect_containers.dm similarity index 84% rename from code/datums/components/connect_containers_ch.dm rename to code/datums/components/connect_containers.dm index 22efc63435..e04656a0cc 100644 --- a/code/datums/components/connect_containers_ch.dm +++ b/code/datums/components/connect_containers.dm @@ -1,6 +1,6 @@ /// This component behaves similar to connect_loc_behalf, but it's nested and hooks a signal onto all MOVABLES containing this atom. /datum/component/connect_containers - dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + dupe_mode = COMPONENT_DUPE_SELECTIVE /// An assoc list of signal -> procpath to register to the loc this object is on. var/list/connections @@ -22,18 +22,18 @@ set_tracked(null) return ..() -/datum/component/connect_containers/InheritComponent(datum/component/component, original, atom/movable/tracked, list/connections) +/datum/component/connect_containers/CheckDupeComponent(datum/component/connect_containers/new_component, atom/movable/tracked, list/connections) // Not equivalent. Checks if they are not the same list via shallow comparison. if(!compare_list(src.connections, connections)) - stack_trace("connect_containers component attached to [parent] tried to inherit another connect_containers component with different connections") - return + return FALSE // Different set of connections. if(src.tracked != tracked) - set_tracked(tracked) + set_tracked(tracked) // Different target for the same set of connections, track the new target. + return TRUE // No new component. /datum/component/connect_containers/proc/set_tracked(atom/movable/new_tracked) if(tracked) UnregisterSignal(tracked, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING)) - unregister_signals(tracked.loc) + unregister_signals(tracked) tracked = new_tracked if(!tracked) return diff --git a/code/datums/components/effect_remover.dm b/code/datums/components/effect_remover.dm new file mode 100644 index 0000000000..9bfb6bc274 --- /dev/null +++ b/code/datums/components/effect_remover.dm @@ -0,0 +1,66 @@ +/datum/component/effect_remover + dupe_mode = COMPONENT_DUPE_ALLOWED + /// Line sent to the user on successful removal. + var/success_feedback + /// Line forcesaid by the user on successful removal. + var/success_forcesay + /// Callback invoked with removal is done. + var/datum/callback/on_clear_callback + /// A typecache of all effects we can clear with our item. + var/list/obj/effect/effects_we_clear + /// If above 0, how long it takes while standing still to remove the effect. + var/time_to_remove = 0 SECONDS + +/datum/component/effect_remover/Initialize(success_forcesay, success_feedback, on_clear_callback, effects_we_clear, time_to_remove) + . = ..() + + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + + if(!effects_we_clear) + stack_trace("[type] was instantiated without any valid removable effects!") + return COMPONENT_INCOMPATIBLE + + //src.success_feedback = success_feedback + //src.success_forcesay = success_forcesay + src.on_clear_callback = on_clear_callback + src.effects_we_clear = typecacheof(effects_we_clear) + src.time_to_remove = time_to_remove + +/datum/component/effect_remover/Destroy(force) + on_clear_callback = null + return ..() + +/datum/component/effect_remover/RegisterWithParent() + RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(try_remove_effect)) + +/datum/component/effect_remover/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_ITEM_PRE_ATTACK) + +/datum/component/effect_remover/proc/try_remove_effect(datum/source, atom/target, mob/living/user, params) + SIGNAL_HANDLER + + if(!isliving(user)) + return NONE + + if(is_type_in_typecache(target, effects_we_clear)) + do_remove_effects(target, user) + return + +/datum/component/effect_remover/proc/do_remove_effects(obj/effect/target, mob/living/user) +/* Grah- Might have to get this revised, later on. + if(time_to_remove && !do_after(user, time_to_remove, target)) + return + var/obj/item/item_parent = parent + if(success_forcesay) + user.say(success_forcesay) + if(success_feedback) + var/real_feedback = replacetext(success_feedback, "%THEEFFECT", "\the [target]") + real_feedback = replacetext(real_feedback, "%THEWEAPON", "\the [item_parent]") + user.balloon_alert() + to_chat(user, span_notice(real_feedback)) +*/ + on_clear_callback?.Invoke(target, user) + + if(!QDELETED(target)) + qdel(target) diff --git a/code/datums/elements/connect_loc.dm b/code/datums/elements/connect_loc.dm new file mode 100644 index 0000000000..2e34d1d37b --- /dev/null +++ b/code/datums/elements/connect_loc.dm @@ -0,0 +1,43 @@ +/// This element hooks a signal onto the loc the current object is on. +/// When the object moves, it will unhook the signal and rehook it to the new object. +/datum/element/connect_loc + element_flags = ELEMENT_BESPOKE|ELEMENT_NO_LIST_UNIT_TEST + argument_hash_start_idx = 2 + + /// An assoc list of signal -> procpath to register to the loc this object is on. + var/list/connections + +/datum/element/connect_loc/Attach(atom/movable/listener, list/connections) + . = ..() + if (!istype(listener)) + return ELEMENT_INCOMPATIBLE + + src.connections = connections + + RegisterSignal(listener, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved), override = TRUE) + update_signals(listener) + +/datum/element/connect_loc/Detach(atom/movable/listener) + . = ..() + unregister_signals(listener, listener.loc) + UnregisterSignal(listener, COMSIG_MOVABLE_MOVED) + +/datum/element/connect_loc/proc/update_signals(atom/movable/listener) + var/atom/listener_loc = listener.loc + if(QDELETED(listener) || QDELETED(listener_loc)) + return + + for (var/signal in connections) + //override=TRUE because more than one connect_loc element instance tracked object can be on the same loc + listener.RegisterSignal(listener_loc, signal, connections[signal], override=TRUE) + +/datum/element/connect_loc/proc/unregister_signals(datum/listener, atom/old_loc) + if(isnull(old_loc)) + return + + listener.UnregisterSignal(old_loc, connections) + +/datum/element/connect_loc/proc/on_moved(atom/movable/listener, atom/old_loc) + SIGNAL_HANDLER + unregister_signals(listener, old_loc) + update_signals(listener) diff --git a/code/game/objects/effects/countdown.dm b/code/game/objects/effects/countdown.dm new file mode 100644 index 0000000000..25e5efd31e --- /dev/null +++ b/code/game/objects/effects/countdown.dm @@ -0,0 +1,94 @@ +/obj/effect/countdown + name = "countdown" + desc = "We're leaving together\n\ + But still it's farewell\n\ + And maybe we'll come back\n\ + To Earth, who can tell?" + + invisibility = INVISIBILITY_OBSERVER + anchored = TRUE + plane = PLANE_GHOSTS + color = "#ff0000" + var/text_size = 3 + var/started = FALSE + var/displayed_text + var/atom/attached_to + +/obj/effect/countdown/Initialize(mapload) + . = ..() + attach(loc) + +/obj/effect/countdown/examine(mob/user) + . = ..() + . += "This countdown is displaying: [displayed_text]." + +/obj/effect/countdown/proc/attach(atom/A) + attached_to = A + var/turf/loc_turf = get_turf(A) + if(!loc_turf) + RegisterSignal(attached_to, COMSIG_MOVABLE_MOVED, PROC_REF(retry_attach), TRUE) + else + forceMove(loc_turf) + +/obj/effect/countdown/proc/retry_attach() + SIGNAL_HANDLER + + var/turf/loc_turf = get_turf(attached_to) + if(!loc_turf) + return + forceMove(loc_turf) + UnregisterSignal(attached_to, COMSIG_MOVABLE_MOVED) + +/obj/effect/countdown/proc/start() + if(!started) + START_PROCESSING(SSfastprocess, src) + started = TRUE + +/obj/effect/countdown/proc/stop() + if(started) + maptext = null + STOP_PROCESSING(SSfastprocess, src) + started = FALSE + +/obj/effect/countdown/proc/get_value() + // Get the value from our atom + return + +/obj/effect/countdown/process() + if(!attached_to || QDELETED(attached_to)) + qdel(src) + forceMove(get_turf(attached_to)) + var/new_val = get_value() + if(new_val == displayed_text) + return + displayed_text = new_val + + if(displayed_text) + maptext = MAPTEXT("[displayed_text]") + else + maptext = null + +/obj/effect/countdown/Destroy() + attached_to = null + STOP_PROCESSING(SSfastprocess, src) + . = ..() + +/obj/effect/countdown/singularity_pull(atom/singularity, current_size) + return + +/obj/effect/countdown/singularity_act() + return +/* +/obj/effect/countdown/anomaly + name = "anomaly countdown" + +/obj/effect/countdown/anomaly/get_value() + var/obj/effect/anomaly/A = attached_to + if(!istype(A)) + return + else if(A.immortal) + stop() + else + var/time_left = max(0, (A.death_time - world.time)/10) + return round(time_left) +*/ diff --git a/vorestation.dme b/vorestation.dme index 6dd62de474..ceaa15a1d4 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -708,10 +708,11 @@ #include "code\datums\cinematics\malf_doomsday.dm" #include "code\datums\cinematics\nuke_cinematics.dm" #include "code\datums\components\_component.dm" -#include "code\datums\components\connect_containers_ch.dm" +#include "code\datums\components\connect_containers.dm" #include "code\datums\components\connect_loc_behalf.dm" #include "code\datums\components\connect_mob_behalf.dm" #include "code\datums\components\connect_range.dm" +#include "code\datums\components\effect_remover.dm" #include "code\datums\components\holographic_nature.dm" #include "code\datums\components\infective.dm" #include "code\datums\components\orbiter.dm" @@ -873,6 +874,7 @@ #include "code\datums\elements\cleaning.dm" #include "code\datums\elements\climbable.dm" #include "code\datums\elements\conflict_checking.dm" +#include "code\datums\elements\connect_loc.dm" #include "code\datums\elements\footstep.dm" #include "code\datums\elements\footstep_override.dm" #include "code\datums\elements\godmode.dm" @@ -1584,6 +1586,7 @@ #include "code\game\objects\effects\bump_teleporter.dm" #include "code\game\objects\effects\client_only_image.dm" #include "code\game\objects\effects\confetti_vr.dm" +#include "code\game\objects\effects\countdown.dm" #include "code\game\objects\effects\effect_system.dm" #include "code\game\objects\effects\effect_system_ch.dm" #include "code\game\objects\effects\explosion_particles.dm"