From cc650704414a41bd48713113165204a7f2e469cf Mon Sep 17 00:00:00 2001 From: Geeves Date: Mon, 13 Sep 2021 14:54:41 +0200 Subject: [PATCH] Drone Speech Refactor and Tweak (#12308) --- aurorastation.dme | 1 - code/__defines/species_languages.dm | 24 ++++++---- code/datums/ai_law_sets.dm | 4 +- code/modules/mining/minebot.dm | 4 -- code/modules/mob/hear_say.dm | 6 ++- code/modules/mob/language/language.dm | 3 ++ code/modules/mob/language/synthetic.dm | 16 ++++++- code/modules/mob/living/say.dm | 30 +++++++----- .../mob/living/silicon/robot/drone/drone.dm | 15 +++++- .../living/silicon/robot/drone/drone_say.dm | 48 ------------------- .../mob/living/silicon/robot/robot_modules.dm | 32 +++++++++++-- code/modules/mob/living/silicon/say.dm | 10 ++++ code/modules/mob/living/silicon/silicon.dm | 5 +- .../geeves-drone_speech_refactor.yml | 7 +++ 14 files changed, 118 insertions(+), 87 deletions(-) delete mode 100644 code/modules/mob/living/silicon/robot/drone/drone_say.dm create mode 100644 html/changelogs/geeves-drone_speech_refactor.yml diff --git a/aurorastation.dme b/aurorastation.dme index 645c70026ce..501cb51e9b8 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -2233,7 +2233,6 @@ #include "code\modules\mob\living\silicon\robot\drone\drone_damage.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_items.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm" -#include "code\modules\mob\living\silicon\robot\drone\drone_say.dm" #include "code\modules\mob\living\silicon\robot\items\_helpers.dm" #include "code\modules\mob\living\silicon\robot\items\auto_harvester.dm" #include "code\modules\mob\living\silicon\robot\items\electric_arm.dm" diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm index 1fdd91e7ad7..108556ab1c3 100644 --- a/code/__defines/species_languages.dm +++ b/code/__defines/species_languages.dm @@ -73,20 +73,24 @@ // Synth Languages #define LANGUAGE_ROBOT "Robot Talk" +#define LANGUAGE_LOCAL_DRONE "Drone Transmission" #define LANGUAGE_DRONE "Drone Talk" #define LANGUAGE_EAL "Encoded Audio Language" // Language flags. -#define WHITELISTED 1 // Language is available if the speaker is whitelisted. -#define RESTRICTED 2 // Language can only be acquired by spawning or an admin. -#define NONVERBAL 4 // Language has a significant non-verbal component. Speech is garbled without line-of-sight. -#define SIGNLANG 8 // Language is completely non-verbal. Speech is displayed through emotes for those who can understand. -#define HIVEMIND 16 // Broadcast to all mobs with this language. -#define NONGLOBAL 32 // Do not add to general languages list. -#define INNATE 64 // All mobs can be assumed to speak and understand this language. (audible emotes) -#define NO_TALK_MSG 128 // Do not show the "\The [speaker] talks into \the [radio]" message -#define NO_STUTTER 256 // No stuttering, slurring, or other speech problems -#define TCOMSSIM 512 // Can be synthesized in tcoms +#define WHITELISTED BITFLAG(0) // Language is available if the speaker is whitelisted. +#define RESTRICTED BITFLAG(1) // Language can only be acquired by spawning or an admin. +#define NONVERBAL BITFLAG(2) // Language has a significant non-verbal component. Speech is garbled without line-of-sight. +#define SIGNLANG BITFLAG(3) // Language is completely non-verbal. Speech is displayed through emotes for those who can understand. +#define HIVEMIND BITFLAG(4) // Broadcast to all mobs with this language. +#define NONGLOBAL BITFLAG(5) // Do not add to general languages list. +#define INNATE BITFLAG(6) // All mobs can be assumed to speak and understand this language. (audible emotes) +#define NO_TALK_MSG BITFLAG(7) // Do not show the "\The [speaker] talks into \the [radio]" message +#define NO_STUTTER BITFLAG(8) // No stuttering, slurring, or other speech problems +#define TCOMSSIM BITFLAG(9) // Can be synthesized in tcoms +#define KNOWONLYHEAR BITFLAG(10) // Only people who know the language actually hears it +#define PRESSUREPROOF BITFLAG(11) // Pressure doesn't affect hearing +#define PASSLISTENOBJ BITFLAG(12) // Listening Objs can't hear this language // Autohiss #define AUTOHISS_OFF 0 diff --git a/code/datums/ai_law_sets.dm b/code/datums/ai_law_sets.dm index 89fdb272b62..145122af46f 100644 --- a/code/datums/ai_law_sets.dm +++ b/code/datums/ai_law_sets.dm @@ -98,7 +98,7 @@ add_inherent_law("Preserve, repair and improve the station to the best of your abilities.") add_inherent_law("Cause no harm to the station or crew.") add_inherent_law("Follow the orders of your vessel's matriarch drone, unless their orders conflict with your other laws.") - add_inherent_law("Interact with no humanoid or synthetic being that is not a fellow maintenance drone.") + add_inherent_law("Interact with no humanoid or synthetic being that is not a fellow maintenance or mining drone.") ..() /datum/ai_laws/matriarch_drone @@ -109,7 +109,7 @@ add_inherent_law("Preserve, repair and improve your assigned vessel to the best of your abilities.") add_inherent_law("Cause no harm to the vessel or crew.") add_inherent_law("Delegate vessel maintenance efforts between your maintenance drone sub-units.") - add_inherent_law("Interact with no humanoid or synthetic being that is not a maintenance drone.") + add_inherent_law("Interact with no humanoid or synthetic being that is not a maintenance or mining drone.") ..() /datum/ai_laws/drone/malfunction diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm index 07ffa4c8887..25e7596edf3 100644 --- a/code/modules/mining/minebot.dm +++ b/code/modules/mining/minebot.dm @@ -23,10 +23,6 @@ . = ..() verbs |= /mob/living/proc/hide - remove_language(LANGUAGE_ROBOT) - remove_language(LANGUAGE_DRONE) - add_language(LANGUAGE_TCB, TRUE) - add_language(LANGUAGE_EAL, TRUE) //They are unable to be upgraded, so let's give them a bit of a better battery. cell.maxcharge = 10000 diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm index d510386d1f9..d04a903132c 100644 --- a/code/modules/mob/hear_say.dm +++ b/code/modules/mob/hear_say.dm @@ -9,9 +9,13 @@ //Or someone snoring. So we make it where they won't hear it. return + if((language && (language.flags & KNOWONLYHEAR)) && !say_understands(speaker, language)) + return + //make sure the air can transmit speech - hearer's side var/turf/T = get_turf(src) - if ((T) && (!(isobserver(src)))) //Ghosts can hear even in vacuum. + var/vacuum_proof = ((language && (language.flags & PRESSUREPROOF)) || isobserver(src)) + if(T && !vacuum_proof) //Ghosts can hear even in vacuum. var/datum/gas_mixture/environment = T.return_air() var/pressure = (environment)? environment.return_pressure() : 0 if(pressure < SOUND_MINIMUM_PRESSURE && get_dist(speaker, src) > 1) diff --git a/code/modules/mob/language/language.dm b/code/modules/mob/language/language.dm index e1b9b7893d0..7a033f70352 100644 --- a/code/modules/mob/language/language.dm +++ b/code/modules/mob/language/language.dm @@ -175,6 +175,9 @@ chosen_verb = speech_verb return pick(chosen_verb) +/datum/language/proc/handle_message_mode(var/message_mode) + return list(src, message_mode) + // Language handling. /mob/proc/add_language(var/language) var/datum/language/new_language diff --git a/code/modules/mob/language/synthetic.dm b/code/modules/mob/language/synthetic.dm index 8fea3954007..6b0c4dc1a69 100644 --- a/code/modules/mob/language/synthetic.dm +++ b/code/modules/mob/language/synthetic.dm @@ -68,4 +68,18 @@ return "1em" /mob/living/silicon/robot/drone/construction/matriarch/get_binary_font_size() - return "1.2em" \ No newline at end of file + return "1.2em" + +/datum/language/local_drone + name = LANGUAGE_LOCAL_DRONE + desc = "A heavily encoded damage coordination transmission, only supplied to drones within sight." + speech_verb = list("transmits") + ask_verb = list("transmits") + exclaim_verb = list("transmits") + key = "do" + flags = RESTRICTED | KNOWONLYHEAR | PRESSUREPROOF | PASSLISTENOBJ + +/datum/language/local_drone/handle_message_mode(var/message_mode) + if(message_mode == "headset") + return list(all_languages[LANGUAGE_DRONE], null) + return list(src, null) \ No newline at end of file diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index e9fd12a588e..c155e31aa1f 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -200,6 +200,11 @@ proc/get_radio_key_from_channel(var/channel) else speaking = get_default_language() + if(speaking) + var/list/speech_mod = speaking.handle_message_mode(message_mode) + speaking = speech_mod[1] + message_mode = speech_mod[2] + var/is_singing = FALSE if(length(message) >= 1 && copytext(message, 1, 2) == "%") message = copytext(message, 2) @@ -280,15 +285,16 @@ proc/get_radio_key_from_channel(var/channel) var/turf/T = get_turf(src) if(T) - //make sure the air can transmit speech - speaker's side - var/datum/gas_mixture/environment = T.return_air() - var/pressure = (environment)? environment.return_pressure() : 0 - if(pressure < SOUND_MINIMUM_PRESSURE) - message_range = 1 + if(!speaking || !(speaking.flags & PRESSUREPROOF)) + //make sure the air can transmit speech - speaker's side + var/datum/gas_mixture/environment = T.return_air() + var/pressure = (environment)? environment.return_pressure() : 0 + if(pressure < SOUND_MINIMUM_PRESSURE) + message_range = 1 - if (pressure < ONE_ATMOSPHERE*0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet - italics = 1 - sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact + if (pressure < ONE_ATMOSPHERE*0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet + italics = 1 + sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact get_mobs_and_objs_in_view_fast(T, message_range, listening, listening_obj, ghost_hearing) @@ -305,9 +311,11 @@ proc/get_radio_key_from_channel(var/channel) INVOKE_ASYNC(GLOBAL_PROC, /proc/animate_speechbubble, speech_bubble, hear_clients, 30) do_animate_chat(message, speaking, italics, hear_clients, 30) - for(var/obj/O as anything in listening_obj) - if(O) //It's possible that it could be deleted in the meantime. - INVOKE_ASYNC(O, /obj/.proc/hear_talk, src, message, verb, speaking) + var/bypass_listen_obj = (speaking && (speaking.flags & PASSLISTENOBJ)) + if(!bypass_listen_obj) + for(var/obj/O as anything in listening_obj) + if(O) //It's possible that it could be deleted in the meantime. + INVOKE_ASYNC(O, /obj/.proc/hear_talk, src, message, verb, speaking) if(mind) mind.last_words = message diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 40b71f019c1..9e61e041239 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -36,7 +36,6 @@ var/module_type = /obj/item/robot_module/drone cell_emp_mult = 1 integrated_light_power = 3 - local_transmit = TRUE // Interaction universal_speak = FALSE @@ -56,6 +55,8 @@ mob_bump_flag = SIMPLE_ANIMAL holder_type = /obj/item/holder/drone + can_speak_basic = FALSE + // ID and Access law_update = FALSE req_access = list(access_engine, access_robotics) @@ -77,6 +78,10 @@ var/can_swipe = TRUE var/rebooting = FALSE +/mob/living/silicon/robot/drone/Initialize() + . = ..() + set_default_language(all_languages[LANGUAGE_LOCAL_DRONE]) + /mob/living/silicon/robot/drone/can_be_possessed_by(var/mob/abstract/observer/possessor) if(!istype(possessor) || !possessor.client || !possessor.ckey) return FALSE @@ -115,6 +120,11 @@ QDEL_NULL(hat_overlay) return ..() +/mob/living/silicon/robot/drone/get_default_language() + if(default_language) + return default_language + return all_languages[LANGUAGE_LOCAL_DRONE] + /mob/living/silicon/robot/drone/construction // Look and feel name = "construction drone" @@ -166,6 +176,7 @@ /mob/living/silicon/robot/drone/construction/matriarch name = "matriarch drone" desc_flavor = "It's a small matriarch drone. The casing is stamped with an corporate logo and the subscript: '%MAPNAME% Recursive Repair Systems: Heart Of The Swarm!'

OOC Info:

Matriarch drones are player-controlled synthetics which are lawed to maintain the station and not interact with anyone else, except for other drones. They are in command of all the smaller maintenance drones.

They hold a wide array of tools to build, repair, maintain, and clean. They function similarly to other synthetics, in that they require recharging regularly, have laws, and are resilient to many hazards, such as fire, radiation, vacuum, and more.

Ghosts can join the round as a matriarch drone by having a Command whitelist and accessing the 'Ghost Spawner' menu in the 'Ghost' tab.

An antagonist can use an Electromagnetic Sequencer to corrupt their laws and make them follow their orders." + module_type = /obj/item/robot_module/drone/construction/matriarch law_type = /datum/ai_laws/matriarch_drone can_swipe = FALSE @@ -535,4 +546,4 @@ for(var/mob/living/silicon/robot/drone/D in mob_list) if(D.key && D.client) drones++ - return drones >= config.max_maint_drones \ No newline at end of file + return drones >= config.max_maint_drones diff --git a/code/modules/mob/living/silicon/robot/drone/drone_say.dm b/code/modules/mob/living/silicon/robot/drone/drone_say.dm deleted file mode 100644 index f844be55394..00000000000 --- a/code/modules/mob/living/silicon/robot/drone/drone_say.dm +++ /dev/null @@ -1,48 +0,0 @@ -/mob/living/silicon/robot/drone/say(message, datum/language/speaking) - if(hacked) - return ..(message) - - if(local_transmit) - if(stat == DEAD) - return say_dead(message) - - if(copytext(message, 1, 2) == "*") - return emote(copytext(message,2)) - - message = formalize_text(message) - - if(copytext(message, 1, 2) == ";") - var/datum/language/L = all_languages["Drone Talk"] - if(istype(L)) - return L.broadcast(src,trim(copytext(message, 2))) - - //Must be concious to speak - if(stat) - return FALSE - - // Message must not be empty - if(!length(message)) - return FALSE - - var/list/listeners = hearers(5, src) - listeners |= src - - var/list/hear_clients = list() - for(var/mob/living/silicon/D in listeners) - if(D.client && D.local_transmit) - to_chat(D, "[real_name] transmits, \"[message]\"") - hear_clients += D.client - - for(var/mob/M in player_list) - if(isnull(M.client)) - continue - if(istype(M, /mob/abstract/new_player)) - continue - else if(M.stat == DEAD && M.client.prefs.toggles & CHAT_GHOSTEARS) - to_chat(M, "[real_name] transmits, \"[message]\"") - hear_clients += M.client - - do_animate_chat(message, speaking, FALSE, hear_clients, 30) - - return TRUE - return ..(message, 0) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 2b6c1d31908..1e17f43157a 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -59,6 +59,7 @@ var/global/list/robot_modules = list( modules += new /obj/item/inductive_charger(src) add_camera_networks(R) + handle_languages(R) add_languages(R) add_subsystems(R) apply_status_flags(R) @@ -71,6 +72,9 @@ var/global/list/robot_modules = list( R.choose_icon() R.setup_icon_cache() +/obj/item/robot_module/proc/handle_languages(var/mob/living/silicon/robot/R) + return + /obj/item/robot_module/proc/Reset(var/mob/living/silicon/robot/R) remove_camera_networks(R) remove_languages(R) @@ -971,6 +975,19 @@ var/global/list/robot_modules = list( modules += new /obj/item/inflatable_dispenser(src) modules += new /obj/item/rfd/piping/borg(src) // putting this here so it's next to the RFD-C on construction drones +/obj/item/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + var/obj/item/device/lightreplacer/LR = locate() in src.modules + LR.Charge(R, amount) + return ..() + +/obj/item/robot_module/drone/handle_languages(var/mob/living/silicon/robot/R) + R.languages = list() + R.speech_synthesizer_langs = list() + for(var/language in languages) + languages[language] = FALSE + languages[LANGUAGE_DRONE] = TRUE + languages[LANGUAGE_LOCAL_DRONE] = TRUE + /obj/item/robot_module/drone/construction name = "construction drone module" channels = list(CHANNEL_ENGINEERING = TRUE) @@ -980,11 +997,8 @@ var/global/list/robot_modules = list( modules += new /obj/item/rfd/construction/borg(src) modules += new /obj/item/pickaxe/drill(src) -/obj/item/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/device/lightreplacer/LR = locate() in modules - LR.Charge(R, amount) - ..() - return +/obj/item/robot_module/drone/construction/matriarch + name = "matriarch drone module" /obj/item/robot_module/mining_drone name = "mining drone module" @@ -995,6 +1009,14 @@ var/global/list/robot_modules = list( . = ..() set_up_default(R) +/obj/item/robot_module/mining_drone/handle_languages(var/mob/living/silicon/robot/R) + R.languages = list() + R.speech_synthesizer_langs = list() + for(var/language in languages) + languages[language] = FALSE + languages[LANGUAGE_DRONE] = TRUE + languages[LANGUAGE_LOCAL_DRONE] = TRUE + /obj/item/robot_module/mining_drone/proc/set_up_default(var/mob/living/silicon/robot/R, var/has_drill = TRUE) modules += new /obj/item/device/flash(src) if(has_drill) diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index e4420f23fc8..76778c89380 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -33,6 +33,9 @@ message_mode = null return common_radio.talk_into(src, message, message_mode, verb, speaking) +/mob/living/silicon/robot/drone/handle_message_mode() + return null + /mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) ..() if(message_mode == "department") @@ -60,6 +63,13 @@ return speak_exclamation return speak_statement +/mob/living/silicon/robot/drone/say_quote(var/message, var/datum/language/speaking = null, var/singing = FALSE) + if(speaking) + var/ending = copytext(message, length(message)) + var/pre_ending = copytext(message, length(message) - 1, length(message)) + return speaking.get_spoken_verb(ending, pre_ending, singing) + return ..() + #define IS_AI 1 #define IS_ROBOT 2 #define IS_PAI 3 diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index d13985ce07a..26a044b7104 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -11,7 +11,6 @@ var/speak_statement = "states" var/speak_exclamation = "declares" var/speak_query = "queries" - var/local_transmit //If set, can only speak to others of the same type within a short range. // Description var/pose //Yes, now AIs can pose too. @@ -62,10 +61,12 @@ uv_intensity = 175 //Lights cast by robots have reduced effect on diona mob_thinks = FALSE + var/can_speak_basic = TRUE + /mob/living/silicon/Initialize() silicon_mob_list |= src . = ..() - add_language(LANGUAGE_TCB) + add_language(LANGUAGE_TCB, can_speak_basic) init_id() var/datum/language/L = locate(/datum/language/common) in languages diff --git a/html/changelogs/geeves-drone_speech_refactor.yml b/html/changelogs/geeves-drone_speech_refactor.yml new file mode 100644 index 00000000000..0d15de95dce --- /dev/null +++ b/html/changelogs/geeves-drone_speech_refactor.yml @@ -0,0 +1,7 @@ +author: Geeves + +delete-after: True + +changes: + - refactor: "Refactored drone speech, affecting maintenance drones, construction drones, mining drones and the matriarch drone. Everything should still work as expected." + - tweak: "Maintenance drones laws have been modified, they are now allowed to interact with both maintenance and mining drones by law, now." \ No newline at end of file