Files
Bubberstation/code/datums/components/ling_decoy_brain.dm
SkyratBot 2fa835185e [MIRROR] Changelings can now speak through their decoy brain if placed in an MMI [MDB IGNORE] (#23879)
* Changelings can now speak through their decoy brain if placed in an MMI (#78342)

## About The Pull Request

- If a changeling's decoy brain is placed in an MMI, they will now be
prompted to speak through it.
- They can speak through the decoy even if incapacitated or dead (or
fake-dead).

https://github.com/tgstation/tgstation/assets/51863163/804bd48a-c4b8-4feb-b021-019ea70e4b8e

## Why It's Good For The Game

The oft-controversial ling MMI test has been brought up time and time
again so I figure I throw my cards in for a solution.

We want as few ways as possible for people to hard and fast discover
whether someone is an antag, especially changling which is supposed to
revel in paranoia. This soft-patches out a big way, the MMI test, in
which you place a ling's brain in an MMI to determine if it's vestigial
and therefore, a ling.

Now the ling player can provide some benefit of the doubt by speaking
through the brain as normal, appearing active while actually in their
body still.

## Changelog

🆑 Melbert
add: Changelings can now speak through their decoy brain if it is placed
in an MMI, to maintain the illusion they are actually dead and have been
debrained.
/🆑

* Changelings can now speak through their decoy brain if placed in an MMI

---------

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
2023-09-24 07:00:24 -04:00

69 lines
2.8 KiB
Plaintext

/// Component applied to ling brains to make them into decoy brains, as ling brains are vestigial and don't do anything
/datum/component/ling_decoy_brain
/// The ling this brain is linked to
VAR_FINAL/datum/antagonist/changeling/parent_ling
/// A talk action that is granted to the ling when this decoy enters an MMI
VAR_FINAL/datum/action/changeling/mmi_talk/talk_action
/datum/component/ling_decoy_brain/Initialize(datum/antagonist/changeling/ling)
if(!istype(parent, /obj/item/organ/internal/brain))
return COMPONENT_INCOMPATIBLE
if(isnull(ling))
stack_trace("[type] instantiated without a changeling to link to.")
return COMPONENT_INCOMPATIBLE
parent_ling = ling
RegisterSignal(parent_ling, COMSIG_QDELETING, PROC_REF(clear_decoy))
/datum/component/ling_decoy_brain/Destroy()
UnregisterSignal(parent_ling, COMSIG_QDELETING)
parent_ling = null
QDEL_NULL(talk_action)
return ..()
/datum/component/ling_decoy_brain/RegisterWithParent()
var/obj/item/organ/internal/brain/ling_brain = parent
ling_brain.organ_flags &= ~ORGAN_VITAL
ling_brain.decoy_override = TRUE
RegisterSignal(ling_brain, COMSIG_ATOM_ENTERING, PROC_REF(entered_mmi))
/datum/component/ling_decoy_brain/UnregisterFromParent()
var/obj/item/organ/internal/brain/ling_brain = parent
ling_brain.organ_flags |= ORGAN_VITAL
ling_brain.decoy_override = FALSE
UnregisterSignal(ling_brain, COMSIG_ATOM_ENTERING, PROC_REF(entered_mmi))
/**
* Signal proc for [COMSIG_ATOM_ENTERING], when the brain enters an MMI grant the MMI talk action to the ling
*
* Unfortunately this is hooked on Entering rather than its own dedicated MMI signal becuase MMI code is a fuck
*/
/datum/component/ling_decoy_brain/proc/entered_mmi(obj/item/organ/internal/brain/source, atom/entering, atom/old_loc, ...)
SIGNAL_HANDLER
var/mob/living/the_real_ling = parent_ling.owner.current
if(!istype(the_real_ling))
return
if(istype(source.loc, /obj/item/mmi) && talk_action?.owner != the_real_ling)
if(isnull(talk_action))
talk_action = new() // Not linked to anything, we manage the reference (and don't want it disappearing on us)
talk_action.brain_ref = source
if(the_real_ling.key)
to_chat(the_real_ling, span_ghostalert("We detect our decoy brain has been placed within a Man-Machine Interface. \
We can use the \"MMI Talk\" action to command it to speak."))
else
the_real_ling.notify_ghost_cloning("Your decoy brain has been placed in an MMI, re-enter your body to talk via it!", source = the_real_ling, flashwindow = TRUE)
talk_action.Grant(the_real_ling)
else if(talk_action?.owner == the_real_ling)
to_chat(the_real_ling, span_ghostalert("We can no longer detect our decoy brain."))
talk_action.Remove(the_real_ling)
/// Clear up the decoy if the ling is de-linged
/datum/component/ling_decoy_brain/proc/clear_decoy(datum/source)
SIGNAL_HANDLER
qdel(src)