Files
Bubberstation/code/datums/components/temporary_body.dm
Y0SH1M4S73R 25eb08420a Temporary bodies return players to minds without bodies (#89323)
## About The Pull Request

There are a couple of cases where ghost roles that give the temporary
body component prevent you from returning to the round when they really
shouldn't. The particular cases are:
- You entered a temporary body while you had no body, but could be
recovered via means such as podcloning
- You enter a temporary body, and while in that body, your original body
is permanently removed while your mind could be recovered via means such
as podcloning
- Basketball

This PR addresses those cases by allowing the temporary body component
to operate with a null `old_body`, and allowing the temporary body
component to be given to ghosts whose minds don't have bodies.


## Why It's Good For The Game

Erroneous DNRs caused by code oversights are probably very undesirable
to the playerbase.

## Changelog

🆑
fix: Joining a minigame or taking certain ghost roles, while you have a
mind without a body, will no longer DNR you, just in case you can be
resurrected by some means.
fix: If your old body is permanently destroyed while you are playing a
minigame or as certain ghost roles, you will still return to your
character's original mind, just in case you can be resurrected by some
means.
fix: The basketball minigame now gives its players and referee temporary
bodies.
/🆑
2025-02-05 20:01:42 +01:00

64 lines
2.1 KiB
Plaintext

/**
* ##temporary_body
*
* Used on living mobs when they are meant to be a 'temporary body'
* Holds a reference to an old mind & body, to put them back in
* once the body this component is attached to, is being deleted.
*/
/datum/component/temporary_body
///The old mind we will be put back into when parent is being deleted.
var/datum/weakref/old_mind_ref
///The old body we will be put back into when parent is being deleted.
var/datum/weakref/old_body_ref
/// Returns the mind if the parent dies by any means
var/delete_on_death = FALSE
/datum/component/temporary_body/Initialize(datum/mind/old_mind, mob/living/old_body, delete_on_death = FALSE)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
src.old_mind_ref = WEAKREF(old_mind)
if(istype(old_body))
ADD_TRAIT(old_body, TRAIT_MIND_TEMPORARILY_GONE, REF(src))
src.old_body_ref = WEAKREF(old_body)
src.delete_on_death = delete_on_death
/datum/component/temporary_body/RegisterWithParent()
RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(on_parent_destroy))
if(delete_on_death)
RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(on_parent_destroy))
/datum/component/temporary_body/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_QDELETING)
/**
* Sends the mind of the temporary body back into their previous host
* If the previous host is alive, we'll force them into the body.
* Otherwise we'll let them hang out as a ghost still.
*/
/datum/component/temporary_body/proc/on_parent_destroy()
SIGNAL_HANDLER
var/datum/mind/old_mind = old_mind_ref?.resolve()
var/mob/living/old_body = old_body_ref?.resolve() || old_mind.current
if(!old_mind)
return
var/mob/living/living_parent = parent
var/mob/dead/observer/ghost = living_parent.ghostize()
if(!ghost)
ghost = living_parent.get_ghost()
if(!ghost)
CRASH("[src] belonging to [parent] was completely unable to find a ghost to put back into a body!")
ghost.mind = old_mind
if(old_body?.stat != DEAD)
old_mind.transfer_to(old_body, force_key_move = TRUE)
else
old_mind.set_current(old_body)
if(old_body)
REMOVE_TRAIT(old_body, TRAIT_MIND_TEMPORARILY_GONE, REF(src))
old_mind = null
old_body = null