From f0251fefebc79f199331ee716d276d2ccfc17ccc Mon Sep 17 00:00:00 2001 From: Drathek <76988376+Drulikar@users.noreply.github.com> Date: Tue, 13 Feb 2024 05:32:02 -0800 Subject: [PATCH] Revive Lesser Drone and Facehugger temporary communication restrictions (#5688) # About the pull request This PR revives and expands #5352. By expand I mean that in addition to a 3 minute restriction for say and hivemind speak, custom emotes and pointing are also restricted during the 3 minute window. Past that I did some additional refactoring. # Explain why it's good for the game As a ghost role, this acts as a measure to mechanically limit the communication of meta info to other members in the hive. For now the restriction is only 3 minutes. # Testing Photographs and Procedure
Screenshots & Videos ![image](https://github.com/cmss13-devs/cmss13/assets/76988376/fd64c2f4-9142-4fe1-9953-b29c480c17ee)
# Changelog :cl: Zonespace Drathek balance: Lesser drones and Facehuggers cannot speak, custom emote, or point for 3 minutes after spawning /:cl: --------- Co-authored-by: John Doe --- .../signals/atom/mob/living/signals_xeno.dm | 4 + .../dcs/signals/atom/mob/signals_mob.dm | 6 ++ code/datums/components/temporary_mute.dm | 90 +++++++++++++++++++ code/modules/mob/emote.dm | 12 +-- .../carbon/xenomorph/castes/Facehugger.dm | 14 +++ .../carbon/xenomorph/castes/lesser_drone.dm | 14 +++ .../mob/living/carbon/xenomorph/say.dm | 3 + code/modules/mob/mob_verbs.dm | 31 ++++--- colonialmarines.dme | 1 + 9 files changed, 154 insertions(+), 21 deletions(-) create mode 100644 code/datums/components/temporary_mute.dm diff --git a/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm b/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm index 73b10d700247..e6e1e64e9c7e 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm @@ -74,3 +74,7 @@ /// From /mob/living/carbon/xenomorph/proc/handle_crit() #define COMSIG_XENO_ENTER_CRIT "xeno_entering_critical" + +/// From /mob/living/carbon/xenomorph/proc/hivemind_talk(): (message) +#define COMSIG_XENO_TRY_HIVEMIND_TALK "xeno_try_hivemind_talk" + #define COMPONENT_OVERRIDE_HIVEMIND_TALK (1<<0) diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm index 710e4d9ae20a..61eb757e9c4d 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm @@ -109,6 +109,12 @@ #define COMSIG_MOB_EMOTED(emote_key) "mob_emoted_[emote_key]" +#define COMSIG_MOB_TRY_EMOTE "mob_try_emote" + #define COMPONENT_OVERRIDE_EMOTE (1<<0) + +#define COMSIG_MOB_TRY_POINT "mob_try_point" + #define COMPONENT_OVERRIDE_POINT (1<<0) + //from /mob/living/set_stat() #define COMSIG_MOB_STAT_SET_ALIVE "mob_stat_set_alive" //from /mob/living/set_stat() diff --git a/code/datums/components/temporary_mute.dm b/code/datums/components/temporary_mute.dm new file mode 100644 index 000000000000..0fed49c4778e --- /dev/null +++ b/code/datums/components/temporary_mute.dm @@ -0,0 +1,90 @@ +/datum/component/temporary_mute + dupe_mode = COMPONENT_DUPE_UNIQUE + /// A message to tell the user when they attempt to speak, if any + var/on_speak_message = "" + /// A message to tell the user when they attempt to emote, if any + var/on_emote_message = "" + /// A message to tell the user when they become no longer mute, if any + var/on_unmute_message = "" + /// How long after the component's initialization it should be deleted. -1 means it will never delete + var/time_until_unmute = 3 MINUTES + +/datum/component/temporary_mute/Initialize(on_speak_message = "", on_emote_message = "", on_unmute_message = "", time_until_unmute = 3 MINUTES) + . = ..() + if(!ismob(parent)) + return COMPONENT_INCOMPATIBLE + + src.on_speak_message = on_speak_message + src.on_emote_message = on_emote_message + src.on_unmute_message = on_unmute_message + src.time_until_unmute = time_until_unmute + if(time_until_unmute != -1) + QDEL_IN(src, time_until_unmute) + +/datum/component/temporary_mute/RegisterWithParent() + ..() + RegisterSignal(parent, COMSIG_LIVING_SPEAK, PROC_REF(on_speak)) + RegisterSignal(parent, COMSIG_XENO_TRY_HIVEMIND_TALK, PROC_REF(on_hivemind)) + RegisterSignal(parent, COMSIG_MOB_TRY_EMOTE, PROC_REF(on_emote)) + RegisterSignal(parent, COMSIG_MOB_TRY_POINT, PROC_REF(on_point)) + +/datum/component/temporary_mute/UnregisterFromParent() + ..() + if(parent) + UnregisterSignal(parent, COMSIG_LIVING_SPEAK) + UnregisterSignal(parent, COMSIG_XENO_TRY_HIVEMIND_TALK) + UnregisterSignal(parent, COMSIG_MOB_TRY_EMOTE) + UnregisterSignal(parent, COMSIG_MOB_TRY_POINT) + if(on_unmute_message) + to_chat(parent, SPAN_NOTICE(on_unmute_message)) + +/datum/component/temporary_mute/proc/on_speak( + mob/user, + message, + datum/language/speaking = null, + verb = "says", + alt_name = "", + italics = FALSE, + message_range = GLOB.world_view_size, + sound/speech_sound, + sound_vol, + nolog = FALSE, + message_mode = null +) + SIGNAL_HANDLER + + if(!nolog) + log_say("[user.name != "Unknown" ? user.name : "([user.real_name])"] attempted to say the following before their spawn mute ended: [message] (CKEY: [user.key]) (JOB: [user.job])") + if(on_speak_message) + to_chat(parent, SPAN_BOLDNOTICE(on_speak_message)) + return COMPONENT_OVERRIDE_SPEAK + +/datum/component/temporary_mute/proc/on_hivemind(mob/user, message) + SIGNAL_HANDLER + + log_say("[user.name != "Unknown" ? user.name : "([user.real_name])"] attempted to hivemind the following before their spawn mute ended: [message] (CKEY: [user.key]) (JOB: [user.job])") + if(on_speak_message) + to_chat(parent, SPAN_BOLDNOTICE(on_speak_message)) + return COMPONENT_OVERRIDE_HIVEMIND_TALK + +/datum/component/temporary_mute/proc/on_emote(mob/user, datum/emote/current_emote, act, m_type, param, intentional) + SIGNAL_HANDLER + + // Allow involuntary emotes or non-custom emotes + if(!intentional) + return + if(!param && !istype(current_emote, /datum/emote/custom)) + return + + log_say("[user.name != "Unknown" ? user.name : "([user.real_name])"] attempted to emote the following before their spawn mute ended: [param] (CKEY: [user.key]) (JOB: [user.job])") + if(on_emote_message) + to_chat(parent, SPAN_BOLDNOTICE(on_emote_message)) + return COMPONENT_OVERRIDE_EMOTE + +/datum/component/temporary_mute/proc/on_point(mob/user, atom/target) + SIGNAL_HANDLER + + log_say("[user.name != "Unknown" ? user.name : "([user.real_name])"] attempted to point at the following before their spawn mute ended: [target] (CKEY: [user.key]) (JOB: [user.job])") + if(on_emote_message) + to_chat(parent, SPAN_BOLDNOTICE(on_emote_message)) + return COMPONENT_OVERRIDE_POINT diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index f1b600179450..fa7c7ec3176e 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -14,13 +14,15 @@ to_chat(src, SPAN_NOTICE("'[act]' emote does not exist. Say *help for a list.")) return FALSE var/silenced = FALSE - for(var/datum/emote/P in key_emotes) - if(!P.check_cooldown(src, intentional)) + for(var/datum/emote/current_emote in key_emotes) + if(!current_emote.check_cooldown(src, intentional)) silenced = TRUE continue - if(P.run_emote(src, param, m_type, intentional)) - SEND_SIGNAL(src, COMSIG_MOB_EMOTE, P, act, m_type, message, intentional) - SEND_SIGNAL(src, COMSIG_MOB_EMOTED(P.key)) + if(SEND_SIGNAL(src, COMSIG_MOB_TRY_EMOTE, current_emote, act, m_type, param, intentional) & COMPONENT_OVERRIDE_EMOTE) + silenced = TRUE + continue + if(current_emote.run_emote(src, param, m_type, intentional)) + SEND_SIGNAL(src, COMSIG_MOB_EMOTE, current_emote, act, m_type, message, intentional) return TRUE if(intentional && !silenced && !force_silence) to_chat(src, SPAN_NOTICE("Unusable emote '[act]'. Say *help for a list.")) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm index 7ce3a8750568..ab7b22b73d81 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm @@ -64,6 +64,20 @@ weed_food_states = list("Facehugger_1","Facehugger_2","Facehugger_3") weed_food_states_flipped = list("Facehugger_1","Facehugger_2","Facehugger_3") +/mob/living/carbon/xenomorph/facehugger/Login() + var/last_ckey_inhabited = persistent_ckey + . = ..() + if(ckey == last_ckey_inhabited) + return + + AddComponent(\ + /datum/component/temporary_mute,\ + "We aren't old enough to vocalize anything yet.",\ + "We aren't old enough to communicate like this yet.",\ + "We feel old enough to be able to vocalize and speak to the hivemind.",\ + 3 MINUTES,\ + ) + /mob/living/carbon/xenomorph/facehugger/initialize_pass_flags(datum/pass_flags_container/PF) ..() if (PF) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm b/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm index f050a0dcfe8a..5d3f4b38c8f8 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm @@ -83,6 +83,20 @@ weed_food_states = list("Lesser_Drone_1","Lesser_Drone_2","Lesser_Drone_3") weed_food_states_flipped = list("Lesser_Drone_1","Lesser_Drone_2","Lesser_Drone_3") +/mob/living/carbon/xenomorph/lesser_drone/Login() + var/last_ckey_inhabited = persistent_ckey + . = ..() + if(ckey == last_ckey_inhabited) + return + + AddComponent(\ + /datum/component/temporary_mute,\ + "We aren't old enough to vocalize anything yet.",\ + "We aren't old enough to communicate like this yet.",\ + "We feel old enough to be able to vocalize and speak to the hivemind.",\ + 3 MINUTES,\ + ) + /mob/living/carbon/xenomorph/lesser_drone/age_xeno() if(stat == DEAD || !caste || QDELETED(src) || !client) return diff --git a/code/modules/mob/living/carbon/xenomorph/say.dm b/code/modules/mob/living/carbon/xenomorph/say.dm index 5b8ce1ecd292..c40a50ce7523 100644 --- a/code/modules/mob/living/carbon/xenomorph/say.dm +++ b/code/modules/mob/living/carbon/xenomorph/say.dm @@ -98,6 +98,9 @@ to_chat(src, SPAN_WARNING("A headhunter temporarily cut off your psychic connection!")) return + if(SEND_SIGNAL(src, COMSIG_XENO_TRY_HIVEMIND_TALK, message) & COMPONENT_OVERRIDE_HIVEMIND_TALK) + return + hivemind_broadcast(message, hive) /mob/living/carbon/proc/hivemind_broadcast(message, datum/hive_status/hive) diff --git a/code/modules/mob/mob_verbs.dm b/code/modules/mob/mob_verbs.dm index 1ba8985d56bd..f12d00cc0988 100644 --- a/code/modules/mob/mob_verbs.dm +++ b/code/modules/mob/mob_verbs.dm @@ -50,34 +50,33 @@ to_chat(usr, SPAN_DANGER("This mob type cannot throw items.")) return -/mob/proc/point_to(atom/A in view()) +/mob/proc/point_to(atom/target in view()) //set name = "Point To" //set category = "Object" - if(!isturf(src.loc) || !(A in view(src)))//target is no longer visible to us - return 0 + if(!isturf(src.loc) || !(target in view(src)))//target is no longer visible to us + return FALSE - if(!A.mouse_opacity)//can't click it? can't point at it. - return 0 + if(!target.mouse_opacity)//can't click it? can't point at it. + return FALSE if(is_mob_incapacitated() || (status_flags & FAKEDEATH)) //incapacitated, can't point - return 0 + return FALSE - var/tile = get_turf(A) - if (!tile) - return 0 + var/tile = get_turf(target) + if(!tile) + return FALSE if(recently_pointed_to > world.time) - return 0 - - next_move = world.time + 2 - - point_to_atom(A, tile) - return 1 - + return FALSE + if(SEND_SIGNAL(src, COMSIG_MOB_TRY_POINT, target) & COMPONENT_OVERRIDE_POINT) + return FALSE + next_move = world.time + 2 + point_to_atom(target, tile) + return TRUE /mob/verb/memory() set name = "Notes" diff --git a/colonialmarines.dme b/colonialmarines.dme index 64760c4f2bc9..09370e73b4b1 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -406,6 +406,7 @@ #include "code\datums\components\overlay_lighting.dm" #include "code\datums\components\rename.dm" #include "code\datums\components\speed_modifier.dm" +#include "code\datums\components\temporary_mute.dm" #include "code\datums\components\toxin_buildup.dm" #include "code\datums\components\tutorial_status.dm" #include "code\datums\components\weed_damage_reduction.dm"