Files
Bubberstation/code/datums/components/ghostrole_on_revive.dm
Time-Green 05982ba29a Recovered Crew are in spawner menu (#91986)
## About The Pull Request

![image](https://github.com/user-attachments/assets/052ad4ae-45e0-4fd5-b59f-4c659adefee3)

Added recovered crew to the ghost role spawner menu. Clicking spawn will
make you orbit the recovered crew body.


https://github.com/user-attachments/assets/326856c4-e306-43fd-b7d6-a8d5554a0e81

Orbiting the body will make it twitch a little to indicate to
coroners/MD's/roboticists that you're ready to be revived.

## Why It's Good For The Game

Getting people to actually play the recovered crew is kinda hard on most
rounds :( . First on my list is to make the process more convenient for
everyone.

By adding it to the ghostrole spawner menu, ghosts can quickly see if
bodies are available if they wish to play as one. Making them twitch
when orbited makes it so the people reviving them don't have to revive
them every few minutes in the case someone wishes to join as them (they
still might, it does get more attention).

I think the twitching effect is the best natural indicator that someone
wishes to join without being too OOC. I can imagine doctors being a
little confused at first, but it should click pretty quickly.

I am not too concerned about it being used as a ghost communication
medium. The spectroscopic sniffers are a more convenient tool for this,
and I don't think I've seen someone do it with them.
## Changelog
🆑
add: Recovered Crew have been added to the ghostrole spawner menu
add: Orbiting Recovered Crew corpses will make them twitch to indicate a
soul is available
/🆑
Giving them straight up superpowers or more aggressive antag rolls is
still something I'm considering. We'll see if/when I decide to do it

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
2025-07-27 12:41:29 +02:00

160 lines
5.5 KiB
Plaintext

/// Proc ghosts to enter the body when it get's revived
/datum/component/ghostrole_on_revive
/// If revived and no ghosts, just die again?
var/refuse_revival_if_failed
/// Callback for when the mob is revived and has their body occupied by a ghost
var/datum/callback/on_successful_revive
/// The chance to twitch when orbiting the spawn
var/twitch_chance = 30
/datum/component/ghostrole_on_revive/Initialize(refuse_revival_if_failed, on_successful_revive)
. = ..()
src.refuse_revival_if_failed = refuse_revival_if_failed
src.on_successful_revive = on_successful_revive
ADD_TRAIT(parent, TRAIT_GHOSTROLE_ON_REVIVE, REF(src)) //for adding an alternate examination
if(ismob(parent))
prepare_mob(parent)
return
if(!istype(parent, /obj/item/organ/brain))
return COMPONENT_INCOMPATIBLE
var/obj/item/organ/brain/brein = parent
if(brein.owner)
prepare_mob(brein.owner)
else
prepare_brain(brein)
/// Give the appropriate signals, and watch for organ removal
/datum/component/ghostrole_on_revive/proc/prepare_mob(mob/living/liver)
RegisterSignal(liver, COMSIG_LIVING_REVIVE, PROC_REF(on_revive))
ADD_TRAIT(liver, TRAIT_GHOSTROLE_ON_REVIVE, REF(src))
add_orbit_twitching(liver)
liver.med_hud_set_status()
if(iscarbon(liver))
var/mob/living/carbon/carbon = liver
var/obj/item/organ/brain = carbon.get_organ_by_type(/obj/item/organ/brain)
if(brain)
RegisterSignal(brain, COMSIG_ORGAN_REMOVED, PROC_REF(on_remove))
/datum/component/ghostrole_on_revive/proc/on_remove(obj/item/organ/brain, mob/living/old_owner)
SIGNAL_HANDLER
REMOVE_TRAIT(old_owner, TRAIT_GHOSTROLE_ON_REVIVE, REF(src))
remove_orbit_twitching(old_owner)
// we might have some lingering blinking eyes
var/obj/item/bodypart/head/head = old_owner?.get_bodypart(BODY_ZONE_HEAD)
if(head)
var/soul_eyes = locate(/datum/bodypart_overlay/simple/soul_pending_eyes) in head.bodypart_overlays
if(soul_eyes)
head.remove_bodypart_overlay(soul_eyes)
prepare_brain(brain)
/datum/component/ghostrole_on_revive/proc/prepare_brain(obj/item/organ/brein)
SIGNAL_HANDLER
RegisterSignal(brein, COMSIG_ORGAN_IMPLANTED, PROC_REF(prepare_mob_from_brain))
UnregisterSignal(brein, COMSIG_ORGAN_REMOVED)
/datum/component/ghostrole_on_revive/proc/prepare_mob_from_brain(obj/item/organ/brain/brein, mob/living/owner)
SIGNAL_HANDLER
UnregisterSignal(brein, COMSIG_ORGAN_IMPLANTED)
prepare_mob(owner)
/datum/component/ghostrole_on_revive/proc/on_revive(mob/living/aliver)
SIGNAL_HANDLER
INVOKE_ASYNC(src, PROC_REF(poll_ghosts), aliver)
/datum/component/ghostrole_on_revive/proc/poll_ghosts(mob/living/aliver)
var/soul_eyes
var/obj/item/bodypart/head
// adds soulful SOUL PENDING eyes to indicate what's happening to observers
var/mob/living/carbon/human/hewmon
if(ishuman(aliver))
hewmon = aliver
head = hewmon.get_bodypart(BODY_ZONE_HEAD)
if(head)
soul_eyes = new /datum/bodypart_overlay/simple/soul_pending_eyes()
head.add_bodypart_overlay(soul_eyes)
// So during the potentially short period of time we're revived, we don't metabolize formaldehyde
// Really just a QOL for coroners, so we dont suddenly start decaying
ADD_TRAIT(aliver, TRAIT_BLOCK_FORMALDEHYDE_METABOLISM, type)
var/mob/dead/observer/chosen_one = SSpolling.poll_ghosts_for_target(
question = "Would you like to play as a recovered crewmember?",
role = null,
check_jobban = ROLE_RECOVERED_CREW,
poll_time = 15 SECONDS,
checked_target = aliver,
ignore_category = POLL_IGNORE_RECOVERED_CREW,
alert_pic = aliver,
role_name_text = "recovered crew",
)
REMOVE_TRAIT(aliver, TRAIT_BLOCK_FORMALDEHYDE_METABOLISM, type)
if(head)
head.remove_bodypart_overlay(soul_eyes)
if(!isobserver(chosen_one))
if(refuse_revival_if_failed)
aliver.death()
aliver.visible_message(span_deadsay("[aliver.name]'s soul is struggling to return!"))
else
aliver.PossessByPlayer(chosen_one.ckey)
on_successful_revive?.Invoke(aliver)
qdel(src)
/datum/component/ghostrole_on_revive/proc/add_orbit_twitching(mob/living/liver)
liver.AddElement(/datum/element/orbit_twitcher, twitch_chance)
// Add it to the ghostrole spawner menu. Note that we can't directly spawn from it, but we can make it twitch to alert bystanders to defib it
LAZYADD(GLOB.joinable_mobs[format_text("Recovered Crew")], liver)
RegisterSignal(liver, COMSIG_LIVING_GHOSTROLE_INFO, PROC_REF(set_spawner_info))
/datum/component/ghostrole_on_revive/proc/set_spawner_info(datum/spawners_menu/menu, string_info)
SIGNAL_HANDLER
string_info["you_are_text"] = "You are a long dead crewmember, but are soon to be revived to rejoin the crew!"
string_info["flavor_text"] = "Get a job and get back to work!"
string_info["important_text"] = "Do your best to help the station. You still roll for midround antagonists."
/datum/component/ghostrole_on_revive/proc/remove_orbit_twitching(mob/living/living)
living.RemoveElement(/datum/element/orbit_twitcher, twitch_chance)
// Remove from the ghostrole spawning menu
var/list/spawners = GLOB.joinable_mobs[format_text("Recovered Crew")]
LAZYREMOVE(spawners, living)
if(!LAZYLEN(spawners))
GLOB.joinable_mobs -= format_text("Recovered Crew")
UnregisterSignal(living, COMSIG_LIVING_GHOSTROLE_INFO)
/datum/component/ghostrole_on_revive/Destroy(force)
REMOVE_TRAIT(parent, TRAIT_GHOSTROLE_ON_REVIVE, REF(src))
var/mob/living/living
if(isliving(parent))
living = parent
else if(istype(parent, /obj/item/organ/brain))
var/obj/item/organ/brain/brain = parent
living = brain.owner
living?.med_hud_set_status()
if(living)
remove_orbit_twitching(living)
return ..()