Files
Bubberstation/code/datums/components/effect_remover.dm
Rhials 4e1b14fd98 Hallucinatory Anomalies now produce hallucinatory decoys of itself, and hit a wider area (#86086)
## About The Pull Request

This "buffs" the hallucinatory anomaly by giving it a bit more impact
and flair. This affects both the detonate effect and what happens when
one initially spawns.

When a hallucinatory anomaly spawns, it will spawn surrounded by "decoy"
hallucination anomalies -- Illusions meant to distract you from the real
one. The idea is that these are not actually there, and that they are
the result of reality getting muddy in proximity to the anomaly.
Scanning one of these will provide a message, either of nothing
happening or a minor hallucination as your character suffers from the
real anomaly's effects.

Using an anomaly neutralizer on a decoy will do nothing. There's nothing
to neutralize, because nothing is there. You're losing your grip on
reality.

Now, the detonate effect will affect people at a wider radius, through
walls. This is done with a second helper different from
`visible_hallucination_pulse()`, which does affect the blind and ignores
walls, `hallucination_pulse()`.
## Why It's Good For The Game

Hallucinatory anomalies are easily the most underwhelming and
understated anomaly in the group. They have the impact of a dry fart on
a round, rarely affecting anyone and vanishing without anyone noticing
or caring.

It makes little sense for the detonate effect to impact only those who
can see it. Anyone with a pulse can make the connection between the
"hallucination anomaly" vanishing and Bubblegum bodyslamming them less
than a second later. By affecting those out of sight, in a wider range,
there's a higher chance the detonation will not only catch people off
guard, but lead to more chaos on comms.

As for the illusory decoy anomalies, it was just a neat idea I had to
differentiate how people typically deal with them. It makes for a more
trippy experience for whoever has to deal with them, and adds confusion
(which is the whole shtick with hallucinations -- confusion).

So, overall, more snazziness and personality, and more of an impact when
left alone.
## Changelog
🆑 Rhials
balance: Hallucinatory anomalies now have a wider range, and will spawn
hallucinatory decoys of itself to mislead you.
/🆑

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
2024-09-08 03:41:28 +00:00

109 lines
3.6 KiB
Plaintext

/*
* Simple component for something that is able to destroy
* certain effects (such as cult runes) in one attack.
*/
/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
/// The text used in the screentip when our parent is hovering over an item we can clear. Ex "Destroy rune"
var/tip_text
/// 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,
tip_text,
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.tip_text = tip_text
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_INTERACTING_WITH_ATOM, PROC_REF(try_remove_effect))
if(tip_text)
var/obj/item/item_parent = parent
item_parent.item_flags |= ITEM_HAS_CONTEXTUAL_SCREENTIPS
RegisterSignal(parent, COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET, PROC_REF(add_item_context))
/datum/component/effect_remover/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ITEM_INTERACTING_WITH_ATOM, COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET))
/*
* Signal proc for [COMSIG_ITEM_INTERACTING_WITH_ATOM].
*/
/datum/component/effect_remover/proc/try_remove_effect(datum/source, mob/living/user, atom/target, params)
SIGNAL_HANDLER
if(!isliving(user))
return NONE
if(HAS_TRAIT(target, TRAIT_ILLUSORY_EFFECT))
to_chat(user, span_notice("You pass [parent] through the [target], but nothing seems to happen. Is it really even there?"))
return NONE
if(is_type_in_typecache(target, effects_we_clear)) // Make sure we get all subtypes and everything
INVOKE_ASYNC(src, PROC_REF(do_remove_effect), target, user)
return ITEM_INTERACT_SUCCESS
/*
* Actually removes the effect, invoking our on_clear_callback before it's deleted.
*/
/datum/component/effect_remover/proc/do_remove_effect(obj/effect/target, mob/living/user)
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, forced = item_parent.name)
if(success_feedback)
var/real_feedback = replacetext(success_feedback, "%THEEFFECT", "\the [target]")
real_feedback = replacetext(real_feedback, "%THEWEAPON", "\the [item_parent]")
to_chat(user, span_notice(real_feedback))
on_clear_callback?.Invoke(target, user)
if(!QDELETED(target))
qdel(target)
/*
* Signal proc for [COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET].
*
* Adds some context for the target, if we have one set and it's a valid target.
*/
/datum/component/effect_remover/proc/add_item_context(obj/item/source, list/context, atom/target, mob/living/user)
SIGNAL_HANDLER
if(effects_we_clear[target.type])
context[SCREENTIP_CONTEXT_LMB] = tip_text
return CONTEXTUAL_SCREENTIP_SET
return NONE