mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-09 07:46:20 +00:00
Recovered Crew are in spawner menu (#91986)
## About The Pull Request  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>
This commit is contained in:
@@ -337,5 +337,8 @@
|
||||
/// Index in modifiers containing the modifer to surgery speed
|
||||
#define SPEED_MOD_INDEX 2
|
||||
|
||||
/// From /datum/spawners_menu/ui_static_data(mob/user) : (list/string_info)
|
||||
#define COMSIG_LIVING_GHOSTROLE_INFO "living_ghostrole_info"
|
||||
|
||||
///from mob/living/befriend()
|
||||
#define COMSIG_LIVING_MADE_NEW_FRIEND "made_new_friend"
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
to_chat(src, span_warning("You cannot speak, your other self is controlling your body!"))
|
||||
return FALSE
|
||||
|
||||
/mob/living/split_personality/emote(act, m_type = null, message = null, intentional = FALSE, force_silence = FALSE)
|
||||
/mob/living/split_personality/emote(act, m_type = null, message = null, intentional = FALSE, force_silence = FALSE, forced = FALSE)
|
||||
return FALSE
|
||||
|
||||
///////////////BRAINWASHING////////////////////
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
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)
|
||||
. = ..()
|
||||
@@ -30,6 +32,9 @@
|
||||
/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))
|
||||
@@ -42,6 +47,8 @@
|
||||
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)
|
||||
@@ -110,6 +117,32 @@
|
||||
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))
|
||||
|
||||
@@ -120,5 +153,7 @@
|
||||
var/obj/item/organ/brain/brain = parent
|
||||
living = brain.owner
|
||||
living?.med_hud_set_status()
|
||||
if(living)
|
||||
remove_orbit_twitching(living)
|
||||
|
||||
. = ..()
|
||||
return ..()
|
||||
|
||||
50
code/datums/elements/orbit_twitcher.dm
Normal file
50
code/datums/elements/orbit_twitcher.dm
Normal file
@@ -0,0 +1,50 @@
|
||||
/datum/element/orbit_twitcher
|
||||
element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH_ON_HOST_DESTROY
|
||||
argument_hash_start_idx = 2
|
||||
/// Chance we have to twitch per second
|
||||
var/twitch_chance
|
||||
/// Those who are being orbited and should twitch
|
||||
var/list/twitchers = list()
|
||||
|
||||
/datum/element/orbit_twitcher/Attach(datum/target, twitch_chance)
|
||||
. = ..()
|
||||
if(!isliving(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
src.twitch_chance = twitch_chance
|
||||
|
||||
RegisterSignal(target, COMSIG_ATOM_ORBIT_BEGIN, PROC_REF(orbit_begin))
|
||||
RegisterSignal(target, COMSIG_ATOM_ORBIT_STOP, PROC_REF(orbit_stop))
|
||||
|
||||
/datum/element/orbit_twitcher/Detach(datum/source, ...)
|
||||
. = ..()
|
||||
|
||||
twitchers.Remove(source)
|
||||
UnregisterSignal(source, list(COMSIG_ATOM_ORBIT_BEGIN, COMSIG_ATOM_ORBIT_STOP))
|
||||
|
||||
/datum/element/orbit_twitcher/process(seconds_per_tick)
|
||||
for(var/mob/living/living as anything in twitchers)
|
||||
if(SPT_PROB(twitch_chance, seconds_per_tick))
|
||||
if(prob(60))
|
||||
living.emote("twitch_s", forced = TRUE)
|
||||
else
|
||||
living.emote("twitch", forced = TRUE)
|
||||
|
||||
/datum/element/orbit_twitcher/proc/orbit_begin(atom/source, atom/orbiter)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
twitchers.Add(source)
|
||||
// It checks if we're already processing so it's fine to always call
|
||||
START_PROCESSING(SSdcs, src)
|
||||
|
||||
/datum/element/orbit_twitcher/proc/orbit_stop(atom/source, atom/orbiter)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
twitchers.Remove(source)
|
||||
|
||||
if(!twitchers.len)
|
||||
STOP_PROCESSING(SSdcs, src)
|
||||
|
||||
/datum/element/orbit_twitcher/OnTargetDelete(datum/source)
|
||||
twitchers.Remove(source)
|
||||
return ..()
|
||||
@@ -51,7 +51,7 @@
|
||||
this["amount_left"] = 0
|
||||
for(var/mob/joinable_mob as anything in GLOB.joinable_mobs[mob_type])
|
||||
this["amount_left"] += 1
|
||||
if(!this["desc"])
|
||||
if(!SEND_SIGNAL(joinable_mob, COMSIG_LIVING_GHOSTROLE_INFO, this))
|
||||
this["desc"] = initial(joinable_mob.desc)
|
||||
if(this["amount_left"] > 0)
|
||||
data["spawners"] += list(this)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#define BEYBLADE_CONFUSION_LIMIT (40 SECONDS)
|
||||
|
||||
//The code execution of the emote datum is located at code/datums/emotes.dm
|
||||
/mob/proc/emote(act, m_type = null, message = null, intentional = FALSE, force_silence = FALSE)
|
||||
/mob/proc/emote(act, m_type = null, message = null, intentional = FALSE, force_silence = FALSE, forced = FALSE)
|
||||
var/param = message
|
||||
var/custom_param = findchar(act, " ")
|
||||
if(custom_param)
|
||||
@@ -31,7 +31,7 @@
|
||||
if(!emote.check_cooldown(src, intentional))
|
||||
silenced = TRUE
|
||||
continue
|
||||
if(!emote.can_run_emote(src, TRUE, intentional, param))
|
||||
if(!forced && !emote.can_run_emote(src, TRUE, intentional, param))
|
||||
continue
|
||||
if(SEND_SIGNAL(src, COMSIG_MOB_PRE_EMOTED, emote.key, param, m_type, intentional, emote) & COMPONENT_CANT_EMOTE)
|
||||
silenced = TRUE
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
z_move_flags |= ZMOVE_IGNORE_OBSTACLES //cameras do not respect these FLOORS you speak so much of
|
||||
return ..()
|
||||
|
||||
/mob/eye/emote(act, m_type=1, message = null, intentional = FALSE, force_silence = FALSE)
|
||||
/mob/eye/emote(act, m_type=1, message = null, intentional = FALSE, force_silence = FALSE, forced = FALSE)
|
||||
if(has_emotes)
|
||||
return ..()
|
||||
return FALSE
|
||||
|
||||
@@ -1720,6 +1720,7 @@
|
||||
#include "code\datums\elements\on_hit_effect.dm"
|
||||
#include "code\datums\elements\only_pull_living.dm"
|
||||
#include "code\datums\elements\openspace_item_click_handler.dm"
|
||||
#include "code\datums\elements\orbit_twitcher.dm"
|
||||
#include "code\datums\elements\ore_collecting.dm"
|
||||
#include "code\datums\elements\organ_set_bonus.dm"
|
||||
#include "code\datums\elements\permanent_fire_overlay.dm"
|
||||
|
||||
Reference in New Issue
Block a user