From 4a687031c7b437e2f67e9dc59b4e307b5fa279c9 Mon Sep 17 00:00:00 2001 From: Gary Lafortune Date: Tue, 5 Apr 2022 18:46:45 -0500 Subject: [PATCH] Refactors how vocal_cords work, fixes say() bugs It's actually kinda complicated at this point, what the particular order of things should be within the say() verb. Before this change, vocal cords -- any vocal cords, even normal ones, could bypass: - Space making your voice not go as far - Items in your inventory that do things when you talk - Dying when you say something when very crit So this fixes that. Beyond that, this commit also ensures that succumbing from your final whisper happens consistently, regardless of how you speak, and that on_mob_say() is consistently called for inventory items. --- code/datums/saymode.dm | 9 +---- code/modules/mob/living/say.dm | 33 +++++++++++----- code/modules/surgery/organs/vocal_cords.dm | 44 +++++++++++----------- 3 files changed, 48 insertions(+), 38 deletions(-) diff --git a/code/datums/saymode.dm b/code/datums/saymode.dm index e25688723f3c..93e07df81ec1 100644 --- a/code/datums/saymode.dm +++ b/code/datums/saymode.dm @@ -77,13 +77,8 @@ mode = MODE_VOCALCORDS /datum/saymode/vocalcords/handle_message(mob/living/user, message, datum/language/language) - if(iscarbon(user)) - var/mob/living/carbon/C = user - var/obj/item/organ/vocal_cords/V = C.getorganslot(ORGAN_SLOT_VOICE) - if(V && V.can_speak_with()) - V.handle_speech(message) //message - V.speak_with(message) //action - return FALSE + return TRUE //Yogs -- This is handled in a refactored, special-snowflake way someplace else, + // because most of vocalcord code is to resolve commands, which must evade accent code /datum/saymode/binary //everything that uses .b (silicons, drones, blobbernauts/spores, swarmers) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index a1bf37d82892..ce8d53d79a58 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -176,7 +176,26 @@ GLOBAL_LIST_INIT(special_radio_keys, list( else src.log_talk(message, LOG_SAY, forced_by=forced) + //Yogs -- Moved the message_range calculation a bit earlier in the say steps, for.. reasons. + //No screams in space, unless you're next to someone. + var/turf/T = get_turf(src) + var/datum/gas_mixture/environment = T.return_air() + var/pressure = (environment)? environment.return_pressure() : 0 + if(pressure < SOUND_MINIMUM_PRESSURE) + message_range = 1 + //yogs end + message = treat_message(message) // unfortunately we still need this + if(istype(saymode,/datum/saymode/vocalcords)) // Yogs -- some hack to make sure that the message gets to Voice of God unscathed + if(iscarbon(src)) + var/mob/living/carbon/C = src + var/obj/item/organ/vocal_cords/V = C.getorganslot(ORGAN_SLOT_VOICE) + if(V) + if(V.does_modify_message()) + message = V.modify_message(message) + else if(V.does_say_message()) + V.say_message(message,message_range) + return on_say_success(message,message_range,succumbed, spans, language, message_mods) // Yogs end var/sigreturn = SEND_SIGNAL(src, COMSIG_MOB_SAY, args) if (sigreturn & COMPONENT_UPPERCASE_SPEECH) message = uppertext(message) @@ -210,27 +229,21 @@ GLOBAL_LIST_INIT(special_radio_keys, list( if(!message_mods[WHISPER_MODE]) message_mods[WHISPER_MODE] = MODE_WHISPER if(radio_return & NOPASS) - return 1 - - //No screams in space, unless you're next to someone. - var/turf/T = get_turf(src) - var/datum/gas_mixture/environment = T.return_air() - var/pressure = (environment)? environment.return_pressure() : 0 - if(pressure < SOUND_MINIMUM_PRESSURE) - message_range = 1 + return on_say_success(message,message_range,succumbed, spans, language, message_mods)//Yogs -- deferred things are good if(pressure < ONE_ATMOSPHERE*0.4) //Thin air, let's italicise the message spans |= SPAN_ITALICS send_speech(message, message_range, src, bubble_type, spans, language, message_mods) + + return on_say_success(message,message_range,succumbed, spans, language, message_mods)//Yogs +/mob/living/proc/on_say_success(message,message_range,succumbed, spans, language, message_mods) // A helper function of stuff that is deferred to when /mob/living/say() is done and has successfully said something. if(succumbed) succumb(1) to_chat(src, compose_message(src, language, message, , spans, message_mods)) - for(var/obj/item/I in contents) I.on_mob_say(src, message, message_range) - return 1 /mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list()) diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 45e0aac156c1..11d760b8f7d3 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -13,14 +13,17 @@ healing_factor = 0 var/list/spans = null -/obj/item/organ/vocal_cords/proc/can_speak_with() //if there is any limitation to speaking with these cords - return TRUE +/obj/item/organ/vocal_cords/proc/does_modify_message() // whether it should be allowed to modify what the player said + return FALSE + +/obj/item/organ/vocal_cords/proc/does_say_message() // whether the vocal cords wish to ASSUME DIRECT CONTROL and speak for themselves + return FALSE -/obj/item/organ/vocal_cords/proc/speak_with(message) //do what the organ does +/obj/item/organ/vocal_cords/proc/modify_message(message) //Returns to /mob/living/say() the new message it ought to say, perhaps with some funky spans or something. return -/obj/item/organ/vocal_cords/proc/handle_speech(message) //actually say the message - owner.say(message, spans = spans, sanitize = FALSE) +/obj/item/organ/vocal_cords/proc/say_message(message,message_range) //Handles saying the message itself. Returns nothing. + return /obj/item/organ/adamantine_resonator name = "adamantine resonator" @@ -43,16 +46,20 @@ return owner.say(".x[message]") -/obj/item/organ/vocal_cords/adamantine/handle_speech(message) - var/msg = span_resonate("[span_name("[owner.real_name]")] [span_message("resonates, \"[message]\"")]") +/obj/item/organ/vocal_cords/adamantine/does_modify_message() + return TRUE + +/obj/item/organ/vocal_cords/adamantine/modify_message(message) + var/msg = span_resonate("[span_name(owner.real_name)] [span_message("resonates, \"[message]\"")]") for(var/m in GLOB.player_list) if(iscarbon(m)) var/mob/living/carbon/C = m if(C.getorganslot(ORGAN_SLOT_ADAMANTINE_RESONATOR)) to_chat(C, msg) - if(isobserver(m)) + else if(isobserver(m)) var/link = FOLLOW_LINK(m, owner) to_chat(m, "[link] [msg]") + return message // Kinda weird to do this, but uhhhh... yeah. //Colossus drop, forces the listeners to obey certain commands /obj/item/organ/vocal_cords/colossus @@ -100,30 +107,24 @@ return owner.say(".x[command]") -/obj/item/organ/vocal_cords/colossus/can_speak_with() +/obj/item/organ/vocal_cords/colossus/does_say_message() if(world.time < next_command) to_chat(owner, span_notice("You must wait [DisplayTimeText(next_command - world.time)] before Speaking again.")) return FALSE if(!owner) return FALSE - if(!owner.can_speak_vocal()) - to_chat(owner, span_warning("You are unable to speak!")) - return FALSE return TRUE -/obj/item/organ/vocal_cords/colossus/handle_speech(message) +/obj/item/organ/vocal_cords/colossus/say_message(message,message_range) playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 300, 1, 5) - return //voice of god speaks for us - -/obj/item/organ/vocal_cords/colossus/speak_with(message) - var/cooldown = voice_of_god(uppertext(message), owner, spans, base_multiplier) + var/cooldown = voice_of_god(uppertext(message), owner, spans, base_multiplier,FALSE,TRUE,TRUE,message_range) next_command = world.time + (cooldown * cooldown_mod) ////////////////////////////////////// ///////////VOICE OF GOD/////////////// ////////////////////////////////////// -/proc/voice_of_god(message, mob/living/user, list/span_list, base_multiplier = 1, include_speaker = FALSE, message_admins = TRUE, forced_span = FALSE) +/proc/voice_of_god(message, mob/living/user, list/span_list, base_multiplier = 1, include_speaker = FALSE, message_admins = TRUE, forced_span = FALSE, max_range = 8) var/cooldown = 0 if(!user || !user.can_speak(message) || user.stat) @@ -138,11 +139,11 @@ if(!span_list || !span_list.len) span_list = list() - user.say(message, spans = span_list, sanitize = FALSE) + if(!user.say(message, spans = span_list, sanitize = FALSE)) // If we failed to speak + return 0 - message = lowertext(message) var/list/mob/living/listeners = list() - for(var/mob/living/L in get_hearers_in_view(8, user)) + for(var/mob/living/L in get_hearers_in_view(max_range, user)) if(L.can_hear() && !L.anti_magic_check(FALSE, TRUE) && L.stat != DEAD) if(L == user && !include_speaker) continue @@ -180,6 +181,7 @@ var/found_string = null //Get the proper job titles + message = lowertext(message) message = get_full_job_name(message) for(var/V in listeners)