From 139d5cd3c3bb7fc377bdb44e982f2c1a8c6e1300 Mon Sep 17 00:00:00 2001 From: ShadowLarkens Date: Mon, 20 Apr 2020 01:11:53 -0700 Subject: [PATCH] Saycode Overhaul -- Multilingualism --- code/__defines/is_helpers.dm | 6 + code/__defines/misc.dm | 4 + code/game/machinery/hologram.dm | 19 +- code/game/machinery/telecomms/broadcaster.dm | 85 +-- .../machinery/telecomms/telecomunications.dm | 8 +- code/game/mecha/combat/combat.dm | 135 ----- code/game/mecha/mecha.dm | 7 +- .../items/devices/communicator/phone.dm | 20 +- code/game/objects/items/devices/megaphone.dm | 123 ++-- .../objects/items/devices/radio/headset.dm | 16 +- .../game/objects/items/devices/radio/radio.dm | 200 +++++-- code/game/objects/items/devices/spy_bug.dm | 10 +- .../objects/items/devices/taperecorder.dm | 11 +- code/game/objects/items/devices/translator.dm | 50 +- code/game/objects/items/devices/tvcamera.dm | 6 +- .../objects/items/weapons/implants/implant.dm | 3 +- code/game/objects/objs.dm | 4 +- code/modules/assembly/holder.dm | 6 +- code/modules/assembly/voice.dm | 3 +- .../integrated_electronics/subtypes/input.dm | 44 +- code/modules/mob/dead/observer/say.dm | 75 +-- code/modules/mob/hear_say.dm | 258 ++++----- code/modules/mob/language/generic.dm | 17 +- code/modules/mob/language/language.dm | 58 +- code/modules/mob/language/station.dm | 4 + code/modules/mob/living/autohiss.dm | 2 +- code/modules/mob/living/bot/bot.dm | 8 +- code/modules/mob/living/carbon/alien/alien.dm | 22 +- .../carbon/alien/diona/say_understands.dm | 7 +- code/modules/mob/living/carbon/alien/emote.dm | 116 ++-- code/modules/mob/living/carbon/alien/say.dm | 25 - code/modules/mob/living/carbon/brain/brain.dm | 33 +- code/modules/mob/living/carbon/brain/emote.dm | 63 +-- code/modules/mob/living/carbon/brain/say.dm | 31 +- code/modules/mob/living/carbon/human/emote.dm | 277 ++++----- code/modules/mob/living/carbon/human/say.dm | 150 ++--- .../carbon/human/species/station/station.dm | 7 +- .../human/species/xenomorphs/alien_species.dm | 8 +- .../mob/living/carbon/metroid/death.dm | 22 - .../mob/living/carbon/metroid/emote.dm | 99 ---- .../mob/living/carbon/metroid/examine.dm | 31 -- code/modules/mob/living/carbon/metroid/hud.dm | 2 - .../modules/mob/living/carbon/metroid/life.dm | 527 ------------------ .../mob/living/carbon/metroid/login.dm | 4 - .../mob/living/carbon/metroid/metroid.dm | 384 ------------- code/modules/mob/living/carbon/metroid/say.dm | 39 -- .../mob/living/carbon/metroid/subtypes.dm | 79 --- .../mob/living/carbon/metroid/update_icons.dm | 9 - code/modules/mob/living/default_language.dm | 2 +- code/modules/mob/living/say.dm | 228 ++++---- code/modules/mob/living/silicon/ai/ai.dm | 63 +++ code/modules/mob/living/silicon/emote.dm | 113 ++++ code/modules/mob/living/silicon/pai/say.dm | 4 +- .../living/silicon/robot/drone/drone_say.dm | 4 +- .../modules/mob/living/silicon/robot/emote.dm | 234 ++------ code/modules/mob/living/silicon/say.dm | 61 +- code/modules/mob/living/silicon/silicon.dm | 24 +- .../mob/living/simple_mob/simple_mob.dm | 17 +- .../simple_mob/subtypes/animal/borer/borer.dm | 11 +- .../subtypes/animal/borer/borer_captive.dm | 7 +- .../simple_mob/subtypes/animal/pets/parrot.dm | 254 +++++++++ code/modules/mob/living/voice/voice.dm | 20 +- code/modules/mob/mob.dm | 3 + code/modules/mob/mob_helpers.dm | 6 + code/modules/mob/new_player/new_player.dm | 2 +- code/modules/mob/say.dm | 195 +++++-- code/modules/multiz/zshadow.dm | 4 +- code/modules/xenoarcheaology/finds/special.dm | 6 +- code/modules/xenobio2/mob/xeno procs.dm | 6 +- vorestation.dme | 2 +- 70 files changed, 1742 insertions(+), 2641 deletions(-) delete mode 100644 code/modules/mob/living/carbon/alien/say.dm delete mode 100644 code/modules/mob/living/carbon/metroid/death.dm delete mode 100644 code/modules/mob/living/carbon/metroid/emote.dm delete mode 100644 code/modules/mob/living/carbon/metroid/examine.dm delete mode 100644 code/modules/mob/living/carbon/metroid/hud.dm delete mode 100644 code/modules/mob/living/carbon/metroid/life.dm delete mode 100644 code/modules/mob/living/carbon/metroid/login.dm delete mode 100644 code/modules/mob/living/carbon/metroid/metroid.dm delete mode 100644 code/modules/mob/living/carbon/metroid/say.dm delete mode 100644 code/modules/mob/living/carbon/metroid/subtypes.dm delete mode 100644 code/modules/mob/living/carbon/metroid/update_icons.dm create mode 100644 code/modules/mob/living/silicon/emote.dm diff --git a/code/__defines/is_helpers.dm b/code/__defines/is_helpers.dm index e121f55216..6d8ee456e7 100644 --- a/code/__defines/is_helpers.dm +++ b/code/__defines/is_helpers.dm @@ -13,6 +13,8 @@ #define isitem(D) istype(D, /obj/item) +#define isradio(A) istype(A, /obj/item/device/radio) + #define isairlock(A) istype(A, /obj/machinery/door/airlock) #define isorgan(A) istype(A, /obj/item/organ/external) @@ -51,5 +53,9 @@ //--------------- //#define isturf(D) istype(D, /turf) //Built in +<<<<<<< HEAD #define isopenspace(A) istype(A, /turf/simulated/open) #define isspace(A) istype(A, /turf/space) +======= +#define isopenspace(A) istype(A, /turf/simulated/open) +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 22f8c86e43..e1505934e8 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -374,3 +374,7 @@ var/global/list/##LIST_NAME = list();\ #define MOUSE_OPACITY_TRANSPARENT 0 #define MOUSE_OPACITY_ICON 1 #define MOUSE_OPACITY_OPAQUE 2 + +// Used by radios to indicate that they have sent a message via something other than subspace +#define RADIO_CONNECTION_FAIL 0 +#define RADIO_CONNECTION_NON_SUBSPACE 1 diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 4fec2cba82..ab86d71df2 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -92,22 +92,11 @@ var/const/HOLOPAD_MODE = RANGE_BASED /*This is the proc for special two-way communication between AI and holopad/people talking near holopad. For the other part of the code, check silicon say.dm. Particularly robot talk.*/ -/obj/machinery/hologram/holopad/hear_talk(mob/living/M, text, verb, datum/language/speaking) - if(M) +/obj/machinery/hologram/holopad/hear_talk(mob/M, list/message_pieces, verb) + if(M && LAZYLEN(masters)) for(var/mob/living/silicon/ai/master in masters) - if(!master.say_understands(M, speaking))//The AI will be able to understand most mobs talking through the holopad. - if(speaking) - text = speaking.scramble(text) - else - text = stars(text) - var/name_used = M.GetVoice() - //This communication is imperfect because the holopad "filters" voices and is only designed to connect to the master only. - var/rendered - if(speaking) - rendered = "Holopad received, [name_used] [speaking.format_message(text, verb)]" - else - rendered = "Holopad received, [name_used] [verb], \"[text]\"" - master.show_message(rendered, 2) + if(masters[master] && M != master) + master.relay_speech(M, message_pieces, verb) /obj/machinery/hologram/holopad/see_emote(mob/living/M, text) if(M) diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index b3c524a5ad..89c1fd30ac 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -86,7 +86,11 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept signal.data["name"], signal.data["job"], signal.data["realname"], signal.data["vname"], DATA_NORMAL, signal.data["compression"], signal.data["level"], signal.frequency, +<<<<<<< HEAD signal.data["verb"], signal.data["language"], forced_radios) +======= + signal.data["verb"]) +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) /** #### - Simple Broadcast - #### **/ @@ -111,9 +115,14 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept signal.data["vmask"], signal.data["vmessage"], signal.data["radio"], signal.data["message"], signal.data["name"], signal.data["job"], +<<<<<<< HEAD signal.data["realname"], signal.data["vname"], DATA_FAKE, signal.data["compression"], signal.data["level"], signal.frequency, signal.data["verb"], signal.data["language"], forced_radios) +======= + signal.data["realname"], signal.data["vname"], 4, signal.data["compression"], signal.data["level"], signal.frequency, + signal.data["verb"]) +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) if(!message_delay) message_delay = 1 @@ -270,18 +279,30 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept signal.data["vmask"], signal.data["vmessage"], signal.data["radio"], signal.data["message"], signal.data["name"], signal.data["job"], +<<<<<<< HEAD signal.data["realname"], signal.data["vname"], DATA_NORMAL, signal.data["compression"], list(0), connection.frequency, signal.data["verb"], signal.data["language"], forced_radios) +======= + signal.data["realname"], signal.data["vname"],, signal.data["compression"], list(0), connection.frequency, + signal.data["verb"]) +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) else if(intercept) Broadcast_Message(signal.data["connection"], signal.data["mob"], signal.data["vmask"], signal.data["vmessage"], signal.data["radio"], signal.data["message"], signal.data["name"], signal.data["job"], +<<<<<<< HEAD signal.data["realname"], signal.data["vname"], DATA_ANTAG, signal.data["compression"], list(0), connection.frequency, signal.data["verb"], signal.data["language"], forced_radios) +======= + signal.data["realname"], signal.data["vname"], 3, signal.data["compression"], list(0), connection.frequency, + signal.data["verb"]) + + +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) /** @@ -341,10 +362,16 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept **/ /proc/Broadcast_Message(var/datum/radio_frequency/connection, var/mob/M, +<<<<<<< HEAD var/vmask, var/vmessage, var/obj/item/device/radio/radio, var/message, var/name, var/job, var/realname, var/vname, var/data, var/compression, var/list/level, var/freq, var/verbage = "says", var/datum/language/speaking = null, var/list/forced_radios) +======= + var/vmask, var/list/vmessage_pieces, var/obj/item/device/radio/radio, + var/list/message_pieces, var/name, var/job, var/realname, var/vname, + var/data, var/compression, var/list/level, var/freq, var/verbage = "says") +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) /* ###### Prepare the radio connection ###### */ @@ -412,7 +439,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept for (var/mob/R in receive) /* --- Loop through the receivers and categorize them --- */ - if (!R.is_preference_enabled(/datum/client_preference/holder/hear_radio)) + if(!R.is_preference_enabled(/datum/client_preference/holder/hear_radio)) continue if(istype(R, /mob/new_player)) // we don't want new players to hear messages. rare but generates runtimes. @@ -429,10 +456,10 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept // --- Can understand the speech --- - if (!M || R.say_understands(M)) + if(!M || R.say_understands(M)) // - Not human or wearing a voice mask - - if (!M || !ishuman(M) || vmask) + if(!M || !ishuman(M) || vmask) heard_masked += R // - Human and not wearing voice mask - @@ -443,7 +470,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept else // - The speaker has a prespecified "voice message" to display if not understood - - if (vmessage) + if(vmessage_pieces) heard_voice += R // - Just display a garbled message - @@ -452,7 +479,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* ###### Begin formatting and sending the message ###### */ - if (length(heard_masked) || length(heard_normal) || length(heard_voice) || length(heard_garbled) || length(heard_gibberish)) + if(length(heard_masked) || length(heard_normal) || length(heard_voice) || length(heard_garbled) || length(heard_gibberish)) /* --- Some miscellaneous variables to format the string output --- */ var/freq_text = get_frequency_name(display_freq) @@ -468,12 +495,11 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept // --- Filter the message; place it in quotes apply a verb --- - var/quotedmsg = null if(M) - quotedmsg = M.say_quote(message) + quotedmsg = "[M.say_quote(multilingual_to_message(message_pieces))], \"[multilingual_to_message(message_pieces)]\"" else - quotedmsg = "says, \"[message]\"" + quotedmsg = "says, \"[multilingual_to_message(message_pieces)]\"" // --- This following recording is intended for research and feedback in the use of department radio channels --- @@ -514,44 +540,41 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept //End of research and feedback code. /* ###### Send the message ###### */ - - /* --- Process all the mobs that heard a masked voice (understood) --- */ - - if (length(heard_masked)) + if(length(heard_masked)) for (var/mob/R in heard_masked) - R.hear_radio(message,verbage, speaking, part_a, part_b, part_c, M, 0, name) + R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, M, 0, name) /* --- Process all the mobs that heard the voice normally (understood) --- */ - - if (length(heard_normal)) + if(length(heard_normal)) for (var/mob/R in heard_normal) - R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, 0, realname) + R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, M, 0, realname) /* --- Process all the mobs that heard the voice normally (did not understand) --- */ - - if (length(heard_voice)) + if(length(heard_voice)) for (var/mob/R in heard_voice) - R.hear_radio(message,verbage, speaking, part_a, part_b, part_c, M,0, vname) + R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, M,0, vname) /* --- Process all the mobs that heard a garbled voice (did not understand) --- */ // Displays garbled message (ie "f*c* **u, **i*er!") - - if (length(heard_garbled)) + if(length(heard_garbled)) for (var/mob/R in heard_garbled) - R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, 1, vname) - + R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, M, 1, vname) /* --- Complete gibberish. Usually happens when there's a compressed message --- */ - - if (length(heard_gibberish)) + if(length(heard_gibberish)) for (var/mob/R in heard_gibberish) - R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, 1) + R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, M, 1) return 1 +<<<<<<< HEAD /proc/Broadcast_SimpleMessage(var/source, var/frequency, var/text, var/data, var/mob/M, var/compression, var/level, var/list/forced_radios) +======= +/proc/Broadcast_SimpleMessage(var/source, var/frequency, list/message_pieces, var/data, var/mob/M, var/compression, var/level) + var/text = multilingual_to_message(message_pieces) +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) /* ###### Prepare the radio connection ###### */ if(!M) @@ -633,7 +656,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept // --- Can understand the speech --- - if (R.say_understands(M)) + if(R.say_understands(M)) heard_normal += R @@ -646,7 +669,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* ###### Begin formatting and sending the message ###### */ - if (length(heard_normal) || length(heard_garbled) || length(heard_gibberish)) + if(length(heard_normal) || length(heard_garbled) || length(heard_gibberish)) /* --- Some miscellaneous variables to format the string output --- */ var/part_a = "" // goes in the actual output @@ -701,7 +724,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* --- Process all the mobs that heard the voice normally (understood) --- */ - if (length(heard_normal)) + if(length(heard_normal)) var/rendered = "[part_a][source][part_b]\"[text]\"[part_c]" for (var/mob/R in heard_normal) @@ -710,7 +733,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* --- Process all the mobs that heard a garbled voice (did not understand) --- */ // Displays garbled message (ie "f*c* **u, **i*er!") - if (length(heard_garbled)) + if(length(heard_garbled)) var/quotedmsg = "\"[stars(text)]\"" var/rendered = "[part_a][source][part_b][quotedmsg][part_c]" @@ -720,7 +743,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* --- Complete gibberish. Usually happens when there's a compressed message --- */ - if (length(heard_gibberish)) + if(length(heard_gibberish)) var/quotedmsg = "\"[Gibberish(text, compression + 50)]\"" var/rendered = "[part_a][Gibberish(source, compression + 50)][part_b][quotedmsg][part_c]" diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 1fffddbd1f..ac6e56cee3 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -602,7 +602,6 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() var/encryption = "null" // encryption key: ie "password" var/salt = "null" // encryption salt: ie "123comsat" // would add up to md5("password123comsat") - var/language = "human" var/obj/item/device/radio/headset/server_radio = null /obj/machinery/telecomms/server/New() @@ -643,12 +642,11 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() log.parameters["mobtype"] = signal.data["mobtype"] log.parameters["job"] = signal.data["job"] log.parameters["key"] = signal.data["key"] - log.parameters["vmessage"] = signal.data["message"] + log.parameters["vmessage"] = multilingual_to_message(signal.data["message"]) log.parameters["vname"] = signal.data["vname"] - log.parameters["message"] = signal.data["message"] + log.parameters["message"] = multilingual_to_message(signal.data["message"]) log.parameters["name"] = signal.data["name"] log.parameters["realname"] = signal.data["realname"] - log.parameters["language"] = signal.data["language"] var/race = "unknown" if(ishuman(M)) @@ -677,7 +675,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() // If the signal is still compressed, make the log entry gibberish if(signal.data["compression"] > 0) - log.parameters["message"] = Gibberish(signal.data["message"], signal.data["compression"] + 50) + log.parameters["message"] = Gibberish(multilingual_to_message(signal.data["message"]), signal.data["compression"] + 50) log.parameters["job"] = Gibberish(signal.data["job"], signal.data["compression"] + 50) log.parameters["name"] = Gibberish(signal.data["name"], signal.data["compression"] + 50) log.parameters["realname"] = Gibberish(signal.data["realname"], signal.data["compression"] + 50) diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm index b58956579a..b5d3351b21 100644 --- a/code/game/mecha/combat/combat.dm +++ b/code/game/mecha/combat/combat.dm @@ -119,134 +119,6 @@ melee_can_hit = 1 return -/* -/obj/mecha/combat/proc/mega_shake(target) - if(!istype(target, /obj) && !istype(target, /mob)) return - if(istype(target, /mob)) - var/mob/M = target - M.make_dizzy(3) - M.adjustBruteLoss(1) - M.updatehealth() - for (var/mob/V in viewers(src)) - V.show_message("[src.name] shakes [M] like a rag doll.") - return -*/ - -/* - if(energy>0 && can_move) - if(step(src,direction)) - can_move = 0 - spawn(step_in) can_move = 1 - if(overload) - energy = energy-2 - health-- - else - energy-- - return 1 - - return 0 -*/ -/* -/obj/mecha/combat/hear_talk(mob/M as mob, text) - ..() - if(am && M==occupant) - if(findtext(text,"")) - sam() - return - -/obj/mecha/combat/proc/sam() - if(am) - var/window = {" - - - - - -
-
- - -
-
- - - "} - occupant << browse(window, "window=sam;size=800x600;") - onclose(occupant, "sam", src) - return -*/ /obj/mecha/combat/moved_inside(var/mob/living/carbon/human/H as mob) if(..()) if(H.client) @@ -275,10 +147,3 @@ if(top_filter.get("close")) am = null return - /* - if(top_filter.get("saminput")) - if(md5(top_filter.get("saminput")) == am) - occupant_message("From the lies of the Antipath, Circuit preserve us.") - am = null - return - */ diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index d9198cc6e7..1e4f4dc8ae 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -290,10 +290,9 @@ /obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits. return -/obj/mecha/hear_talk(mob/M as mob, text) - if(M==occupant && radio.broadcasting) - radio.talk_into(M, text) - return +/obj/mecha/hear_talk(mob/M, list/message_pieces, verb) + if(M == occupant && radio.broadcasting) + radio.talk_into(M, message_pieces) //////////////////////////// ///// Action processing //// diff --git a/code/game/objects/items/devices/communicator/phone.dm b/code/game/objects/items/devices/communicator/phone.dm index 3042b06fa9..d7816fbb82 100644 --- a/code/game/objects/items/devices/communicator/phone.dm +++ b/code/game/objects/items/devices/communicator/phone.dm @@ -227,12 +227,12 @@ ..() // Proc: hear_talk() -// Parameters: 4 (M - the mob the speech originated from, text - what is being said, verb - the word used to describe how text is being said, speaking - language -// being used) +// Parameters: 3 (M - the mob the speech originated from, +// list/message_pieces - what is being said w/ baked languages, +// verb - the word used to describe how text is being said) // Description: Relays the speech to all linked communicators. -/obj/item/device/communicator/hear_talk(mob/living/M, text, verb, datum/language/speaking) +/obj/item/device/communicator/hear_talk(mob/M, list/message_pieces, verb) for(var/obj/item/device/communicator/comm in communicating) - var/turf/T = get_turf(comm) if(!T) return //VOREStation Edit Start for commlinks @@ -246,18 +246,10 @@ //VOREStation Edit End for(var/mob/mob in mobs_to_relay) - //Can whoever is hearing us understand? - if(!mob.say_understands(M, speaking)) - if(speaking) - text = speaking.scramble(text) - else - text = stars(text) + var/message = mob.combine_message(message_pieces, verb, M) var/name_used = M.GetVoice() var/rendered = null - if(speaking) //Language being used - rendered = "[bicon(src)] [name_used] [speaking.format_message(text, verb)]" - else - rendered = "[bicon(src)] [name_used] [verb], \"[text]\"" + rendered = "[bicon(src)] [name_used] [message]" mob.show_message(rendered, 2) // Proc: show_message() diff --git a/code/game/objects/items/devices/megaphone.dm b/code/game/objects/items/devices/megaphone.dm index 0a12b31df2..7e7bbdb629 100644 --- a/code/game/objects/items/devices/megaphone.dm +++ b/code/game/objects/items/devices/megaphone.dm @@ -10,53 +10,52 @@ var/list/insultmsg = list("FUCK EVERYONE!", "I'M A TERRORIST!", "ALL SECURITY TO SHOOT ME ON SIGHT!", "I HAVE A BOMB!", "CAPTAIN IS A COMDOM!", "GLORY TO ALMACH!") /obj/item/device/megaphone/proc/can_broadcast(var/mob/living/user) - if (user.client) + if(user.client) if(user.client.prefs.muted & MUTE_IC) to_chat(user, "You cannot speak in IC (muted).") - return 0 + return FALSE if(!(ishuman(user) || user.isSynthetic())) to_chat(user, "You don't know how to use this!") - return 0 + return FALSE if(user.silent) - return 0 - if(spamcheck) - to_chat(user, "\The [src] needs to recharge!") - return 0 - return 1 + return FALSE + if(spamcheck > world.time) + to_chat(user, "[src] needs to recharge!") + return FALSE + if(loc != user) + return FALSE + if(user.stat != CONSCIOUS) + return FALSE + return TRUE /obj/item/device/megaphone/proc/do_broadcast(var/mob/living/user, var/message) - if ((src.loc == user && usr.stat == 0)) - if(emagged) - if(insults) - user.audible_message("[user] broadcasts, \"[pick(insultmsg)]\"") - insults-- - else - to_chat(user, "*BZZZZzzzzzt*") + if(emagged) + if(insults) + user.audible_message("[user.GetVoice()][user.GetAltName()] broadcasts, \"[pick(insultmsg)]\"") + insults-- else - user.audible_message("[user] broadcasts, \"[message]\"") - - spamcheck = 1 - spawn(20) - spamcheck = 0 - return - -/obj/item/device/megaphone/attack_self(mob/living/user as mob) - if(!can_broadcast(user)) - return + to_chat(user, "*BZZZZzzzzzt*") + else + user.audible_message("[user.GetVoice()][user.GetAltName()] broadcasts, \"[message]\"") +/obj/item/device/megaphone/attack_self(var/mob/living/user) var/message = sanitize(input(user, "Shout a message?", "Megaphone", null) as text) if(!message) return message = capitalize(message) + if(!can_broadcast(user)) + return + + spamcheck = world.time + 20 do_broadcast(user, message) /obj/item/device/megaphone/emag_act(var/remaining_charges, var/mob/user) if(!emagged) - to_chat(user, "You overload \the [src]'s voice synthesizer.") - emagged = 1 + to_chat(user, "You overload [src]'s voice synthesizer.") + emagged = TRUE insults = rand(1, 3)//to prevent caps spam. - return 1 + return TRUE /obj/item/device/megaphone/super name = "gigaphone" @@ -130,41 +129,35 @@ broadcast_color = new_color /obj/item/device/megaphone/super/do_broadcast(var/mob/living/user, var/message) - if ((src.loc == user && usr.stat == 0)) - if(emagged) - if(insults) - user.audible_message("[user] broadcasts, \"[pick(insultmsg)]\"") - if(broadcast_size >= 11) - var/turf/T = get_turf(user) - playsound(T, 'sound/items/AirHorn.ogg', 100, 1) - for(var/mob/living/carbon/M in oviewers(4, T)) - if(M.get_ear_protection() >= 2) - continue - M.sleeping = 0 - M.stuttering += 20 - M.ear_deaf += 30 - M.Weaken(3) - if(prob(30)) - M.Stun(10) - M.Paralyse(4) - else - M.make_jittery(50) - insults-- - else - user.audible_message("*BZZZZzzzzzt*") - if(prob(40) && insults <= 0) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(2, 1, get_turf(user)) - s.start() - user.visible_message("\The [src] sparks violently!") - spawn(30) - explosion(get_turf(src), -1, -1, 1, 3, adminlog = 1) - qdel(src) - return + if(emagged) + if(insults) + user.audible_message("[user.GetVoice()][user.GetAltName()] broadcasts, \"[pick(insultmsg)]\"") + if(broadcast_size >= 11) + var/turf/T = get_turf(user) + playsound(T, 'sound/items/AirHorn.ogg', 100, 1) + for(var/mob/living/carbon/M in oviewers(4, T)) + if(M.get_ear_protection() >= 2) + continue + M.sleeping = 0 + M.stuttering += 20 + M.ear_deaf += 30 + M.Weaken(3) + if(prob(30)) + M.Stun(10) + M.Paralyse(4) + else + M.make_jittery(50) + insults-- else - user.audible_message("[user] broadcasts, \"[message]\"") - - spamcheck = 1 - spawn(20) - spamcheck = 0 - return + user.audible_message("*BZZZZzzzzzt*") + if(prob(40) && insults <= 0) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, get_turf(user)) + s.start() + user.visible_message("\The [src] sparks violently!") + spawn(30) + explosion(get_turf(src), -1, -1, 1, 3, adminlog = 1) + qdel(src) + return + else + user.audible_message("[user.GetVoice()][user.GetAltName()] broadcasts, \"[message]\"") diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 67ad07567f..580a59616d 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -43,15 +43,17 @@ to_chat(user, "The following channels are available:") to_chat(user, radio_desc) -/obj/item/device/radio/headset/handle_message_mode(mob/living/M as mob, message, channel) - if (channel == "special") - if (translate_binary) +/obj/item/device/radio/headset/handle_message_mode(mob/living/M as mob, list/message_pieces, channel) + if(channel == "special") + if(translate_binary) var/datum/language/binary = GLOB.all_languages["Robot Talk"] - binary.broadcast(M, message) - if (translate_hive) + binary.broadcast(M, M.strip_prefixes(multilingual_to_message(message_pieces))) + return RADIO_CONNECTION_NON_SUBSPACE + if(translate_hive) var/datum/language/hivemind = GLOB.all_languages["Hivemind"] - hivemind.broadcast(M, message) - return null + hivemind.broadcast(M, M.strip_prefixes(multilingual_to_message(message_pieces))) + return RADIO_CONNECTION_NON_SUBSPACE + return RADIO_CONNECTION_FAIL return ..() diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 69b5192abb..afe58f7308 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -216,7 +216,7 @@ var/global/list/default_medbay_channels = list( return can_admin_interact() /obj/item/device/radio/proc/text_wires() - if (b_stat) + if(b_stat) return wires.GetInteractWindow() return @@ -244,31 +244,31 @@ var/global/list/default_medbay_channels = list( return TRUE usr.set_machine(src) - if (href_list["track"]) + if(href_list["track"]) var/mob/target = locate(href_list["track"]) var/mob/living/silicon/ai/A = locate(href_list["track2"]) if(A && target) A.ai_actual_track(target) . = 1 - else if (href_list["freq"]) + else if(href_list["freq"]) var/new_frequency = (frequency + text2num(href_list["freq"])) - if ((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)) + if((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)) new_frequency = sanitize_frequency(new_frequency) set_frequency(new_frequency) if(hidden_uplink) if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency)) usr << browse(null, "window=radio") . = 1 - else if (href_list["talk"]) + else if(href_list["talk"]) ToggleBroadcast() . = 1 - else if (href_list["listen"]) + else if(href_list["listen"]) var/chan_name = href_list["ch_name"] - if (!chan_name) + if(!chan_name) ToggleReception() else - if (channels[chan_name] & FREQ_LISTENING) + if(channels[chan_name] & FREQ_LISTENING) channels[chan_name] &= ~FREQ_LISTENING else channels[chan_name] |= FREQ_LISTENING @@ -287,13 +287,18 @@ var/global/list/default_medbay_channels = list( /obj/item/device/radio/proc/autosay(var/message, var/from, var/channel, var/list/zlevels) //BS12 EDIT var/datum/radio_frequency/connection = null if(channel && channels && channels.len > 0) +<<<<<<< HEAD if (channel == "department") +======= + if(channel == "department") + //to_world("DEBUG: channel=\"[channel]\" switching to \"[channels[1]]\"") +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) channel = channels[1] connection = secure_radio_connections[channel] else connection = radio_connection channel = null - if (!istype(connection)) + if(!istype(connection)) return if(!LAZYLEN(zlevels)) @@ -303,32 +308,37 @@ var/global/list/default_medbay_channels = list( A.SetName(from) Broadcast_Message(connection, A, 0, "*garbled automated announcement*", src, +<<<<<<< HEAD message, from, "Automated Announcement", from, "synthesized voice", 4, 0, zlevels, connection.frequency, "states") +======= + message_to_multilingual(message), from, "Automated Announcement", from, "synthesized voice", + 4, 0, list(0), connection.frequency, "states") +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) // Interprets the message mode when talking into a radio, possibly returning a connection datum -/obj/item/device/radio/proc/handle_message_mode(mob/living/M as mob, message, message_mode) +/obj/item/device/radio/proc/handle_message_mode(mob/living/M as mob, list/message_pieces, message_mode) // If a channel isn't specified, send to common. if(!message_mode || message_mode == "headset") return radio_connection // Otherwise, if a channel is specified, look for it. if(channels && channels.len > 0) - if (message_mode == "department") // Department radio shortcut + if(message_mode == "department") // Department radio shortcut message_mode = channels[1] - if (channels[message_mode]) // only broadcast if the channel is set on + if(channels[message_mode]) // only broadcast if the channel is set on return secure_radio_connections[message_mode] // If we were to send to a channel we don't have, drop it. - return null + return RADIO_CONNECTION_FAIL -/obj/item/device/radio/talk_into(mob/living/M as mob, message, channel, var/verb = "says", var/datum/language/speaking = null) - if(!on) return FALSE // the device has to be on +/obj/item/device/radio/talk_into(mob/living/M as mob, list/message_pieces, channel, var/verb = "says") + if(!on) + return FALSE // the device has to be on // Fix for permacell radios, but kinda eh about actually fixing them. - if(!M || !message) return FALSE - - if(speaking && (speaking.flags & (SIGNLANG|NONVERBAL))) return FALSE + if(!M || !message_pieces) + return FALSE if(istype(M)) M.trigger_aiming(TARGET_CAN_RADIO) @@ -352,11 +362,22 @@ var/global/list/default_medbay_channels = list( */ //#### Grab the connection datum ####// - var/datum/radio_frequency/connection = handle_message_mode(M, message, channel) - if (!istype(connection)) + var/message_mode = handle_message_mode(M, message_pieces, channel) + switch(message_mode) + if(RADIO_CONNECTION_FAIL) + return FALSE + if(RADIO_CONNECTION_NON_SUBSPACE) + return TRUE + + if(!istype(message_mode, /datum/radio_frequency)) //if not a special case, it should be returning a radio connection return FALSE +<<<<<<< HEAD var/pos_z = get_z(src) +======= + var/datum/radio_frequency/connection = message_mode + var/turf/position = get_turf(src) +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) //#### Tagging the signal with all appropriate identity values ####// @@ -372,24 +393,24 @@ var/global/list/default_medbay_channels = list( var/jobname // the mob's "job" // --- Human: use their actual job --- - if (ishuman(M)) + if(ishuman(M)) var/mob/living/carbon/human/H = M jobname = H.get_assignment() // --- Carbon Nonhuman --- - else if (iscarbon(M)) // Nonhuman carbon mob + else if(iscarbon(M)) // Nonhuman carbon mob jobname = "No id" // --- AI --- - else if (isAI(M)) + else if(isAI(M)) jobname = "AI" // --- Cyborg --- - else if (isrobot(M)) + else if(isrobot(M)) jobname = "Cyborg" // --- Personal AI (pAI) --- - else if (istype(M, /mob/living/silicon/pai)) + else if(istype(M, /mob/living/silicon/pai)) jobname = "Personal AI" // --- Unidentifiable mob --- @@ -400,7 +421,7 @@ var/global/list/default_medbay_channels = list( // --- Modifications to the mob's identity --- // The mob is disguising their identity: - if (ishuman(M) && M.GetVoice() != real_name) + if(ishuman(M) && M.GetVoice() != real_name) displayname = M.GetVoice() jobname = "Unknown" voicemask = 1 @@ -469,9 +490,48 @@ var/global/list/default_medbay_channels = list( return FALSE // First, we want to generate a new radio signal +<<<<<<< HEAD signal.transmission_method = TRANSMISSION_SUBSPACE //#### Sending the signal to all subspace receivers ####// +======= + var/datum/signal/signal = new + signal.transmission_method = 2 // 2 would be a subspace transmission. + // transmission_method could probably be enumerated through #define. Would be neater. + + // --- Finally, tag the actual signal with the appropriate values --- + signal.data = list( + // Identity-associated tags: + "mob" = M, // store a reference to the mob + "mobtype" = M.type, // the mob's type + "realname" = real_name, // the mob's real name + "name" = displayname, // the mob's display name + "job" = jobname, // the mob's job + "key" = mobkey, // the mob's key + "vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood + "vname" = M.voice_name, // the name to display if the voice wasn't understood + "vmask" = voicemask, // 1 if the mob is using a voice gas mask + + // We store things that would otherwise be kept in the actual mob + // so that they can be logged even AFTER the mob is deleted or something + + // Other tags: + "compression" = rand(45,50), // compressed radio signal + "message" = message_pieces, // the actual sent message + "connection" = connection, // the radio connection to use + "radio" = src, // stores the radio used for transmission + "slow" = 0, // how much to sleep() before broadcasting - simulates net lag + "traffic" = 0, // dictates the total traffic sum that the signal went through + "type" = 0, // determines what type of radio input it is: normal broadcast + "server" = null, // the last server to log this signal + "reject" = 0, // if nonzero, the signal will not be accepted by any broadcasting machinery + "level" = position.z, // The source's z level + "verb" = verb + ) + signal.frequency = connection.frequency // Quick frequency set + + //#### Sending the signal to all subspace receivers ####// +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) for(var/obj/machinery/telecomms/receiver/R in telecomms_list) R.receive_signal(signal) @@ -487,6 +547,20 @@ var/global/list/default_medbay_channels = list( else if(adhoc_fallback) //Less huzzah, we have to fallback to_chat(loc, "\The [src] pings as it falls back to local radio transmission.") subspace_transmission = FALSE +<<<<<<< HEAD +======= + return Broadcast_Message(connection, M, voicemask, pick(M.speak_emote), + src, message_pieces, displayname, jobname, real_name, M.voice_name, + signal.transmission_method, signal.data["compression"], GetConnectedZlevels(position.z), connection.frequency,verb) + + /* ###### Intercoms and station-bounced radios ###### */ + + var/filter_type = 2 + + /* --- Intercoms can only broadcast to other intercoms, but bounced radios can broadcast to bounced radios and intercoms --- */ + if(istype(src, /obj/item/device/radio/intercom)) + filter_type = 1 +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) else //Oh well return FALSE @@ -504,9 +578,25 @@ var/global/list/default_medbay_channels = list( for(var/obj/machinery/telecomms/receiver/R in telecomms_list) R.receive_signal(signal) +<<<<<<< HEAD // Allinone can act as receivers. for(var/obj/machinery/telecomms/allinone/R in telecomms_list) R.receive_signal(signal) +======= + "compression" = 0, // uncompressed radio signal + "message" = message_pieces, // the actual sent message + "connection" = connection, // the radio connection to use + "radio" = src, // stores the radio used for transmission + "slow" = 0, + "traffic" = 0, + "type" = 0, + "server" = null, + "reject" = 0, + "level" = position.z, + "verb" = verb + ) + signal.frequency = connection.frequency // Quick frequency set +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) for(var/obj/machinery/telecomms/receiver/R in telecomms_list) R.receive_signal(signal) @@ -520,21 +610,45 @@ var/global/list/default_medbay_channels = list( //Nothing handled any sort of remote radio-ing and returned before now, just squawk on this zlevel. return Broadcast_Message(connection, M, voicemask, pick(M.speak_emote), +<<<<<<< HEAD src, message, displayname, jobname, real_name, M.voice_name, filter_type, signal.data["compression"], using_map.get_map_levels(pos_z), connection.frequency, verb, speaking) +======= + src, message_pieces, displayname, jobname, real_name, M.voice_name, + filter_type, signal.data["compression"], GetConnectedZlevels(position.z), connection.frequency, verb) +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) -/obj/item/device/radio/hear_talk(mob/M as mob, msg, var/verb = "says", var/datum/language/speaking = null) - if (broadcasting) +/obj/item/device/radio/hear_talk(mob/M, list/message_pieces, verb) + if(broadcasting) if(get_dist(src, M) <= canhear_range) - talk_into(M, msg,null,verb,speaking) + talk_into(M, message_pieces, null, verb) +<<<<<<< HEAD +======= +/* +/obj/item/device/radio/proc/accept_rad(obj/item/device/radio/R as obj, message) + + if((R.frequency == frequency && message)) + return TRUE + else if + + else + return null + return +*/ + +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) /obj/item/device/radio/proc/receive_range(freq, level) // check if this radio can receive on the given frequency, and if so, // what the range is in which mobs will hear the radio // returns: -1 if can't receive, range otherwise +<<<<<<< HEAD +======= + +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) if(wires.IsIndexCut(WIRE_RECEIVE)) return -1 if(!listening) @@ -551,20 +665,20 @@ var/global/list/default_medbay_channels = list( if(freq in CENT_FREQS) if(!(src.centComm))//Checks to see if it's allowed on that frequency, based on the encryption keys return -1 - if (!on) + if(!on) return -1 - if (!freq) //recieved on main frequency - if (!listening) + if(!freq) //recieved on main frequency + if(!listening) return -1 else var/accept = (freq==frequency && listening) - if (!accept) + if(!accept) for (var/ch_name in channels) var/datum/radio_frequency/RF = secure_radio_connections[ch_name] - if (RF && RF.frequency==freq && (channels[ch_name]&FREQ_LISTENING)) + if(RF && RF.frequency==freq && (channels[ch_name]&FREQ_LISTENING)) accept = 1 break - if (!accept) + if(!accept) return -1 return canhear_range @@ -577,8 +691,8 @@ var/global/list/default_medbay_channels = list( /obj/item/device/radio/examine(mob/user) . = ..() - if ((in_range(src, user) || loc == user)) - if (b_stat) + if((in_range(src, user) || loc == user)) + if(b_stat) user.show_message("\The [src] can be attached and modified!") else user.show_message("\The [src] can not be modified or attached!") @@ -587,11 +701,11 @@ var/global/list/default_medbay_channels = list( /obj/item/device/radio/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() user.set_machine(src) - if (!W.is_screwdriver()) + if(!W.is_screwdriver()) return b_stat = !( b_stat ) if(!istype(src, /obj/item/device/radio/beacon)) - if (b_stat) + if(b_stat) user.show_message("\The [src] can now be attached and modified!") else user.show_message("\The [src] can no longer be modified or attached!") @@ -631,7 +745,7 @@ var/global/list/default_medbay_channels = list( /obj/item/device/radio/borg/talk_into() . = ..() - if (isrobot(src.loc)) + if(isrobot(src.loc)) var/mob/living/silicon/robot/R = src.loc var/datum/robot_component/C = R.components["radio"] R.cell_use_power(C.active_usage) @@ -639,7 +753,7 @@ var/global/list/default_medbay_channels = list( /obj/item/device/radio/borg/attackby(obj/item/weapon/W as obj, mob/user as mob) // ..() user.set_machine(src) - if (!(W.is_screwdriver() || istype(W, /obj/item/device/encryptionkey))) + if(!(W.is_screwdriver() || istype(W, /obj/item/device/encryptionkey))) return if(W.is_screwdriver()) @@ -713,7 +827,7 @@ var/global/list/default_medbay_channels = list( /obj/item/device/radio/borg/Topic(href, href_list) if(..()) return TRUE - if (href_list["mode"]) + if(href_list["mode"]) var/enable_subspace_transmission = text2num(href_list["mode"]) if(enable_subspace_transmission != subspace_transmission) subspace_transmission = !subspace_transmission @@ -727,7 +841,7 @@ var/global/list/default_medbay_channels = list( else recalculateChannels() . = 1 - if (href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio. + if(href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio. var/do_shut_up = text2num(href_list["shutup"]) if(do_shut_up != shut_up) shut_up = !shut_up diff --git a/code/game/objects/items/devices/spy_bug.dm b/code/game/objects/items/devices/spy_bug.dm index 1f15d36b12..5d8587272d 100644 --- a/code/game/objects/items/devices/spy_bug.dm +++ b/code/game/objects/items/devices/spy_bug.dm @@ -126,10 +126,7 @@ linkedmonitor.unpair(src) linkedmonitor = null ..() -/* -/obj/item/device/camerabug/hear_talk(mob/M, var/msg, verb, datum/language/speaking) - radio.hear_talk(M, msg, speaking) -*/ + /obj/item/device/bug_monitor name = "mobile camera pod monitor" desc = "A portable camera console designed to work with mobile camera pods." @@ -208,10 +205,7 @@ return return 1 -/* -/obj/item/device/bug_monitor/hear_talk(mob/M, var/msg, verb, datum/language/speaking) - return radio.hear_talk(M, msg, speaking) -*/ + /obj/item/device/bug_monitor/spy name = "\improper PDA" desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge." diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index c2320dcf44..bdb35fb643 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -86,15 +86,10 @@ update_icon() -/obj/item/device/taperecorder/hear_talk(mob/living/M as mob, msg, var/verb="says", datum/language/speaking=null) +/obj/item/device/taperecorder/hear_talk(mob/M, list/message_pieces, verb) + var/msg = multilingual_to_message(message_pieces, requires_machine_understands = TRUE, with_capitalization = TRUE) if(mytape && recording) - - if(speaking) - if(!speaking.machine_understands) - msg = speaking.scramble(msg) - mytape.record_speech("[M.name] [speaking.format_message_plain(msg, verb)]") - else - mytape.record_speech("[M.name] [verb], \"[msg]\"") + mytape.record_speech("[M.name] [verb], \"[msg]\"") /obj/item/device/taperecorder/see_emote(mob/M as mob, text, var/emote_type) diff --git a/code/game/objects/items/devices/translator.dm b/code/game/objects/items/devices/translator.dm index fc6352de29..868481d51e 100644 --- a/code/game/objects/items/devices/translator.dm +++ b/code/game/objects/items/devices/translator.dm @@ -33,8 +33,8 @@ icon_state = "[initial(icon_state)]" to_chat(user, "You disable \the [src].") -/obj/item/device/universal_translator/hear_talk(var/mob/speaker, var/message, var/vrb, var/datum/language/language) - if(!listening || !istype(speaker)) +/obj/item/device/universal_translator/hear_talk(mob/M, list/message_pieces, verb) + if(!listening || !istype(M)) return //Show the "I heard something" animation. @@ -46,34 +46,38 @@ return var/mob/living/L = loc + if(visual && ((L.sdisabilities & BLIND) || L.eye_blind)) + return + if(audio && ((L.sdisabilities & DEAF) || L.ear_deaf)) + return - if(!language) - return //Borgs were causing runtimes when passing language=null + // Using two for loops kinda sucks, but I think it's more efficient + // to shortcut past string building if we're just going to discard the string + // anyways. + if(user_understands(M, L, message_pieces)) + return - if (language && (language.flags & NONVERBAL)) - return //Not gonna translate sign language + var/new_message = "" - if (!language.machine_understands) - return //Any other languages that it can't translate. + for(var/datum/multilingual_say_piece/S in message_pieces) + if(S.speaking.flags & NONVERBAL) + continue + if(!S.speaking.machine_understands) + new_message += stars(S.message) + " " + continue - if (visual && ((L.sdisabilities & BLIND) || L.eye_blind)) - return //Can't see the screen, don't get the message + new_message += (S.message + " ") - if (audio && ((L.sdisabilities & DEAF) || L.ear_deaf)) - return //Can't hear the translation, don't get the message + if(!L.say_understands(null, langset)) + new_message = langset.scramble(new_message) - //Only translate if they can't understand, otherwise pointlessly spammy - //I'll just assume they don't look at the screen in that case + to_chat(L, "[src] translates, \"[new_message]\"") - //They don't understand the spoken language we're translating FROM - if(!L.say_understands(speaker,language)) - //They understand the output language - if(L.say_understands(null,langset)) - to_chat(L, "[src] translates, \"[message]\"") - - //They don't understand the output language - else - to_chat(L, "[src] translates, \"[langset.scramble(message)]\"") +/obj/item/device/universal_translator/proc/user_understands(mob/M, mob/living/L, list/message_pieces) + for(var/datum/multilingual_say_piece/S in message_pieces) + if(S.speaking && !L.say_understands(M, S.speaking)) + return FALSE + return TRUE //Let's try an ear-worn version /obj/item/device/universal_translator/ear diff --git a/code/game/objects/items/devices/tvcamera.dm b/code/game/objects/items/devices/tvcamera.dm index 3fdaa5e79f..67bafbc1bd 100644 --- a/code/game/objects/items/devices/tvcamera.dm +++ b/code/game/objects/items/devices/tvcamera.dm @@ -38,9 +38,9 @@ radio.icon_state = src.icon_state update_icon() -/obj/item/device/tvcamera/hear_talk(mob/living/M, msg, var/verb="says", datum/language/speaking=null) - radio.hear_talk(M,msg,verb,speaking) - ..() +/obj/item/device/tvcamera/hear_talk(mob/M, list/message_pieces, verb) + radio.hear_talk(M, message_pieces, verb) + . = ..() /obj/item/device/tvcamera/attack_self(mob/user) add_fingerprint(user) diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index 0de385500e..34f44ffc8d 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -227,7 +227,8 @@ Implant Specifics:
"} Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} return dat -/obj/item/weapon/implant/explosive/hear_talk(mob/M as mob, msg) +/obj/item/weapon/implant/explosive/hear_talk(mob/M, list/message_pieces, verb) + var/msg = multilingual_to_message(message_pieces) hear(msg) return diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index faafdb62f3..a14a62eaa8 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -162,9 +162,9 @@ /obj/proc/hides_under_flooring() return 0 -/obj/proc/hear_talk(mob/M as mob, text, verb, datum/language/speaking) +/obj/proc/hear_talk(mob/M, list/message_pieces, verb) if(talking_atom) - talking_atom.catchMessage(text, M) + talking_atom.catchMessage(multilingual_to_message(message_pieces), M) /* var/mob/mo = locate(/mob) in src if(mo) diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm index c95d2869e9..3806bd60ba 100644 --- a/code/modules/assembly/holder.dm +++ b/code/modules/assembly/holder.dm @@ -155,11 +155,11 @@ master.receive_signal() return 1 -/obj/item/device/assembly_holder/hear_talk(mob/living/M as mob, msg, verb, datum/language/speaking) +/obj/item/device/assembly_holder/hear_talk(mob/M, list/message_pieces, verb) if(a_right) - a_right.hear_talk(M,msg,verb,speaking) + a_right.hear_talk(M, message_pieces, verb) if(a_left) - a_left.hear_talk(M,msg,verb,speaking) + a_left.hear_talk(M, message_pieces, verb) /obj/item/device/assembly_holder/timer_igniter name = "timer-igniter assembly" diff --git a/code/modules/assembly/voice.dm b/code/modules/assembly/voice.dm index 8ebf8278a8..8990e01d63 100644 --- a/code/modules/assembly/voice.dm +++ b/code/modules/assembly/voice.dm @@ -7,7 +7,8 @@ var/listening = 0 var/recorded //the activation message -/obj/item/device/assembly/voice/hear_talk(mob/living/M as mob, msg) +/obj/item/device/assembly/voice/hear_talk(mob/M, list/message_pieces, verb) + var/msg = multilingual_to_message(message_pieces) if(listening) recorded = msg listening = 0 diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm index 37504035c0..a084633642 100644 --- a/code/modules/integrated_electronics/subtypes/input.dm +++ b/code/modules/integrated_electronics/subtypes/input.dm @@ -527,13 +527,15 @@ listening_objects -= src return ..() -/obj/item/integrated_circuit/input/microphone/hear_talk(mob/living/M, msg, var/verb="says", datum/language/speaking=null) +/obj/item/integrated_circuit/input/microphone/hear_talk(mob/M, list/message_pieces, verb) + var/msg = multilingual_to_message(message_pieces, requires_machine_understands = TRUE) + var/translated = FALSE if(M && msg) - if(speaking) - if(!speaking.machine_understands) - msg = speaking.scramble(msg) - if(!istype(speaking, /datum/language/common)) + for(var/datum/multilingual_say_piece/S in message_pieces) + // S.speaking && here is not redundant, it's preventing `S.speaking = null` from flagging + // as a translation, when it is not. + if(S.speaking && !istype(S.speaking, /datum/language/common)) translated = TRUE set_pin_data(IC_OUTPUT, 1, M.GetVoice()) set_pin_data(IC_OUTPUT, 2, msg) @@ -577,25 +579,41 @@ var/datum/language/newlang = GLOB.all_languages[lang] my_langs |= newlang -/obj/item/integrated_circuit/input/microphone/sign/hear_talk(mob/living/M, msg, var/verb="says", datum/language/speaking=null) +/obj/item/integrated_circuit/input/microphone/sign/hear_talk(mob/M, list/message_pieces, verb) + var/msg = multilingual_to_message(message_pieces) + var/translated = FALSE if(M && msg) - if(speaking) - if(!((speaking.flags & NONVERBAL) || (speaking.flags & SIGNLANG))) - translated = TRUE - msg = speaking.scramble(msg, my_langs) + for(var/datum/multilingual_say_piece/S in message_pieces) + if(S.speaking) + if(!((S.speaking.flags & NONVERBAL) || (S.speaking.flags & SIGNLANG))) + translated = TRUE + msg = stars(msg) + break set_pin_data(IC_OUTPUT, 1, M.GetVoice()) set_pin_data(IC_OUTPUT, 2, msg) push_data() if(!translated) activate_pin(1) - if(translated) + else activate_pin(2) /obj/item/integrated_circuit/input/microphone/sign/hear_signlang(text, verb, datum/language/speaking, mob/M as mob) - hear_talk(M, text, verb, speaking) - return + var/translated = FALSE + if(M && text) + if(speaking) + if(!((speaking.flags & NONVERBAL) || (speaking.flags & SIGNLANG))) + translated = TRUE + text = speaking.scramble(text, my_langs) + set_pin_data(IC_OUTPUT, 1, M.GetVoice()) + set_pin_data(IC_OUTPUT, 2, text) + + push_data() + if(!translated) + activate_pin(1) + else + activate_pin(2) /obj/item/integrated_circuit/input/sensor name = "sensor" diff --git a/code/modules/mob/dead/observer/say.dm b/code/modules/mob/dead/observer/say.dm index dc44a55168..49ab8f2710 100644 --- a/code/modules/mob/dead/observer/say.dm +++ b/code/modules/mob/dead/observer/say.dm @@ -1,63 +1,42 @@ -/mob/observer/dead/say(var/message) +/mob/observer/dead/say(var/message, var/datum/language/speaking = null, var/whispering = 0) message = sanitize(message) - if (!message) - return - - log_ghostsay(message, src) - - if (src.client) - if(message) - client.handle_spam_prevention(MUTE_DEADCHAT) - if(src.client.prefs.muted & MUTE_DEADCHAT) - to_chat(src, "You cannot talk in deadchat (muted).") - return - - . = src.say_dead(message) - - -/mob/observer/dead/emote(var/act, var/type, var/message) - //message = sanitize(message) - already sanitized in verb/me_verb() - if(!message) return - if(act != "me") + log_ghostsay(message, src) + + if (client) + if(message) + client.handle_spam_prevention(MUTE_DEADCHAT) + if(client.prefs.muted & MUTE_DEADCHAT) + to_chat(src, "You cannot talk in deadchat (muted).") + return + + . = say_dead(message) + + +/mob/observer/dead/me_verb(message as text) + if(!message) return log_ghostemote(message, src) - if(src.client) + if(client) if(message) client.handle_spam_prevention(MUTE_DEADCHAT) - if(src.client.prefs.muted & MUTE_DEADCHAT) + if(client.prefs.muted & MUTE_DEADCHAT) to_chat(src, "You cannot emote in deadchat (muted).") return - . = src.emote_dead(message) + . = emote_dead(message) -/* - for (var/mob/M in hearers(null, null)) - if (!M.stat) - if(M.job == "Chaplain") - if (prob (49)) - M.show_message("You hear muffled speech... but nothing is there...", 2) - if(prob(20)) - playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) - else - M.show_message("You hear muffled speech... you can almost make out some words...", 2) -// M.show_message("[stutter(message)]", 2) - if(prob(30)) - playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) - else - if (prob(50)) - return - else if (prob (95)) - M.show_message("You hear muffled speech... but nothing is there...", 2) - if(prob(20)) - playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) - else - M.show_message("You hear muffled speech... you can almost make out some words...", 2) -// M.show_message("[stutter(message)]", 2) - playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) -*/ +/mob/observer/dead/handle_track(message, verb = "says", mob/speaker = null, speaker_name, hard_to_hear) + return "[speaker_name] ([ghost_follow_link(speaker, src)])" + +/mob/observer/dead/handle_speaker_name(mob/speaker = null, vname, hard_to_hear) + var/speaker_name = ..() + //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs. + if(speaker && (speaker_name != speaker.real_name) && !isAI(speaker)) + speaker_name = "[speaker.real_name] ([speaker_name])" + return speaker_name \ No newline at end of file diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm index fa2784116a..ff08be434a 100644 --- a/code/modules/mob/hear_say.dm +++ b/code/modules/mob/hear_say.dm @@ -1,54 +1,96 @@ // At minimum every mob has a hear_say proc. +/mob/proc/combine_message(var/list/message_pieces, var/verb, var/mob/speaker, always_stars = FALSE, var/radio = FALSE) + var/iteration_count = 0 + var/msg = "" // This is to make sure that the pieces have actually added something + . = "[verb], \"" + for(var/datum/multilingual_say_piece/SP in message_pieces) + iteration_count++ + var/piece = SP.message + if(piece == "") + continue -/mob/proc/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + if(SP.speaking && SP.speaking.flags & INNATE) // Snowflake for noise lang + if(radio) + return SP.speaking.format_message_radio(piece) + else + return SP.speaking.format_message(piece) + + if(iteration_count == 1) + piece = capitalize(piece) + + if(always_stars) + piece = stars(piece) + else if(!say_understands(speaker, SP.speaking)) + piece = saypiece_scramble(SP) + if(isliving(speaker)) + var/mob/living/S = speaker + if(istype(S.say_list) && length(S.say_list.speak)) + piece = pick(S.say_list.speak) + + if(!SP.speaking) // Catch the most generic case first + piece = "[piece]" + else if(radio) // SP.speaking == TRUE enforced by previous !SP.speaking + piece = SP.speaking.format_message_radio(piece) + else // SP.speaking == TRUE && radio == FALSE + piece = SP.speaking.format_message(piece) + + msg += (piece + " ") + + if(msg == "") + // There is literally no content left in this message, we need to shut this shit down + . = "" // hear_say will suppress it + else + . = trim(. + trim(msg)) + . += "\"" + +/mob/proc/saypiece_scramble(datum/multilingual_say_piece/SP) + if(SP.speaking) + return SP.speaking.scramble(SP.message) + else + return stars(SP.message) + +/mob/proc/hear_say(var/list/message_pieces, var/verb = "says", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) if(!client && !teleop) - return + return FALSE - if(speaker && !speaker.client && istype(src,/mob/observer/dead) && is_preference_enabled(/datum/client_preference/ghost_ears) && !(speaker in view(src))) + if(isobserver(src) && is_preference_enabled(/datum/client_preference/ghost_ears)) + if(speaker && !speaker.client && !(speaker in view(src))) //Does the speaker have a client? It's either random stuff that observers won't care about (Experiment 97B says, 'EHEHEHEHEHEHEHE') //Or someone snoring. So we make it where they won't hear it. - return + return FALSE //make sure the air can transmit speech - hearer's side var/turf/T = get_turf(src) - if ((T) && (!(istype(src, /mob/observer/dead)))) //Ghosts can hear even in vacuum. + if(T && !isobserver(src)) //Ghosts can hear even in vacuum. var/datum/gas_mixture/environment = T.return_air() - var/pressure = (environment)? environment.return_pressure() : 0 + var/pressure = environment ? environment.return_pressure() : 0 if(pressure < SOUND_MINIMUM_PRESSURE && get_dist(speaker, src) > 1) - return + return FALSE - 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 + 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(sleeping || stat == 1) - hear_sleep(message) - return - - //non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet. - if (language && (language.flags & NONVERBAL)) - if (!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src))) - message = stars(message) - - if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages - if(!say_understands(speaker,language)) - if(language) - message = language.scramble(message, languages) - else - message = stars(message) - var/speaker_name = speaker.name - if(istype(speaker, /mob/living/carbon/human)) + if(ishuman(speaker)) var/mob/living/carbon/human/H = speaker speaker_name = H.GetVoice() + var/message = combine_message(message_pieces, verb, speaker) + if(message == "") + return + + if(sleeping || stat == UNCONSCIOUS) + hear_sleep(message) + return FALSE + if(italics) message = "[message]" message = encode_html_emphasis(message) var/track = null - if(istype(src, /mob/observer/dead)) + if(isobserver(src)) if(italics && is_preference_enabled(/datum/client_preference/ghost_radio)) return if(speaker_name != speaker.real_name && speaker.real_name) @@ -58,31 +100,27 @@ message = "[message]" if(is_deaf()) - if(!language || !(language.flags & INNATE)) // INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set - if(speaker == src) - to_chat(src, "You cannot hear yourself speak!") - else - to_chat(src, "[speaker_name][alt_name] talks but you cannot hear.") + if(speaker == src) + to_chat(src, "You cannot hear yourself speak!") + else + to_chat(src, "[speaker_name][speaker.GetAltName()] makes a noise, possibly speech, but you cannot hear them.") else var/message_to_send = null - if(language) - message_to_send = "[speaker_name][alt_name] [track][language.format_message(message, verb)]" - else - message_to_send = "[speaker_name][alt_name] [track][verb], \"[message]\"" - if(check_mentioned(message) && is_preference_enabled(/datum/client_preference/check_mention)) + message_to_send = "[speaker_name][speaker.GetAltName()] [track][message]" + if(check_mentioned(multilingual_to_message(message_pieces)) && is_preference_enabled(/datum/client_preference/check_mention)) message_to_send = "[message_to_send]" on_hear_say(message_to_send) - if (speech_sound && (get_dist(speaker, src) <= world.view && src.z == speaker.z)) - var/turf/source = speaker? get_turf(speaker) : get_turf(src) - src.playsound_local(source, speech_sound, sound_vol, 1) + if(speech_sound && (get_dist(speaker, src) <= world.view && z == speaker.z)) + var/turf/source = speaker ? get_turf(speaker) : get_turf(src) + playsound_local(source, speech_sound, sound_vol, 1) // Done here instead of on_hear_say() since that is NOT called if the mob is clientless (which includes most AI mobs). -/mob/living/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) +/mob/living/hear_say(var/list/message_pieces, var/verb = "says", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) ..() if(has_AI()) // Won't happen if no ai_holder exists or there's a player inside w/o autopilot active. - ai_holder.on_hear_say(speaker, message) + ai_holder.on_hear_say(speaker, multilingual_to_message(message_pieces)) /mob/proc/on_hear_say(var/message) to_chat(src, message) @@ -124,114 +162,25 @@ return tagged_message -/mob/proc/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="") - +/mob/proc/hear_radio(var/list/message_pieces, var/verb = "says", var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname = "") if(!client) return - if(sleeping || stat==1) //If unconscious or sleeping + var/message = combine_message(message_pieces, verb, speaker, always_stars = hard_to_hear, radio = TRUE) + if(sleeping || stat == UNCONSCIOUS) //If unconscious or sleeping hear_sleep(message) return - var/track = null - - //non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet. - if (language && (language.flags & NONVERBAL)) - if (!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src))) - message = stars(message) - - if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages - if(!say_understands(speaker,language)) - if(language) - message = language.scramble(message, languages) - else - message = stars(message) - - if(hard_to_hear) - message = stars(message) - - var/speaker_name = speaker.name - - if(vname) - speaker_name = vname - - if(istype(speaker, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = speaker - if(H.voice) - speaker_name = H.voice - - if(hard_to_hear) - speaker_name = "unknown" - - var/changed_voice - - if(istype(src, /mob/living/silicon/ai) && !hard_to_hear) - var/jobname // the mob's "job" - var/mob/living/carbon/human/impersonating //The crew member being impersonated, if any. - - if (ishuman(speaker)) - var/mob/living/carbon/human/H = speaker - - if(H.wear_mask && istype(H.wear_mask,/obj/item/clothing/mask/gas/voice)) - changed_voice = 1 - var/list/impersonated = new() - var/mob/living/carbon/human/I = impersonated[speaker_name] - - if(!I) - for(var/mob/living/carbon/human/M in mob_list) - if(M.real_name == speaker_name) - I = M - impersonated[speaker_name] = I - break - - // If I's display name is currently different from the voice name and using an agent ID then don't impersonate - // as this would allow the AI to track I and realize the mismatch. - if(I && !(I.name != speaker_name && I.wear_id && istype(I.wear_id,/obj/item/weapon/card/id/syndicate))) - impersonating = I - jobname = impersonating.get_assignment() - else - jobname = "Unknown" - else - jobname = H.get_assignment() - - else if (iscarbon(speaker)) // Nonhuman carbon mob - jobname = "No id" - else if (isAI(speaker)) - jobname = "AI" - else if (isrobot(speaker)) - jobname = "Cyborg" - else if (istype(speaker, /mob/living/silicon/pai)) - jobname = "Personal AI" - else - jobname = "Unknown" - - if(changed_voice) - if(impersonating) - track = "[speaker_name] ([jobname])" - else - track = "[speaker_name] ([jobname])" - else - track = "[speaker_name] ([jobname])" - - if(istype(src, /mob/observer/dead)) - if(speaker_name != speaker.real_name && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs. - speaker_name = "[speaker.real_name] ([speaker_name])" - track = "[speaker_name] ([ghost_follow_link(speaker, src)])" + var/speaker_name = handle_speaker_name(speaker, vname, hard_to_hear) + var/track = handle_track(message, verb, speaker, speaker_name, hard_to_hear) message = encode_html_emphasis(message) - var/formatted - if(language) - formatted = "[language.format_message_radio(message, verb)][part_c]" - else - formatted = "[verb], \"[message]\"[part_c]" - - if((sdisabilities & DEAF) || ear_deaf) if(prob(20)) to_chat(src, "You feel your headset vibrate but can hear nothing from it!") else - on_hear_radio(part_a, speaker_name, track, part_b, formatted) + on_hear_radio(part_a, speaker_name, track, part_b, message) /proc/say_timestamp() return "\[[stationtime2text()]\]" @@ -296,9 +245,40 @@ heardword = copytext(heardword,2) if(copytext(heardword,-1) in punctuation) heardword = copytext(heardword,1,length(heardword)) - heard = "...You hear something about...[heardword]" + heard = "...You hear something about...[heardword]" else - heard = "...You almost hear someone talking..." + heard = "...You almost hear someone talking..." - to_chat(src,heard) + to_chat(src, heard) + +/mob/proc/handle_speaker_name(mob/speaker, vname, hard_to_hear) + var/speaker_name = "unknown" + if(speaker) + speaker_name = speaker.name + + if(ishuman(speaker)) + var/mob/living/carbon/human/H = speaker + if(H.voice) + speaker_name = H.voice + + if(vname) + speaker_name = vname + + if(hard_to_hear) + speaker_name = "unknown" + + return speaker_name + +/mob/proc/handle_track(message, verb = "says", mob/speaker = null, speaker_name, hard_to_hear) + return + +/mob/proc/hear_holopad_talk(list/message_pieces, var/verb = "says", var/mob/speaker = null) + var/message = combine_message(message_pieces, verb, speaker) + + var/name = speaker.name + if(!say_understands(speaker)) + name = speaker.voice_name + + var/rendered = "[name] [message]" + to_chat(src, rendered) \ No newline at end of file diff --git a/code/modules/mob/language/generic.dm b/code/modules/mob/language/generic.dm index 8fa9efcd73..03daea6197 100644 --- a/code/modules/mob/language/generic.dm +++ b/code/modules/mob/language/generic.dm @@ -5,12 +5,6 @@ key = "" flags = RESTRICTED|NONGLOBAL|INNATE|NO_TALK_MSG|NO_STUTTER -/datum/language/noise/format_message(message, verb) - return "[message]" - -/datum/language/noise/format_message_plain(message, verb) - return message - /datum/language/noise/format_message_radio(message, verb) return "[message]" @@ -143,6 +137,17 @@ var/obj/item/organ/external/hand/hands = locate() in speaker //you can't sign without hands return (hands || !iscarbon(speaker)) +/datum/language/sign/scramble(var/input, var/list/known_languages) + return stars(input) + +// This is a little weird because broadcast is traditionally for hivemind languages +// But in practice, it's just a way for a language to override all other languages and bypass hear_say +// which is exactly what sign language does. +/datum/language/sign/broadcast(var/mob/living/speaker, var/message, var/speaker_mask) + log_say("(SIGN) [message]", speaker) + speaker.say_signlang(message, pick(signlang_verb), src) + + // Silly language for those times when you try to talk a languague you normally can't /datum/language/gibberish name = LANGUAGE_GIBBERISH diff --git a/code/modules/mob/language/language.dm b/code/modules/mob/language/language.dm index 215376cd44..14d6fb853d 100644 --- a/code/modules/mob/language/language.dm +++ b/code/modules/mob/language/language.dm @@ -113,13 +113,13 @@ return scrambled_text /datum/language/proc/format_message(message, verb) - return "[verb], \"[capitalize(message)]\"" + return "[message]" /datum/language/proc/format_message_plain(message, verb) - return "[verb], \"[capitalize(message)]\"" + return "[capitalize(message)]" /datum/language/proc/format_message_radio(message, verb) - return "[verb], \"[capitalize(message)]\"" + return "[capitalize(message)]" /datum/language/proc/get_talkinto_msg_range(message) // if you yell, you'll be heard from two tiles over instead of one @@ -129,7 +129,7 @@ log_say("(HIVE) [message]", speaker) if(!speaker_mask) speaker_mask = speaker.name - message = format_message(message, get_spoken_verb(message)) + message = "[get_spoken_verb(message)], \"[format_message(message, get_spoken_verb(message))]\"" for(var/mob/player in player_list) player.hear_broadcast(src, speaker, speaker_mask, message) @@ -233,36 +233,36 @@ return prefix in config.language_prefixes //TBD +/mob/proc/check_lang_data() + . = "" + + for(var/datum/language/L in languages) + if(!(L.flags & NONGLOBAL)) + . += "[L.name] ([get_language_prefix()][L.key])
[L.desc]

" + +/mob/living/check_lang_data() + . = "" + + if(default_language) + . += "Current default language: [default_language] - reset

" + + for(var/datum/language/L in languages) + if(!(L.flags & NONGLOBAL)) + if(L == default_language) + . += "[L.name] ([get_language_prefix()][L.key]) - default - reset
[L.desc]

" + else if (can_speak(L)) + . += "[L.name] ([get_language_prefix()][L.key]) - set default
[L.desc]

" + else + . += "[L.name] ([get_language_prefix()][L.key]) - cannot speak!
[L.desc]

" + /mob/verb/check_languages() set name = "Check Known Languages" set category = "IC" set src = usr - var/dat = "Known Languages

" - - for(var/datum/language/L in languages) - if(!(L.flags & NONGLOBAL)) - dat += "[L.name] ([get_language_prefix()][L.key])
[L.desc]

" - - src << browse(dat, "window=checklanguage") - return - -/mob/living/check_languages() - var/dat = "Known Languages

" - - if(default_language) - dat += "Current default language: [default_language] - reset

" - - for(var/datum/language/L in languages) - if(!(L.flags & NONGLOBAL)) - if(L == default_language) - dat += "[L.name] ([get_language_prefix()][L.key]) - default - reset
[L.desc]

" - else if (can_speak(L)) - dat += "[L.name] ([get_language_prefix()][L.key]) - set default
[L.desc]

" - else - dat += "[L.name] ([get_language_prefix()][L.key]) - cannot speak!
[L.desc]

" - - src << browse(dat, "window=checklanguage") + var/datum/browser/popup = new(src, "checklanguage", "Known Languages", 420, 470) + popup.set_content(check_lang_data()) + popup.open() /mob/living/Topic(href, href_list) if(href_list["default_lang"]) diff --git a/code/modules/mob/language/station.dm b/code/modules/mob/language/station.dm index 93959c2f1f..d2ed3a3890 100644 --- a/code/modules/mob/language/station.dm +++ b/code/modules/mob/language/station.dm @@ -94,6 +94,10 @@ key = "l" flags = WHITELISTED | SIGNLANG | NO_STUTTER | NONVERBAL +/datum/language/tajsign/broadcast(var/mob/living/speaker, var/message, var/speaker_mask) + log_say("(SIGN) [message]", speaker) + speaker.say_signlang(message, pick(signlang_verb), src) + /datum/language/tajsign/can_speak_special(var/mob/speaker) // TODO: If ever we make external organs assist languages, convert this over to the new format var/list/allowed_species = list(SPECIES_TAJ, SPECIES_TESHARI) // Need a tail and ears and such to use this. if(iscarbon(speaker)) diff --git a/code/modules/mob/living/autohiss.dm b/code/modules/mob/living/autohiss.dm index 4ee08dec85..7a3999ea36 100644 --- a/code/modules/mob/living/autohiss.dm +++ b/code/modules/mob/living/autohiss.dm @@ -6,7 +6,7 @@ #define AUTOHISS_NUM 3 -/mob/living/proc/handle_autohiss(message, datum/language/L) +/mob/proc/handle_autohiss(message, datum/language/L) return message // no autohiss at this level /mob/living/carbon/human/handle_autohiss(message, datum/language/L) diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index 5e9f496646..4ea28b3eea 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -144,12 +144,8 @@ /mob/living/bot/attack_ai(var/mob/user) return attack_hand(user) -/mob/living/bot/say(var/message) - var/verb = "beeps" - - message = sanitize(message) - - ..(message, null, verb) +/mob/living/bot/say_quote(var/message, var/datum/language/speaking = null) + return "beeps" /mob/living/bot/speech_bubble_appearance() return "machine" diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 42f7dece0c..149eba55eb 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -1,5 +1,4 @@ /mob/living/carbon/alien - name = "alien" desc = "What IS that?" icon = 'icons/mob/alien.dmi' @@ -52,4 +51,23 @@ return //Consider adding cuffs and hats to this, for the sake of fun. /mob/living/carbon/alien/cannot_use_vents() - return \ No newline at end of file + return + +/mob/living/carbon/alien/get_default_language() + if(default_language) + return default_language + return GLOB.all_languages["Xenomorph"] + +/mob/living/carbon/alien/say_quote(var/message, var/datum/language/speaking = null) + var/verb = "hisses" + var/ending = copytext(message, length(message)) + + if(speaking && (speaking.name != "Galactic Common")) //this is so adminbooze xenos speaking common have their custom verbs, + verb = speaking.get_spoken_verb(ending) //and use normal verbs for their own languages and non-common languages + else + if(ending == "!") + verb = "roars" + else if(ending == "?") + verb = "hisses curiously" + return verb + diff --git a/code/modules/mob/living/carbon/alien/diona/say_understands.dm b/code/modules/mob/living/carbon/alien/diona/say_understands.dm index 3f68a44cff..b42109059e 100644 --- a/code/modules/mob/living/carbon/alien/diona/say_understands.dm +++ b/code/modules/mob/living/carbon/alien/diona/say_understands.dm @@ -1,6 +1,5 @@ -/mob/living/carbon/alien/diona/say_understands(var/mob/other,var/datum/language/speaking = null) - - if (istype(other, /mob/living/carbon/human) && !speaking) +/mob/living/carbon/alien/diona/say_understands(var/mob/other, var/datum/language/speaking = null) + if(ishuman(other) && !speaking) if(languages.len >= 2) // They have sucked down some blood. - return 1 + return TRUE return ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/emote.dm b/code/modules/mob/living/carbon/alien/emote.dm index 8b4744bdc3..6c9cca88fb 100644 --- a/code/modules/mob/living/carbon/alien/emote.dm +++ b/code/modules/mob/living/carbon/alien/emote.dm @@ -1,131 +1,107 @@ -/mob/living/carbon/alien/emote(var/act,var/m_type=1,var/message = null) - +/mob/living/carbon/alien/emote(var/act, var/m_type=1, var/message = null) var/param = null - if (findtext(act, "-", 1, null)) + if(findtext(act, "-", 1, null)) var/t1 = findtext(act, "-", 1, null) param = copytext(act, t1 + 1, length(act) + 1) act = copytext(act, 1, t1) - if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_' - act = copytext(act,1,length(act)) var/muzzled = is_muzzled() switch(act) - if ("me") - if(silent) - return - if (src.client) - if (client.prefs.muted & MUTE_IC) - to_chat(src, "You cannot send IC messages (muted).") - return - if (stat) - return - if(!(message)) - return - return custom_emote(m_type, message) - - if ("custom") - return custom_emote(m_type, message) if("sign") - if (!src.restrained()) - message = text("The alien signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null)) - m_type = 1 - if ("burp") - if (!muzzled) + if(!restrained()) + var/num = null + if(text2num(param)) + num = "the number [text2num(param)]" + if(num) + message = "[src] signs [num]." + m_type = 1 + if("burp") + if(!muzzled) message = "[src] burps." m_type = 2 if("deathgasp") - message = "The [src.name] lets out a waning guttural screech, green blood bubbling from its maw." + message = "[src] lets out a waning guttural screech, green blood bubbling from its maw." m_type = 2 if("scratch") - if (!src.restrained()) - message = "The [src.name] scratches." + if(!restrained()) + message = "[src] scratches." m_type = 1 if("whimper") - if (!muzzled) - message = "The [src.name] whimpers." + if(!muzzled) + message = "[src] whimpers." m_type = 2 if("tail") - message = "The [src.name] waves its tail." + message = "[src] waves its tail." m_type = 1 if("gasp") - message = "The [src.name] gasps." + message = "[src] gasps." m_type = 2 if("shiver") - message = "The [src.name] shivers." + message = "[src] shivers." m_type = 2 if("drool") - message = "The [src.name] drools." + message = "[src] drools." m_type = 1 if("scretch") - if (!muzzled) - message = "The [src.name] scretches." + if(!muzzled) + message = "[src] scretches." m_type = 2 if("choke") - message = "The [src.name] chokes." + message = "[src] chokes." m_type = 2 if("moan") - message = "The [src.name] moans!" + message = "[src] moans!" m_type = 2 if("nod") - message = "The [src.name] nods its head." + message = "[src] nods its head." m_type = 1 // if("sit") -// message = "The [src.name] sits down." //Larvan can't sit down, /N +// message = "[src] sits down." //Larvan can't sit down, /N // m_type = 1 if("sway") - message = "The [src.name] sways around dizzily." + message = "[src] sways around dizzily." m_type = 1 if("sulk") - message = "The [src.name] sulks down sadly." + message = "[src] sulks down sadly." m_type = 1 if("twitch") - message = "The [src.name] twitches." + message = "[src] twitches." m_type = 1 if("twitch_v") - message = "The [src.name] twitches violently." + message = "[src] twitches violently." m_type = 1 if("dance") - if (!src.restrained()) - message = "The [src.name] dances around happily." + if(!restrained()) + message = "[src] dances around happily." m_type = 1 if("roll") - if (!src.restrained()) - message = "The [src.name] rolls." + if(!restrained()) + message = "[src] rolls." m_type = 1 if("shake") - message = "The [src.name] shakes its head." + message = "[src] shakes its head." m_type = 1 if("gnarl") - if (!muzzled) - message = "The [src.name] gnarls and shows its teeth.." + if(!muzzled) + message = "[src] gnarls and shows its teeth.." m_type = 2 if("jump") - message = "The [src.name] jumps!" + message = "[src] jumps!" m_type = 1 if("hiss_") - message = "The [src.name] hisses softly." + message = "[src] hisses softly." m_type = 1 if("collapse") Paralyse(2) - message = text("[] collapses!", src) + message = "[src] collapses!" m_type = 2 if("chirp") - message = "The [src.name] chirps!" - playsound(src.loc, 'sound/misc/nymphchirp.ogg', 50, 0) + message = "[src] chirps!" + playsound(loc, 'sound/misc/nymphchirp.ogg', 50, 0) m_type = 2 if("help") - to_chat(src, "burp, chirp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, twitch, whimper") - else - to_chat(src, "Invalid Emote: [act]") - if ((message && src.stat == 0)) - log_emote(message, src) - if (m_type & 1) - for(var/mob/O in viewers(src, null)) - O.show_message(message, m_type) - //Foreach goto(703) - else - for(var/mob/O in hearers(src, null)) - O.show_message(message, m_type) - //Foreach goto(746) - return \ No newline at end of file + to_chat(src, "burp, chirp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, twitch, whimper") + + if(!stat) + ..(act, m_type, message) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/say.dm b/code/modules/mob/living/carbon/alien/say.dm deleted file mode 100644 index 8621339927..0000000000 --- a/code/modules/mob/living/carbon/alien/say.dm +++ /dev/null @@ -1,25 +0,0 @@ -/mob/living/carbon/alien/say(var/message) - var/verb = "says" - var/message_range = world.view - - if(client) - if(client.prefs.muted & MUTE_IC) - to_chat(src, "You cannot speak in IC (Muted).") - return - - message = sanitize(message) - - if(stat == 2) - return say_dead(message) - - if(copytext(message,1,2) == "*") - return emote(copytext(message,2)) - - var/datum/language/speaking = parse_language(message) - - message = trim(message) - - if(!message || stat) - return - - ..(message, speaking, verb, null, null, message_range, null) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm index a75deb25d0..a8a0b8fb01 100644 --- a/code/modules/mob/living/carbon/brain/brain.dm +++ b/code/modules/mob/living/carbon/brain/brain.dm @@ -18,36 +18,19 @@ /mob/living/carbon/brain/Destroy() if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting. - if(stat!=DEAD) //If not dead. + if(stat != DEAD) //If not dead. death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA ghostize() //Ghostize checks for key so nothing else is necessary. return ..() /mob/living/carbon/brain/say_understands(var/other)//Goddamn is this hackish, but this say code is so odd - if (istype(other, /mob/living/silicon/ai)) - if(!(container && istype(container, /obj/item/device/mmi))) - return 0 - else - return 1 - if (istype(other, /mob/living/silicon/decoy)) - if(!(container && istype(container, /obj/item/device/mmi))) - return 0 - else - return 1 - if (istype(other, /mob/living/silicon/pai)) - if(!(container && istype(container, /obj/item/device/mmi))) - return 0 - else - return 1 - if (istype(other, /mob/living/silicon/robot)) - if(!(container && istype(container, /obj/item/device/mmi))) - return 0 - else - return 1 - if (istype(other, /mob/living/carbon/human)) - return 1 - if (istype(other, /mob/living/simple_mob/slime)) - return 1 + if(istype(container, /obj/item/device/mmi)) + if(issilicon(other)) + return TRUE + if(ishuman(other)) + return TRUE + if(isslime(other)) + return TRUE return ..() /mob/living/carbon/brain/update_canmove() diff --git a/code/modules/mob/living/carbon/brain/emote.dm b/code/modules/mob/living/carbon/brain/emote.dm index bc4623647b..05706fe299 100644 --- a/code/modules/mob/living/carbon/brain/emote.dm +++ b/code/modules/mob/living/carbon/brain/emote.dm @@ -2,79 +2,46 @@ if(!(container && istype(container, /obj/item/device/mmi)))//No MMI, no emotes return - if (findtext(act, "-", 1, null)) + if(findtext(act, "-", 1, null)) var/t1 = findtext(act, "-", 1, null) act = copytext(act, 1, t1) - if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_' - act = copytext(act,1,length(act)) - - if(src.stat == DEAD) + if(stat == DEAD) return switch(act) - if ("me") - if(silent) - return - if (src.client) - if (client.prefs.muted & MUTE_IC) - to_chat(src, "You cannot send IC messages (muted).") - return - if (stat) - return - if(!(message)) - return - return custom_emote(m_type, message) - - if ("custom") - return custom_emote(m_type, message) - if ("alarm") + if("alarm") to_chat(src, "You sound an alarm.") message = "[src] sounds an alarm." m_type = 2 - if ("alert") + if("alert") to_chat(src, "You let out a distressed noise.") message = "[src] lets out a distressed noise." m_type = 2 - if ("notice") + if("notice") to_chat(src, "You play a loud tone.") message = "[src] plays a loud tone." m_type = 2 - if ("flash") + if("flash") message = "The lights on [src] flash quickly." m_type = 1 - if ("blink") + if("blink") message = "[src] blinks." m_type = 1 - if ("whistle") + if("whistle") to_chat(src, "You whistle.") message = "[src] whistles." m_type = 2 - if ("beep") + if("beep") to_chat(src, "You beep.") message = "[src] beeps." m_type = 2 - if ("boop") + if("boop") to_chat(src, "You boop.") message = "[src] boops." m_type = 2 - if ("help") - to_chat(src, "alarm,alert,notice,flash,blink,whistle,beep,boop") - else - to_chat(src, "Unusable emote '[act]'. Say *help for a list.") + if("help") + to_chat(src, "alarm, alert, notice, flash, blink, whistle, beep, boop") - if (message) - log_emote(message, src) - - for(var/mob/M in dead_mob_list) - if (!M.client || istype(M, /mob/new_player)) - continue //skip monkeys, leavers, and new_players - if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_sight) && !(M in viewers(src,null))) - M.show_message(message) - - - if (m_type & 1) - for (var/mob/O in viewers(src, null)) - O.show_message(message, m_type) - else if (m_type & 2) - for (var/mob/O in hearers(src.loc, null)) - O.show_message(message, m_type) \ No newline at end of file + if(!stat) + ..(act, m_type, message) + \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/carbon/brain/say.dm index 0493b2d92d..e03067db1a 100644 --- a/code/modules/mob/living/carbon/brain/say.dm +++ b/code/modules/mob/living/carbon/brain/say.dm @@ -1,6 +1,6 @@ //TODO: Convert this over for languages. -/mob/living/carbon/brain/say(var/message) - if (silent) +/mob/living/carbon/brain/say(var/message, var/datum/language/speaking = null, var/whispering = 0) + if(silent) return message = sanitize(message) @@ -8,39 +8,22 @@ if(!(container && container.can_speak)) return //Certain objects can speak, like MMIs. Most others cannot. -Q else - var/datum/language/speaking = parse_language(message) - if(speaking) - message = copytext(message, 2+length(speaking.key)) - var/verb = "says" - var/ending = copytext(message, length(message)) - if (speaking) - verb = speaking.get_spoken_verb(ending) - else - if(ending=="!") - verb=pick("exclaims","shouts","yells") - if(ending=="?") - verb="asks" - - if(prob(emp_damage*4)) + if(prob(emp_damage * 4)) if(prob(10))//10% chance to drop the message entirely return else message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher - if(speaking && speaking.flags & HIVEMIND) - speaking.broadcast(src,trim(message)) - return + ..() - ..(trim(message), speaking, verb) - -/mob/living/carbon/brain/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) +/mob/living/carbon/brain/handle_message_mode(message_mode, message, verb, speaking, used_radios) ..() if(message_mode) var/obj/item/device/mmi/R = container - if (R.radio && R.radio.radio_enabled) + if(R.radio && R.radio.radio_enabled) if(message_mode == "general") message_mode = null - return R.radio.talk_into(src,message,message_mode,verb,speaking) + return R.radio.talk_into(src, message, message_mode, verb, speaking) else to_chat(src, "Your radio is disabled.") return 0 diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index c0f0e59421..88b74579b1 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -3,29 +3,26 @@ var/datum/gender/T = gender_datums[get_visible_gender()] - if (findtext(act, "-", 1, null)) + if(findtext(act, "-", 1, null)) var/t1 = findtext(act, "-", 1, null) param = copytext(act, t1 + 1, length(act) + 1) act = copytext(act, 1, t1) - if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_' - act = copytext(act,1,length(act)) - var/muzzled = is_muzzled() //var/m_type = 1 for(var/obj/item/organ/O in src.organs) for (var/obj/item/weapon/implant/I in O) - if (I.implanted) + if(I.implanted) I.trigger(act, src) - if(src.stat == 2.0 && (act != "deathgasp")) + if(stat == DEAD && (act != "deathgasp")) return if(attempt_vr(src,"handle_emote_vr",list(act,m_type,message))) return //VOREStation Add - Custom Emote Handler switch(act) - if ("airguitar") - if (!src.restrained()) + if("airguitar") + if(!src.restrained()) message = "is strumming the air and headbanging like a safari chimp." m_type = 1 @@ -39,7 +36,7 @@ var/M = null if(param) for (var/mob/A in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break if(!M) @@ -75,7 +72,7 @@ else use_sound = 'sound/effects/mob_effects/f_machine_sneeze.ogg' - if (param) + if(param) message = "[display_msg] at [param]." else message = "[display_msg]." @@ -103,142 +100,142 @@ message = "warbles." m_type = 2 - if ("blink") + if("blink") message = "blinks." m_type = 1 - if ("blink_r") + if("blink_r") message = "blinks rapidly." m_type = 1 - if ("bow") - if (!src.buckled) + if("bow") + if(!src.buckled) var/M = null - if (param) + if(param) for (var/mob/A in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break - if (!M) + if(!M) param = null - if (param) + if(param) message = "bows to [param]." else message = "bows." m_type = 1 - if ("custom") + if("custom") var/input = sanitize(input("Choose an emote to display.") as text|null) - if (!input) + if(!input) return var/input2 = input("Is this a visible or hearable emote?") in list("Visible","Hearable") - if (input2 == "Visible") + if(input2 == "Visible") m_type = 1 - else if (input2 == "Hearable") - if (src.miming) + else if(input2 == "Hearable") + if(src.miming) return m_type = 2 else alert("Unable to use this emote, must be either hearable or visible.") return - return custom_emote(m_type, message) + return custom_emote(m_type, input) - if ("me") + if("me") //if(silent && silent > 0 && findtext(message,"\"",1, null) > 0) // return //This check does not work and I have no idea why, I'm leaving it in for reference. - if (src.client) - if (client.prefs.muted & MUTE_IC) + if(src.client) + if(client.prefs.muted & MUTE_IC) to_chat(src, "You cannot send IC messages (muted).") return - if (stat) + if(stat) return if(!(message)) return return custom_emote(m_type, message) - if ("salute") - if (!src.buckled) + if("salute") + if(!src.buckled) var/M = null - if (param) + if(param) for (var/mob/A in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break - if (!M) + if(!M) param = null - if (param) + if(param) message = "salutes to [param]." else message = "salutes." m_type = 1 - if ("choke") + if("choke") if(miming) message = "clutches [T.his] throat desperately!" m_type = 1 else - if (!muzzled) + if(!muzzled) message = "chokes!" m_type = 2 else message = "makes a strong noise." m_type = 2 - if ("clap") - if (!src.restrained()) + if("clap") + if(!src.restrained()) message = "claps." playsound(src.loc, 'sound/misc/clapping.ogg') m_type = 2 if(miming) m_type = 1 - if ("flap") - if (!src.restrained()) + if("flap") + if(!src.restrained()) message = "flaps [T.his] wings." m_type = 2 if(miming) m_type = 1 - if ("aflap") - if (!src.restrained()) + if("aflap") + if(!src.restrained()) message = "flaps [T.his] wings ANGRILY!" m_type = 2 if(miming) m_type = 1 - if ("drool") + if("drool") message = "drools." m_type = 1 - if ("eyebrow") + if("eyebrow") message = "raises an eyebrow." m_type = 1 - if ("chuckle") + if("chuckle") if(miming) message = "appears to chuckle." m_type = 1 else - if (!muzzled) + if(!muzzled) message = "chuckles." m_type = 2 else message = "makes a noise." m_type = 2 - if ("twitch") + if("twitch") message = "twitches." m_type = 1 - if ("twitch_v") + if("twitch_v") message = "twitches violently." m_type = 1 - if ("faint") + if("faint") message = "faints." if(src.sleeping) return //Can't faint while asleep @@ -277,167 +274,167 @@ message = "makes a strong noise." m_type = 2 - if ("frown") + if("frown") message = "frowns." m_type = 1 - if ("nod") + if("nod") message = "nods." m_type = 1 - if ("blush") + if("blush") message = "blushes." m_type = 1 - if ("wave") + if("wave") message = "waves." m_type = 1 - if ("gasp") + if("gasp") if(miming) message = "appears to be gasping!" m_type = 1 else - if (!muzzled) + if(!muzzled) message = "gasps!" m_type = 2 else message = "makes a weak noise." m_type = 2 - if ("deathgasp") + if("deathgasp") message = "[species.get_death_message()]" m_type = 1 - if ("giggle") + if("giggle") if(miming) message = "giggles silently!" m_type = 1 else - if (!muzzled) + if(!muzzled) message = "giggles." m_type = 2 else message = "makes a noise." m_type = 2 - if ("glare") + if("glare") var/M = null - if (param) + if(param) for (var/mob/A in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break - if (!M) + if(!M) param = null - if (param) + if(param) message = "glares at [param]." else message = "glares." - if ("stare") + if("stare") var/M = null - if (param) + if(param) for (var/mob/A in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break - if (!M) + if(!M) param = null - if (param) + if(param) message = "stares at [param]." else message = "stares." - if ("look") + if("look") var/M = null - if (param) + if(param) for (var/mob/A in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break - if (!M) + if(!M) param = null - if (param) + if(param) message = "looks at [param]." else message = "looks." m_type = 1 - if ("grin") + if("grin") message = "grins." m_type = 1 - if ("cry") + if("cry") if(miming) message = "cries." m_type = 1 else - if (!muzzled) + if(!muzzled) message = "cries." m_type = 2 else message = "makes a weak noise. [T.he] [get_visible_gender() == NEUTER ? "frown" : "frowns"]." // no good, non-unwieldy alternative to this ternary at the moment m_type = 2 - if ("sigh") + if("sigh") if(miming) message = "sighs." m_type = 1 else - if (!muzzled) + if(!muzzled) message = "sighs." m_type = 2 else message = "makes a weak noise." m_type = 2 - if ("laugh") + if("laugh") if(miming) message = "acts out a laugh." m_type = 1 else - if (!muzzled) + if(!muzzled) message = "laughs." m_type = 2 else message = "makes a noise." m_type = 2 - if ("mumble") + if("mumble") message = "mumbles!" m_type = 2 if(miming) m_type = 1 - if ("grumble") + if("grumble") if(miming) message = "grumbles!" m_type = 1 - if (!muzzled) + if(!muzzled) message = "grumbles!" m_type = 2 else message = "makes a noise." m_type = 2 - if ("groan") + if("groan") if(miming) message = "appears to groan!" m_type = 1 else - if (!muzzled) + if(!muzzled) message = "groans!" m_type = 2 else message = "makes a loud noise." m_type = 2 - if ("moan") + if("moan") if(miming) message = "appears to moan!" m_type = 1 @@ -445,11 +442,11 @@ message = "moans!" m_type = 2 - if ("johnny") + if("johnny") var/M - if (param) + if(param) M = param - if (!M) + if(!M) param = null else if(miming) @@ -459,27 +456,27 @@ message = "says, \"[M], please. He had a family.\" [src.name] takes a drag from a cigarette and blows his name out in smoke." m_type = 2 - if ("point") - if (!src.restrained()) + if("point") + if(!src.restrained()) var/mob/M = null - if (param) + if(param) for (var/atom/A as mob|obj|turf|area in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break - if (!M) + if(!M) message = "points." else pointed(M) - if (M) + if(M) message = "points to [M]." else m_type = 1 - if ("raise") - if (!src.restrained()) + if("raise") + if(!src.restrained()) message = "raises a hand." m_type = 1 @@ -487,35 +484,35 @@ message = "shakes [T.his] head." m_type = 1 - if ("shrug") + if("shrug") message = "shrugs." m_type = 1 - if ("signal") - if (!src.restrained()) + if("signal") + if(!src.restrained()) var/t1 = round(text2num(param)) - if (isnum(t1)) - if (t1 <= 5 && (!src.r_hand || !src.l_hand)) + if(isnum(t1)) + if(t1 <= 5 && (!src.r_hand || !src.l_hand)) message = "raises [t1] finger\s." - else if (t1 <= 10 && (!src.r_hand && !src.l_hand)) + else if(t1 <= 10 && (!src.r_hand && !src.l_hand)) message = "raises [t1] finger\s." m_type = 1 - if ("smile") + if("smile") message = "smiles." m_type = 1 - if ("shiver") + if("shiver") message = "shivers." m_type = 2 if(miming) m_type = 1 - if ("pale") + if("pale") message = "goes pale for a second." m_type = 1 - if ("tremble") + if("tremble") message = "trembles in fear!" m_type = 1 @@ -550,48 +547,48 @@ message = "makes a strange noise." m_type = 2 - if ("sniff") + if("sniff") message = "sniffs." m_type = 2 if(miming) m_type = 1 - if ("snore") - if (miming) + if("snore") + if(miming) message = "sleeps soundly." m_type = 1 else - if (!muzzled) + if(!muzzled) message = "snores." m_type = 2 else message = "makes a noise." m_type = 2 - if ("whimper") - if (miming) + if("whimper") + if(miming) message = "appears hurt." m_type = 1 else - if (!muzzled) + if(!muzzled) message = "whimpers." m_type = 2 else message = "makes a weak noise." m_type = 2 - if ("wink") + if("wink") message = "winks." m_type = 1 - if ("yawn") - if (!muzzled) + if("yawn") + if(!muzzled) message = "yawns." m_type = 2 if(miming) m_type = 1 - if ("collapse") + if("collapse") Paralyse(2) message = "collapses!" m_type = 2 @@ -600,49 +597,49 @@ if("hug") m_type = 1 - if (!src.restrained()) + if(!src.restrained()) var/M = null - if (param) + if(param) for (var/mob/A in view(1, null)) - if (param == A.name) + if(param == A.name) M = A break - if (M == src) + if(M == src) M = null - if (M) + if(M) message = "hugs [M]." else message = "hugs [T.himself]." - if ("handshake") + if("handshake") m_type = 1 - if (!src.restrained() && !src.r_hand) + if(!src.restrained() && !src.r_hand) var/mob/living/M = null - if (param) + if(param) for (var/mob/living/A in view(1, null)) - if (param == A.name) + if(param == A.name) M = A break - if (M == src) + if(M == src) M = null - if (M) - if (M.canmove && !M.r_hand && !M.restrained()) + if(M) + if(M.canmove && !M.r_hand && !M.restrained()) message = "shakes hands with [M]." else message = "holds out [T.his] hand to [M]." if("dap") m_type = 1 - if (!src.restrained()) + if(!src.restrained()) var/M = null - if (param) + if(param) for (var/mob/A in view(1, null)) - if (param == A.name) + if(param == A.name) M = A break - if (M) + if(M) message = "gives daps to [M]." else message = "sadly can't find anybody to give daps to, and daps [T.himself]. Shameful." @@ -737,16 +734,20 @@ else message = "makes a light spitting noise, a poor attempt at a whistle." - if ("help") - to_chat(src, "blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, eyebrow, fastsway/qwag, \ + if("help") + to_chat(src, "blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, eyebrow, fastsway/qwag, \ frown, gasp, giggle, glare-(none)/mob, grin, groan, grumble, handshake, hug-(none)/mob, laugh, look-(none)/mob, moan, mumble, nod, pale, point-atom, \ raise, salute, scream, sneeze, shake, shiver, shrug, sigh, signal-#1-10, slap-(none)/mob, smile, sneeze, sniff, snore, stare-(none)/mob, stopsway/swag, sway/wag, swish, tremble, twitch, \ - twitch_v, vomit, whimper, wink, yawn. Prometheans: squish Synthetics: beep, buzz, dwoop, yes, no, rcough, rsneeze, ping. Skrell: warble") + twitch_v, vomit, whimper, wink, yawn. Prometheans: squish Synthetics: beep, buzz, dwoop, yes, no, rcough, rsneeze, ping. Skrell: warble") else +<<<<<<< HEAD to_chat(src, "Unusable emote '[act]'. Say *help or *vhelp for a list.") //VOREStation Edit, mention *vhelp for Virgo-specific emotes located in emote_vr.dm. +======= + to_chat(src, "Unusable emote '[act]'. Say *help for a list.") +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) - if (message) + if(message) custom_emote(m_type,message) /mob/living/carbon/human/verb/pose() diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index 1e5e549106..df9e6a331e 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -1,10 +1,13 @@ -/mob/living/carbon/human/say(var/message,var/whispering=0) - var/alt_name = "" +/mob/living/carbon/human/GetAltName() if(name != GetVoice()) - alt_name = "(as [get_id_name("Unknown")])" + return " (as [get_id_name("Unknown")])" +<<<<<<< HEAD message = sanitize_or_reflect(message,src) //VOREStation Edit - Reflect too-long messages, within reason ..(message, alt_name = alt_name, whispering = whispering) +======= + return ..() +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) /mob/living/carbon/human/proc/forcesay(list/append) if(stat == CONSCIOUS) @@ -47,18 +50,18 @@ return species.speech_bubble_appearance return "normal" -/mob/living/carbon/human/say_understands(var/mob/other,var/datum/language/speaking = null) - +/mob/living/carbon/human/say_understands(var/mob/other, var/datum/language/speaking = null) if(has_brain_worms()) //Brain worms translate everything. Even mice and alien speak. - return 1 + return TRUE if(species.can_understand(other)) - return 1 + return TRUE //These only pertain to common. Languages are handled by mob/say_understands() - if (!speaking) - if (istype(other, /mob/living/carbon/alien/diona)) + if(!speaking) + if(istype(other, /mob/living/carbon/alien/diona)) if(other.languages.len >= 2) //They've sucked down some blood and can speak common now. +<<<<<<< HEAD return 1 if (istype(other, /mob/living/silicon)) return 1 @@ -72,11 +75,19 @@ // if((other.universal_speak && !speaking) || src.universal_speak || src.universal_understand) // return 1 // return 0 +======= + return TRUE + if(issilicon(other)) + return TRUE + if(isbrain(other)) + return TRUE + if(isslime(other)) + return TRUE +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) return ..() /mob/living/carbon/human/GetVoice() - var/voice_sub if(istype(get_rig(),/obj/item/weapon/rig)) var/obj/item/weapon/rig/rig = get_rig() @@ -113,30 +124,6 @@ /mob/living/carbon/human/proc/GetSpecialVoice() return special_voice - -/* - ***Deprecated*** - let this be handled at the hear_say or hear_radio proc - This is left in for robot speaking when humans gain binary channel access until I get around to rewriting - robot_talk() proc. - There is no language handling build into it however there is at the /mob level so we accept the call - for it but just ignore it. -*/ - -/mob/living/carbon/human/say_quote(var/message, var/datum/language/speaking = null) - var/verb = "says" - var/ending = copytext(message, length(message)) - - if(speaking) - verb = speaking.get_spoken_verb(ending) - else - if(ending == "!") - verb=pick("exclaims","shouts","yells") - else if(ending == "?") - verb="asks" - - return verb - /mob/living/carbon/human/handle_speech_problems(var/list/message_data) if(silent || (sdisabilities & MUTE)) message_data[1] = "" @@ -152,59 +139,72 @@ else . = ..(message_data) -/mob/living/carbon/human/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) +/mob/living/carbon/human/handle_message_mode(message_mode, list/message_pieces, verb, used_radios) switch(message_mode) if("intercom") - if(!src.restrained()) + if(!restrained()) for(var/obj/item/device/radio/intercom/I in view(1)) - I.talk_into(src, message, null, verb, speaking) + I.talk_into(src, message_pieces, null, verb) I.add_fingerprint(src) used_radios += I if("headset") - if(l_ear && istype(l_ear,/obj/item/device/radio)) - var/obj/item/device/radio/R = l_ear - R.talk_into(src,message,null,verb,speaking) - used_radios += l_ear - else if(r_ear && istype(r_ear,/obj/item/device/radio)) - var/obj/item/device/radio/R = r_ear - R.talk_into(src,message,null,verb,speaking) - used_radios += r_ear - if("right ear") - var/obj/item/device/radio/R - var/has_radio = 0 - if(r_ear && istype(r_ear,/obj/item/device/radio)) - R = r_ear - has_radio = 1 - if(r_hand && istype(r_hand, /obj/item/device/radio)) - R = r_hand - has_radio = 1 - if(has_radio) - R.talk_into(src,message,null,verb,speaking) - used_radios += R - if("left ear") - var/obj/item/device/radio/R - var/has_radio = 0 - if(l_ear && istype(l_ear,/obj/item/device/radio)) + var/obj/item/device/radio/R = null + if(isradio(l_ear)) R = l_ear - has_radio = 1 - if(l_hand && istype(l_hand,/obj/item/device/radio)) + if(R.talk_into(src, message_pieces, null, verb)) + used_radios += R + return + + if(isradio(r_ear)) + R = r_ear + if(R.talk_into(src, message_pieces, null, verb)) + used_radios += R + return + if("right ear") + var/obj/item/device/radio/R = null + if(isradio(r_ear)) + R = r_ear + if(isradio(r_hand)) + R = r_hand + if(istype(R)) + if(R.talk_into(src, message_pieces, null, verb)) + used_radios += R + if("left ear") + var/obj/item/device/radio/R = null + if(isradio(l_ear)) + R = l_ear + if(isradio(l_hand)) R = l_hand - has_radio = 1 - if(has_radio) - R.talk_into(src,message,null,verb,speaking) - used_radios += R + if(istype(R)) + if(R.talk_into(src, message_pieces, null, verb)) + used_radios += R else if(message_mode) - if(l_ear && istype(l_ear,/obj/item/device/radio)) - l_ear.talk_into(src,message, message_mode, verb, speaking) - used_radios += l_ear - else if(r_ear && istype(r_ear,/obj/item/device/radio)) - r_ear.talk_into(src,message, message_mode, verb, speaking) - used_radios += r_ear + if(isradio(l_ear)) + if(l_ear.talk_into(src, message_pieces, message_mode, verb)) + used_radios += l_ear + return + + if(isradio(r_ear)) + if(r_ear.talk_into(src, message_pieces, message_mode, verb)) + used_radios += r_ear /mob/living/carbon/human/handle_speech_sound() + var/list/returns[2] if(species.speech_sounds && prob(species.speech_chance)) - var/list/returns[2] returns[1] = sound(pick(species.speech_sounds)) returns[2] = 50 - return ..() + return returns + +/mob/living/carbon/human/binarycheck() + . = FALSE + var/obj/item/device/radio/headset/R = null + if(istype(l_ear, /obj/item/device/radio/headset)) + R = l_ear + if(R.translate_binary) + . = TRUE + + if(istype(r_ear, /obj/item/device/radio/headset)) + R = r_ear + if(R.translate_binary) + . = TRUE diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm index 3383e7bdfb..4e64d59d72 100644 --- a/code/modules/mob/living/carbon/human/species/station/station.dm +++ b/code/modules/mob/living/carbon/human/species/station/station.dm @@ -532,10 +532,9 @@ genders = list(PLURAL) /datum/species/diona/can_understand(var/mob/other) - var/mob/living/carbon/alien/diona/D = other - if(istype(D)) - return 1 - return 0 + if(istype(other, /mob/living/carbon/alien/diona)) + return TRUE + return FALSE /datum/species/diona/equip_survival_gear(var/mob/living/carbon/human/H) if(H.backbag == 1) diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm index 8a72f6ecf8..4809853f00 100644 --- a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm @@ -86,11 +86,9 @@ return "alien [caste_name] ([alien_number])" /datum/species/xenos/can_understand(var/mob/other) - - if(istype(other,/mob/living/carbon/alien/larva)) - return 1 - - return 0 + if(istype(other, /mob/living/carbon/alien/larva)) + return TRUE + return FALSE /datum/species/xenos/hug(var/mob/living/carbon/human/H,var/mob/living/target) H.visible_message("[H] caresses [target] with its scythe-like arm.", \ diff --git a/code/modules/mob/living/carbon/metroid/death.dm b/code/modules/mob/living/carbon/metroid/death.dm deleted file mode 100644 index d5510ac509..0000000000 --- a/code/modules/mob/living/carbon/metroid/death.dm +++ /dev/null @@ -1,22 +0,0 @@ -/mob/living/carbon/slime/death(gibbed) - - if(stat == DEAD) return - - if(!gibbed && is_adult) - var/mob/living/carbon/slime/M = new /mob/living/carbon/slime(loc, colour) - M.rabid = 1 - M.Friends = Friends.Copy() - step_away(M, src) - is_adult = 0 - maxHealth = 150 - revive() - if (!client) rabid = 1 - number = rand(1, 1000) - name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])" - return - - . = ..(gibbed, "seizes up and falls limp...") - mood = null - regenerate_icons() - - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/metroid/emote.dm b/code/modules/mob/living/carbon/metroid/emote.dm deleted file mode 100644 index 6fccaddb8f..0000000000 --- a/code/modules/mob/living/carbon/metroid/emote.dm +++ /dev/null @@ -1,99 +0,0 @@ -/mob/living/carbon/slime/emote(var/act, var/m_type=1, var/message = null) - - if (findtext(act, "-", 1, null)) - var/t1 = findtext(act, "-", 1, null) - //param = copytext(act, t1 + 1, length(act) + 1) - act = copytext(act, 1, t1) - - if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_' - act = copytext(act,1,length(act)) - - var/updateicon = 0 - - switch(act) //Alphabetical please - if ("me") - if(silent) - return - if (src.client) - if (client.prefs.muted & MUTE_IC) - to_chat(src, "You cannot send IC messages (muted).") - return - if (stat) - return - if(!(message)) - return - return custom_emote(m_type, message) - if("bounce") - message = "The [src.name] bounces in place." - m_type = 1 - - if ("custom") - return custom_emote(m_type, message) - - if("jiggle") - message = "The [src.name] jiggles!" - m_type = 1 - - if("light") - message = "The [src.name] lights up for a bit, then stops." - m_type = 1 - - if("moan") - message = "The [src.name] moans." - m_type = 2 - - if("shiver") - message = "The [src.name] shivers." - m_type = 2 - - if("sway") - message = "The [src.name] sways around dizzily." - m_type = 1 - - if("twitch") - message = "The [src.name] twitches." - m_type = 1 - - if("vibrate") - message = "The [src.name] vibrates!" - m_type = 1 - - if("nomood") - mood = null - updateicon = 1 - - if("pout") - mood = "pout" - updateicon = 1 - - if("sad") - mood = "sad" - updateicon = 1 - - if("angry") - mood = "angry" - updateicon = 1 - - if("frown") - mood = "mischevous" - updateicon = 1 - - if("smile") - mood = ":3" - updateicon = 1 - - if ("help") //This is an exception - to_chat(src, "Help for slime emotes. You can use these emotes with say \"*emote\":\n\nbounce, custom, jiggle, light, moan, shiver, sway, twitch, vibrate. You can also set your face with: \n\nnomood, pout, sad, angry, frown, smile") - - else - to_chat(src, "Unusable emote '[act]'. Say *help for a list.") - if ((message && src.stat == 0)) - if (m_type & 1) - for(var/mob/O in viewers(src, null)) - O.show_message(message, m_type) - else - for(var/mob/O in hearers(src, null)) - O.show_message(message, m_type) - if(updateicon) - regenerate_icons() - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/metroid/examine.dm b/code/modules/mob/living/carbon/metroid/examine.dm deleted file mode 100644 index 9e96e3257d..0000000000 --- a/code/modules/mob/living/carbon/metroid/examine.dm +++ /dev/null @@ -1,31 +0,0 @@ -/mob/living/carbon/slime/examine(mob/user) - ..(user) - var/msg = "" - if (src.stat == DEAD) - msg += "It is limp and unresponsive.\n" - else - if (src.getBruteLoss()) - msg += "" - if (src.getBruteLoss() < 40) - msg += "It has some punctures in its flesh!" - else - msg += "It has severe punctures and tears in its flesh!" - msg += "\n" - - switch(powerlevel) - - if(2 to 3) - msg += "It is flickering gently with a little electrical activity.\n" - - if(4 to 5) - msg += "It is glowing gently with moderate levels of electrical activity.\n" - - if(6 to 9) - msg += "It is glowing brightly with high levels of electrical activity.\n" - - if(10) - msg += "It is radiating with massive levels of electrical activity!\n" - - msg += "*---------*" - to_chat(user,msg) - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/metroid/hud.dm b/code/modules/mob/living/carbon/metroid/hud.dm deleted file mode 100644 index da6729c3dc..0000000000 --- a/code/modules/mob/living/carbon/metroid/hud.dm +++ /dev/null @@ -1,2 +0,0 @@ -/mob/living/carbon/slime/handle_regular_hud_updates() - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/metroid/life.dm b/code/modules/mob/living/carbon/metroid/life.dm deleted file mode 100644 index 7643ea3d2e..0000000000 --- a/code/modules/mob/living/carbon/metroid/life.dm +++ /dev/null @@ -1,527 +0,0 @@ -/mob/living/carbon/slime/Life() - set invisibility = 0 - set background = 1 - - if (src.transforming) - return - - ..() - - if(stat != DEAD) - handle_nutrition() - - if (!client) - handle_targets() - if (!AIproc) - spawn() - handle_AI() - handle_speech_and_mood() - -/mob/living/carbon/slime/handle_environment(datum/gas_mixture/environment) - if(!environment) - adjustToxLoss(rand(10,20)) - return - - //var/environment_heat_capacity = environment.heat_capacity() - var/loc_temp = T0C - if(istype(get_turf(src), /turf/space)) - //environment_heat_capacity = loc:heat_capacity - var/turf/heat_turf = get_turf(src) - loc_temp = heat_turf.temperature - else if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) - loc_temp = loc:air_contents.temperature - else - loc_temp = environment.temperature - - bodytemperature += adjust_body_temperature(bodytemperature, loc_temp, 1) - - if(bodytemperature < (T0C + 5)) // start calculating temperature damage etc - if(bodytemperature <= hurt_temperature) - if(bodytemperature <= die_temperature) - adjustToxLoss(200) - else - // could be more fancy, but doesn't worth the complexity: when the slimes goes into a cold area - // the damage is mostly determined by how fast its body cools - adjustToxLoss(30) - - updatehealth() - - return //TODO: DEFERRED - -/mob/living/carbon/slime/proc/adjust_body_temperature(current, loc_temp, boost) - var/temperature = current - var/difference = abs(current-loc_temp) //get difference - var/increments// = difference/10 //find how many increments apart they are - if(difference > 50) - increments = difference/5 - else - increments = difference/10 - var/change = increments*boost // Get the amount to change by (x per increment) - var/temp_change - if(current < loc_temp) - temperature = min(loc_temp, temperature+change) - else if(current > loc_temp) - temperature = max(loc_temp, temperature-change) - temp_change = (temperature - current) - return temp_change - -/mob/living/carbon/slime/handle_chemicals_in_body() - chem_effects.Cut() - - if(touching) touching.metabolize() - if(ingested) ingested.metabolize() - if(bloodstr) bloodstr.metabolize() - - src.updatehealth() - - return //TODO: DEFERRED - -/mob/living/carbon/slime/handle_regular_status_updates() - - src.blinded = null - - health = getMaxHealth() - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss()) - - if(health < 0 && stat != DEAD) - death() - return - - if (halloss) - halloss = 0 - - if(prob(30)) - adjustOxyLoss(-1) - adjustToxLoss(-1) - adjustFireLoss(-1) - adjustCloneLoss(-1) - adjustBruteLoss(-1) - - if (src.stat == DEAD) - src.lying = 1 - src.blinded = 1 - else - if (src.paralysis || src.stunned || src.weakened || (status_flags & FAKEDEATH)) //Stunned etc. - if (src.stunned > 0) - src.set_stat(CONSCIOUS) - if (src.weakened > 0) - src.lying = 0 - src.set_stat(CONSCIOUS) - if (src.paralysis > 0) - src.blinded = 0 - src.lying = 0 - src.set_stat(CONSCIOUS) - - else - src.lying = 0 - src.set_stat(CONSCIOUS) - - if (src.stuttering) src.stuttering = 0 - - if (src.eye_blind) - SetBlinded(0) - src.blinded = 1 - - if (src.ear_deaf > 0) src.ear_deaf = 0 - if (src.ear_damage < 25) - src.ear_damage = 0 - - src.density = !( src.lying ) - - if (src.sdisabilities & BLIND) - src.blinded = 1 - if (src.sdisabilities & DEAF) - src.ear_deaf = 1 - - if (src.eye_blurry > 0) - src.eye_blurry = 0 - - if (src.druggy > 0) - src.druggy = 0 - - return 1 - -/mob/living/carbon/slime/proc/handle_nutrition() - - if (prob(15)) - nutrition -= 1 + is_adult - - if(nutrition <= 0) - nutrition = 0 - adjustToxLoss(rand(1,3)) - if (client && prob(5)) - to_chat(src, "You are starving!") - - else if (nutrition >= get_grow_nutrition() && amount_grown < 10) - nutrition -= 20 - amount_grown++ - -/mob/living/carbon/slime/proc/handle_targets() - if(attacked > 50) attacked = 50 // Let's not get into absurdly long periods of rage - - if(attacked > 0) - attacked-- - - if(Discipline > 0) - - if(Discipline >= 5 && rabid) - if(prob(60)) rabid = 0 - - if(prob(10)) - Discipline-- - - if(!canmove) return - - if(Victim) return // if it's eating someone already, continue eating! - - if(Target) - --target_patience - if (target_patience <= 0 || SStun || Discipline || attacked) // Tired of chasing or something draws out attention - target_patience = 0 - Target = null - - var/hungry = 0 // determines if the slime is hungry - - if (nutrition < get_starve_nutrition()) - hungry = 2 - else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition()) - hungry = 1 - - if(hungry == 2 && !client) // if a slime is starving, it starts losing its friends - if(Friends.len > 0 && prob(1)) - var/mob/nofriend = pick(Friends) - if(nofriend && Friends[nofriend]) - Friends[nofriend] -= 1 - if (Friends[nofriend] <= 0) - Friends[nofriend] = null - Friends -= nofriend - Friends -= null - - if(!Target) - if(will_hunt(hungry) || attacked || rabid) // Only add to the list if we need to - var/list/targets = list() - - for(var/mob/living/L in view(7,src)) - - if(isslime(L) || L.stat == DEAD) // Ignore other slimes and dead mobs - continue - - if(L in Friends) // No eating friends! - continue - - if(issilicon(L) && (rabid || attacked)) // They can't eat silicons, but they can glomp them in defence - targets += L // Possible target found! - - if(istype(L, /mob/living/carbon/human) && dna) //Ignore slime(wo)men - var/mob/living/carbon/human/H = L - if(H.species.name == "Promethean") - continue - - if(!L.canmove) // Only one slime can latch on at a time. - var/notarget = 0 - for(var/mob/living/carbon/slime/M in view(1,L)) - if(M.Victim == L) - notarget = 1 - if(notarget) - continue - - targets += L // Possible target found! - - if(targets.len > 0) - if(attacked || rabid || hungry == 2) - Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care - else - for(var/mob/living/carbon/C in targets) - if(ishuman(C) && !Discipline && prob(5)) - Target = C - break - - if(isalien(C) || issmall(C) || isanimal(C)) - Target = C - break - - if (Target) - target_patience = rand(5,7) - if (is_adult) - target_patience += 3 - - if(!Target) // If we have no target, we are wandering or following orders - if (Leader) - if (holding_still) - holding_still = max(holding_still - 1, 0) - else if(canmove && isturf(loc)) - step_to(src, Leader) - - else if(hungry) - if (holding_still) - holding_still = max(holding_still - 1 - hungry, 0) - else if(canmove && isturf(loc) && prob(50)) - step(src, pick(cardinal)) - - else - if (holding_still) - holding_still = max(holding_still - 1, 0) - else if(canmove && isturf(loc) && prob(33)) - step(src, pick(cardinal)) - -/mob/living/carbon/slime/proc/handle_AI() // the master AI process - - if(stat == DEAD || client || Victim) return // If we're dead or have a client, we don't need AI, if we're feeding, we continue feeding - AIproc = 1 - - if(amount_grown >= 10 && !Target) - if(is_adult) - Reproduce() - else - Evolve() - AIproc = 0 - return - - if(Target) // We're chasing the target - if(Target.stat == DEAD) - Target = null - AIproc = 0 - return - - for(var/mob/living/carbon/slime/M in view(1, Target)) - if(M.Victim == Target) - Target = null - AIproc = 0 - return - - if(Target.Adjacent(src)) - if(istype(Target, /mob/living/silicon)) // Glomp the silicons - if(!Atkcool) - a_intent = I_HURT - UnarmedAttack(Target) - Atkcool = 1 - spawn(45) - Atkcool = 0 - AIproc = 0 - return - - if(Target.client && !Target.lying && prob(60 + powerlevel * 4)) // Try to take down the target first - if(!Atkcool) - Atkcool = 1 - spawn(45) - Atkcool = 0 - - a_intent = I_DISARM - UnarmedAttack(Target) - - else - if(!Atkcool) - a_intent = I_GRAB - UnarmedAttack(Target) - - else if(Target in view(7, src)) - step_to(src, Target) - - else - Target = null - AIproc = 0 - return - - else - var/mob/living/carbon/slime/frenemy - for (var/mob/living/carbon/slime/S in view(1, src)) - if (S != src) - frenemy = S - if (frenemy && prob(1)) - if (frenemy.colour == colour) - a_intent = I_HELP - else - a_intent = I_HURT - UnarmedAttack(frenemy) - - var/sleeptime = movement_delay() - if(sleeptime <= 5) sleeptime = 5 // Maximum one action per half a second - spawn (sleeptime) - handle_AI() - return - -/mob/living/carbon/slime/proc/handle_speech_and_mood() - //Mood starts here - var/newmood = "" - a_intent = I_HELP - if (rabid || attacked) - newmood = "angry" - a_intent = I_HURT - else if (Target) newmood = "mischevous" - - if (!newmood) - if (Discipline && prob(25)) - newmood = "pout" - else if (prob(1)) - newmood = pick("sad", ":3", "pout") - - if ((mood == "sad" || mood == ":3" || mood == "pout") && !newmood) - if (prob(75)) newmood = mood - - if (newmood != mood) // This is so we don't redraw them every time - mood = newmood - regenerate_icons() - - //Speech understanding starts here - var/to_say - if (speech_buffer.len > 0) - var/who = speech_buffer[1] // Who said it? - var/phrase = speech_buffer[2] // What did they say? - if ((findtext(phrase, num2text(number)) || findtext(phrase, "slimes"))) // Talking to us - if (findtext(phrase, "hello") || findtext(phrase, "hi")) - to_say = pick("Hello...", "Hi...") - else if (findtext(phrase, "follow")) - if (Leader) - if (Leader == who) // Already following him - to_say = pick("Yes...", "Lead...", "Following...") - else if (Friends[who] > Friends[Leader]) // VIVA - Leader = who - to_say = "Yes... I follow [who]..." - else - to_say = "No... I follow [Leader]..." - else - if (Friends[who] > 2) - Leader = who - to_say = "I follow..." - else // Not friendly enough - to_say = pick("No...", "I won't follow...") - else if (findtext(phrase, "stop")) - if (Victim) // We are asked to stop feeding - if (Friends[who] > 4) - Victim = null - Target = null - if (Friends[who] < 7) - --Friends[who] - to_say = "Grrr..." // I'm angry but I do it - else - to_say = "Fine..." - else if (Target) // We are asked to stop chasing - if (Friends[who] > 3) - Target = null - if (Friends[who] < 6) - --Friends[who] - to_say = "Grrr..." // I'm angry but I do it - else - to_say = "Fine..." - else if (Leader) // We are asked to stop following - if (Leader == who) - to_say = "Yes... I'll stay..." - Leader = null - else - if (Friends[who] > Friends[Leader]) - Leader = null - to_say = "Yes... I'll stop..." - else - to_say = "No... I'll keep following..." - else if (findtext(phrase, "stay")) - if (Leader) - if (Leader == who) - holding_still = Friends[who] * 10 - to_say = "Yes... Staying..." - else if (Friends[who] > Friends[Leader]) - holding_still = (Friends[who] - Friends[Leader]) * 10 - to_say = "Yes... Staying..." - else - to_say = "No... I'll keep following..." - else - if (Friends[who] > 2) - holding_still = Friends[who] * 10 - to_say = "Yes... Staying..." - else - to_say = "No... I won't stay..." - speech_buffer = list() - - //Speech starts here - if (to_say) - say (to_say) - else if(prob(1)) - emote(pick("bounce","sway","light","vibrate","jiggle")) - else - var/t = 10 - var/slimes_near = -1 // Don't count myself - var/dead_slimes = 0 - var/friends_near = list() - for (var/mob/living/carbon/M in view(7,src)) - if (isslime(M)) - ++slimes_near - if (M.stat == DEAD) - ++dead_slimes - if (M in Friends) - t += 20 - friends_near += M - if (nutrition < get_hunger_nutrition()) t += 10 - if (nutrition < get_starve_nutrition()) t += 10 - if (prob(2) && prob(t)) - var/phrases = list() - if (Target) phrases += "[Target]... looks tasty..." - if (nutrition < get_starve_nutrition()) - phrases += "So... hungry..." - phrases += "Very... hungry..." - phrases += "Need... food..." - phrases += "Must... eat..." - else if (nutrition < get_hunger_nutrition()) - phrases += "Hungry..." - phrases += "Where is the food?" - phrases += "I want to eat..." - phrases += "Rawr..." - phrases += "Blop..." - phrases += "Blorble..." - if (rabid || attacked) - phrases += "Hrr..." - phrases += "Nhuu..." - phrases += "Unn..." - if (mood == ":3") - phrases += "Purr..." - if (attacked) - phrases += "Grrr..." - if (getToxLoss() > 30) - phrases += "Cold..." - if (getToxLoss() > 60) - phrases += "So... cold..." - phrases += "Very... cold..." - if (getToxLoss() > 90) - phrases += "..." - phrases += "C... c..." - if (Victim) - phrases += "Nom..." - phrases += "Tasty..." - if (powerlevel > 3) phrases += "Bzzz..." - if (powerlevel > 5) phrases += "Zap..." - if (powerlevel > 8) phrases += "Zap... Bzz..." - if (mood == "sad") phrases += "Bored..." - if (slimes_near) phrases += "Brother..." - if (slimes_near > 1) phrases += "Brothers..." - if (dead_slimes) phrases += "What happened?" - if (!slimes_near) - phrases += "Lonely..." - for (var/M in friends_near) - phrases += "[M]... friend..." - if (nutrition < get_hunger_nutrition()) - phrases += "[M]... feed me..." - say (pick(phrases)) - -/mob/living/carbon/slime/proc/get_max_nutrition() // Can't go above it - if (is_adult) return 1200 - else return 1000 - -/mob/living/carbon/slime/proc/get_grow_nutrition() // Above it we grow, below it we can eat - if (is_adult) return 1000 - else return 800 - -/mob/living/carbon/slime/proc/get_hunger_nutrition() // Below it we will always eat - if (is_adult) return 600 - else return 500 - -/mob/living/carbon/slime/proc/get_starve_nutrition() // Below it we will eat before everything else - if (is_adult) return 300 - else return 200 - -/mob/living/carbon/slime/proc/will_hunt(var/hunger) // Check for being stopped from feeding and chasing - if (hunger == 2 || rabid || attacked) return 1 - if (Leader) return 0 - if (holding_still) return 0 - if (hunger == 1 || prob(25)) - return 1 - return 0 - -/mob/living/carbon/slime/slip() //Can't slip something without legs. - return 0 diff --git a/code/modules/mob/living/carbon/metroid/login.dm b/code/modules/mob/living/carbon/metroid/login.dm deleted file mode 100644 index 8ca29bf481..0000000000 --- a/code/modules/mob/living/carbon/metroid/login.dm +++ /dev/null @@ -1,4 +0,0 @@ -/mob/living/carbon/slime/Login() - ..() - update_hud() - return diff --git a/code/modules/mob/living/carbon/metroid/metroid.dm b/code/modules/mob/living/carbon/metroid/metroid.dm deleted file mode 100644 index a871d7e3ac..0000000000 --- a/code/modules/mob/living/carbon/metroid/metroid.dm +++ /dev/null @@ -1,384 +0,0 @@ -/mob/living/carbon/slime - name = "baby slime" - icon = 'icons/mob/slimes.dmi' - icon_state = "grey baby slime" - pass_flags = PASSTABLE - var/is_adult = 0 - speak_emote = list("chirps") - - plane = MOB_PLANE - layer = ABOVE_MOB_LAYER - maxHealth = 150 - health = 150 - gender = NEUTER - - update_icon = 0 - nutrition = 700 - - see_in_dark = 8 - update_slimes = 0 - - // canstun and canweaken don't affect slimes because they ignore stun and weakened variables - // for the sake of cleanliness, though, here they are. - status_flags = CANPARALYSE|CANPUSH - - var/cores = 1 // the number of /obj/item/slime_extract's the slime has left inside - var/mutation_chance = 30 // Chance of mutating, should be between 25 and 35 - - var/powerlevel = 0 // 0-10 controls how much electricity they are generating - var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces - - var/number = 0 // Used to understand when someone is talking to it - - var/mob/living/Victim = null // the person the slime is currently feeding on - var/mob/living/Target = null // AI variable - tells the slime to hunt this down - var/mob/living/Leader = null // AI variable - tells the slime to follow this person - - var/attacked = 0 // Determines if it's been attacked recently. Can be any number, is a cooloff-ish variable - var/rabid = 0 // If set to 1, the slime will attack and eat anything it comes in contact with - var/holding_still = 0 // AI variable, cooloff-ish for how long it's going to stay in one place - var/target_patience = 0 // AI variable, cooloff-ish for how long it's going to follow its target - - var/list/Friends = list() // A list of friends; they are not considered targets for feeding; passed down after splitting - - var/list/speech_buffer = list() // Last phrase said near it and person who said it - - var/mood = "" // To show its face - - var/AIproc = 0 // If it's 0, we need to launch an AI proc - var/Atkcool = 0 // attack cooldown - var/SStun = 0 // NPC stun variable. Used to calm them down when they are attacked while feeding, or they will immediately re-attach - var/Discipline = 0 // if a slime has been hit with a freeze gun, or wrestled/attacked off a human, they become disciplined and don't attack anymore for a while. The part about freeze gun is a lie - - var/hurt_temperature = T0C-50 // slime keeps taking damage when its bodytemperature is below this - var/die_temperature = 50 // slime dies instantly when its bodytemperature is below this - - ///////////TIME FOR SUBSPECIES - - var/colour = "grey" - var/coretype = /obj/item/slime_extract/grey - var/list/slime_mutation[4] - - var/core_removal_stage = 0 //For removing cores. - -/mob/living/carbon/slime/New(var/location, var/colour="grey") - - verbs += /mob/living/proc/ventcrawl - - src.colour = colour - number = rand(1, 1000) - name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])" - real_name = name - slime_mutation = mutation_table(colour) - mutation_chance = rand(25, 35) - var/sanitizedcolour = replacetext(colour, " ", "") - coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]") - regenerate_icons() - ..(location) - -/mob/living/carbon/slime/movement_delay() - if (bodytemperature >= 330.23) // 135 F - return -1 // slimes become supercharged at high temperatures - - var/tally = 0 - - var/health_deficiency = (getMaxHealth() - health) - if(health_deficiency >= 30) tally += (health_deficiency / 25) - - if (bodytemperature < 183.222) - tally += (283.222 - bodytemperature) / 10 * 1.75 - - if(reagents) - if(reagents.has_reagent("hyperzine")) // Hyperzine slows slimes down - tally *= 2 - - if(reagents.has_reagent("frostoil")) // Frostoil also makes them move VEEERRYYYYY slow - tally *= 5 - - if(health <= 0) // if damaged, the slime moves twice as slow - tally *= 2 - - return tally + config.slime_delay - -/mob/living/carbon/slime/Bump(atom/movable/AM as mob|obj, yes) - if ((!(yes) || now_pushing)) - return - now_pushing = 1 - - if(isobj(AM) && !client && powerlevel > 0) - var/probab = 10 - switch(powerlevel) - if(1 to 2) probab = 20 - if(3 to 4) probab = 30 - if(5 to 6) probab = 40 - if(7 to 8) probab = 60 - if(9) probab = 70 - if(10) probab = 95 - if(prob(probab)) - if(istype(AM, /obj/structure/window) || istype(AM, /obj/structure/grille)) - if(nutrition <= get_hunger_nutrition() && !Atkcool) - if (is_adult || prob(5)) - UnarmedAttack(AM) - Atkcool = 1 - spawn(45) - Atkcool = 0 - - if(ismob(AM)) - var/mob/tmob = AM - - if(is_adult) - if(istype(tmob, /mob/living/carbon/human)) - if(prob(90)) - now_pushing = 0 - return - else - if(istype(tmob, /mob/living/carbon/human)) - now_pushing = 0 - return - - now_pushing = 0 - - ..() - -/mob/living/carbon/slime/Process_Spacemove() - return 2 - -/mob/living/carbon/slime/Stat() - ..() - - statpanel("Status") - stat(null, "Health: [round((health / getMaxHealth()) * 100)]%") - stat(null, "Intent: [a_intent]") - - if (client.statpanel == "Status") - stat(null, "Nutrition: [nutrition]/[get_max_nutrition()]") - if(amount_grown >= 10) - if(is_adult) - stat(null, "You can reproduce!") - else - stat(null, "You can evolve!") - - stat(null,"Power Level: [powerlevel]") - -/mob/living/carbon/slime/adjustFireLoss(amount) - ..(-abs(amount)) // Heals them - return - -/mob/living/carbon/slime/bullet_act(var/obj/item/projectile/Proj) - attacked += 10 - ..(Proj) - return 0 - -/mob/living/carbon/slime/emp_act(severity) - powerlevel = 0 // oh no, the power! - ..() - -/mob/living/carbon/slime/ex_act(severity) - ..() - - var/b_loss = null - var/f_loss = null - switch (severity) - if (1.0) - qdel(src) - return - - if (2.0) - - b_loss += 60 - f_loss += 60 - - - if(3.0) - b_loss += 30 - - adjustBruteLoss(b_loss) - adjustFireLoss(f_loss) - - updatehealth() - - -/mob/living/carbon/slime/u_equip(obj/item/W as obj) - return - -/mob/living/carbon/slime/attack_ui(slot) - return - -/mob/living/carbon/slime/attack_hand(mob/living/carbon/human/M as mob) - - ..() - - if(Victim) - if(Victim == M) - if(prob(60)) - visible_message("[M] attempts to wrestle \the [name] off!") - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - - else - visible_message(" [M] manages to wrestle \the [name] off!") - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - - if(prob(90) && !client) - Discipline++ - - SStun = 1 - spawn(rand(45,60)) - SStun = 0 - - Victim = null - anchored = 0 - step_away(src,M) - - return - - else - if(prob(30)) - visible_message("[M] attempts to wrestle \the [name] off of [Victim]!") - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - - else - visible_message(" [M] manages to wrestle \the [name] off of [Victim]!") - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - - if(prob(80) && !client) - Discipline++ - - if(!is_adult) - if(Discipline == 1) - attacked = 0 - - SStun = 1 - spawn(rand(55,65)) - SStun = 0 - - Victim = null - anchored = 0 - step_away(src,M) - - return - - switch(M.a_intent) - - if (I_HELP) - help_shake_act(M) - - if (I_GRAB) - if (M == src || anchored) - return - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src) - - M.put_in_active_hand(G) - - G.synch() - - LAssailant = M - - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - visible_message("[M] has grabbed [src] passively!") - - else - - var/damage = rand(1, 9) - - attacked += 10 - if (prob(90)) - if (HULK in M.mutations) - damage += 5 - if(Victim || Target) - Victim = null - Target = null - anchored = 0 - if(prob(80) && !client) - Discipline++ - spawn(0) - step_away(src,M,15) - sleep(3) - step_away(src,M,15) - - playsound(loc, "punch", 25, 1, -1) - visible_message("[M] has punched [src]!", \ - "[M] has punched [src]!") - - adjustBruteLoss(damage) - updatehealth() - else - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - visible_message("[M] has attempted to punch [src]!") - return - -/mob/living/carbon/slime/attackby(obj/item/W, mob/user) - if(W.force > 0) - attacked += 10 - if(prob(25)) - to_chat(user, "[W] passes right through [src]!") - return - if(Discipline && prob(50)) // wow, buddy, why am I getting attacked?? - Discipline = 0 - if(W.force >= 3) - if(is_adult) - if(prob(5 + round(W.force/2))) - if(Victim || Target) - if(prob(80) && !client) - Discipline++ - - Victim = null - Target = null - anchored = 0 - - SStun = 1 - spawn(rand(5,20)) - SStun = 0 - - spawn(0) - if(user) - canmove = 0 - step_away(src, user) - if(prob(25 + W.force)) - sleep(2) - if(user) - step_away(src, user) - canmove = 1 - - else - if(prob(10 + W.force*2)) - if(Victim || Target) - if(prob(80) && !client) - Discipline++ - if(Discipline == 1) - attacked = 0 - SStun = 1 - spawn(rand(5,20)) - SStun = 0 - - Victim = null - Target = null - anchored = 0 - - spawn(0) - if(user) - canmove = 0 - step_away(src, user) - if(prob(25 + W.force*4)) - sleep(2) - if(user) - step_away(src, user) - canmove = 1 - ..() - -/mob/living/carbon/slime/restrained() - return 0 - -/mob/living/carbon/slime/var/co2overloadtime = null -/mob/living/carbon/slime/var/temperature_resistance = T0C+75 - -/mob/living/carbon/slime/toggle_throw_mode() - return - -/mob/living/carbon/slime/proc/gain_nutrition(var/amount) - nutrition += amount - if(prob(amount * 2)) // Gain around one level per 50 nutrition - powerlevel++ - if(powerlevel > 10) - powerlevel = 10 - adjustToxLoss(-10) - nutrition = max(nutrition, get_max_nutrition()) diff --git a/code/modules/mob/living/carbon/metroid/say.dm b/code/modules/mob/living/carbon/metroid/say.dm deleted file mode 100644 index 7c7ad76240..0000000000 --- a/code/modules/mob/living/carbon/metroid/say.dm +++ /dev/null @@ -1,39 +0,0 @@ -/mob/living/carbon/slime/say(var/message) - - message = sanitize(message) - - var/verb = say_quote(message) - - if(copytext(message,1,2) == "*") - return emote(copytext(message,2)) - - return ..(message, null, verb) - -/mob/living/carbon/slime/say_quote(var/text) - var/ending = copytext(text, length(text)) - - if (ending == "?") - return "asks"; - else if (ending == "!") - return "cries"; - - return "chirps"; - -/mob/living/carbon/slime/say_understands(var/other) - if (istype(other, /mob/living/carbon/slime)) - return 1 - return ..() - -/mob/living/carbon/slime/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) - if (speaker in Friends) - speech_buffer = list() - speech_buffer.Add(speaker) - speech_buffer.Add(lowertext(html_decode(message))) - ..() - -/mob/living/carbon/slime/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="") - if (speaker in Friends) - speech_buffer = list() - speech_buffer.Add(speaker) - speech_buffer.Add(lowertext(html_decode(message))) - ..() diff --git a/code/modules/mob/living/carbon/metroid/subtypes.dm b/code/modules/mob/living/carbon/metroid/subtypes.dm deleted file mode 100644 index 6aa75990ac..0000000000 --- a/code/modules/mob/living/carbon/metroid/subtypes.dm +++ /dev/null @@ -1,79 +0,0 @@ -/mob/living/carbon/slime/proc/mutation_table(var/colour) - var/list/slime_mutation[4] - switch(colour) - //Tier 1 - if("grey") - slime_mutation[1] = "orange" - slime_mutation[2] = "metal" - slime_mutation[3] = "blue" - slime_mutation[4] = "purple" - //Tier 2 - if("purple") - slime_mutation[1] = "dark purple" - slime_mutation[2] = "dark blue" - slime_mutation[3] = "green" - slime_mutation[4] = "green" - if("metal") - slime_mutation[1] = "silver" - slime_mutation[2] = "yellow" - slime_mutation[3] = "gold" - slime_mutation[4] = "gold" - if("orange") - slime_mutation[1] = "dark purple" - slime_mutation[2] = "yellow" - slime_mutation[3] = "red" - slime_mutation[4] = "red" - if("blue") - slime_mutation[1] = "dark blue" - slime_mutation[2] = "silver" - slime_mutation[3] = "pink" - slime_mutation[4] = "pink" - //Tier 3 - if("dark blue") - slime_mutation[1] = "purple" - slime_mutation[2] = "purple" - slime_mutation[3] = "blue" - slime_mutation[4] = "blue" - if("dark purple") - slime_mutation[1] = "purple" - slime_mutation[2] = "purple" - slime_mutation[3] = "orange" - slime_mutation[4] = "orange" - if("yellow") - slime_mutation[1] = "metal" - slime_mutation[2] = "metal" - slime_mutation[3] = "orange" - slime_mutation[4] = "orange" - if("silver") - slime_mutation[1] = "metal" - slime_mutation[2] = "metal" - slime_mutation[3] = "blue" - slime_mutation[4] = "blue" - //Tier 4 - if("pink") - slime_mutation[1] = "pink" - slime_mutation[2] = "pink" - slime_mutation[3] = "light pink" - slime_mutation[4] = "light pink" - if("red") - slime_mutation[1] = "red" - slime_mutation[2] = "red" - slime_mutation[3] = "oil" - slime_mutation[4] = "oil" - if("gold") - slime_mutation[1] = "gold" - slime_mutation[2] = "gold" - slime_mutation[3] = "adamantine" - slime_mutation[4] = "adamantine" - if("green") - slime_mutation[1] = "green" - slime_mutation[2] = "green" - slime_mutation[3] = "black" - slime_mutation[4] = "black" - // Tier 5 - else - slime_mutation[1] = colour - slime_mutation[2] = colour - slime_mutation[3] = colour - slime_mutation[4] = colour - return(slime_mutation) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/metroid/update_icons.dm b/code/modules/mob/living/carbon/metroid/update_icons.dm deleted file mode 100644 index 847dcaeb18..0000000000 --- a/code/modules/mob/living/carbon/metroid/update_icons.dm +++ /dev/null @@ -1,9 +0,0 @@ -/mob/living/carbon/slime/regenerate_icons() - if (stat == DEAD) - icon_state = "[colour] baby slime dead" - else - icon_state = "[colour] [is_adult ? "adult" : "baby"] slime[Victim ? "" : " eat"]" - overlays.len = 0 - if (mood) - overlays += image('icons/mob/slimes.dmi', icon_state = "aslime-[mood]") - ..() \ No newline at end of file diff --git a/code/modules/mob/living/default_language.dm b/code/modules/mob/living/default_language.dm index 94b08207b8..eefe4929f9 100644 --- a/code/modules/mob/living/default_language.dm +++ b/code/modules/mob/living/default_language.dm @@ -10,7 +10,7 @@ return 0 if(language == GLOB.all_languages[src.species_language]) - to_chat(src, "You will now speak your standard default language, [language], if you do not specify a language when speaking.") + to_chat(src, "You will now speak your standard default language, [language ? language : "common"], if you do not specify a language when speaking.") else if (language) if(language && !can_speak(language)) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index f980601d39..e3693533a8 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -70,34 +70,23 @@ proc/get_radio_key_from_channel(var/channel) return key /mob/living/proc/binarycheck() + return FALSE - if (istype(src, /mob/living/silicon/pai)) - return +/mob/proc/get_default_language() + return null - if (!ishuman(src)) - return - - var/mob/living/carbon/human/H = src - if (H.l_ear || H.r_ear) - var/obj/item/device/radio/headset/dongle - if(istype(H.l_ear,/obj/item/device/radio/headset)) - dongle = H.l_ear - else - dongle = H.r_ear - if(!istype(dongle)) return - if(dongle.translate_binary) return 1 - -/mob/living/proc/get_default_language() +/mob/living/get_default_language() return default_language //Takes a list of the form list(message, verb, whispering) and modifies it as needed //Returns 1 if a speech problem was applied, 0 otherwise /mob/living/proc/handle_speech_problems(var/list/message_data) - var/message = message_data[1] + var/list/message_pieces = message_data[1] var/verb = message_data[2] var/whispering = message_data[3] . = 0 +<<<<<<< HEAD if((HULK in mutations) && health >= 25 && length(message)) message = "[uppertext(message)]!!!" verb = pick("yells","roars","hollers") @@ -119,13 +108,35 @@ proc/get_radio_key_from_channel(var/channel) //VOREStation Edit End message_data[1] = message +======= + // Technically this rerolls the verb for as many say pieces as there are. _shrug_ + for(var/datum/multilingual_say_piece/S in message_pieces) + if(S.speaking && (S.speaking.flags & NO_STUTTER || S.speaking.flags & SIGNLANG)) + continue + + if((HULK in mutations) && health >= 25 && length(S.message)) + S.message = "[uppertext(S.message)]!!!" + verb = pick("yells","roars","hollers") + whispering = 0 + . = 1 + if(slurring) + S.message = slur(S.message) + verb = pick("slobbers","slurs") + . = 1 + if(stuttering) + S.message = stutter(S.message) + verb = pick("stammers","stutters") + . = 1 + + message_data[1] = message_pieces +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) message_data[2] = verb message_data[3] = whispering -/mob/living/proc/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) +/mob/living/proc/handle_message_mode(message_mode, list/message_pieces, verb, used_radios) if(message_mode == "intercom") for(var/obj/item/device/radio/intercom/I in view(1, null)) - I.talk_into(src, message, verb, speaking) + I.talk_into(src, message_pieces, verb) used_radios += I return 0 @@ -136,13 +147,13 @@ proc/get_radio_key_from_channel(var/channel) return returns /mob/living/proc/get_speech_ending(verb, var/ending) - if(ending=="!") + if(ending == "!") return pick("exclaims","shouts","yells") - if(ending=="?") + if(ending == "?") return "asks" return verb -/mob/living/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/whispering = 0) +/mob/living/say(var/message, var/whispering = 0) //If you're muted for IC chat if(client) if(message) @@ -161,98 +172,81 @@ proc/get_radio_key_from_channel(var/channel) var/message_mode = parse_message_mode(message, "headset") //Maybe they are using say/whisper to do a quick emote, so do those - switch(copytext(message,1,2)) - if("*") return emote(copytext(message,2)) - if("^") return custom_emote(1, copytext(message,2)) + switch(copytext(message, 1, 2)) + if("*") return emote(copytext(message, 2)) + if("^") return custom_emote(1, copytext(message, 2)) //Parse the radio code and consume it - if (message_mode) - if (message_mode == "headset") - message = copytext(message,2) //it would be really nice if the parse procs could do this for us. - else if (message_mode == "whisper") + if(message_mode) + if(message_mode == "headset") + message = copytext(message, 2) //it would be really nice if the parse procs could do this for us. + else if(message_mode == "whisper") whispering = 1 message_mode = null - message = copytext(message,3) + message = copytext(message, 3) else - message = copytext(message,3) + message = copytext(message, 3) //Clean up any remaining space on the left message = trim_left(message) //Parse the language code and consume it - if(!speaking) - speaking = parse_language(message) - - if(!speaking) - speaking = get_default_language() - - if(!can_speak(speaking)) - speaking = GLOB.all_languages[LANGUAGE_GIBBERISH] - var/babble_key = ",r" - message = babble_key + message - - if(speaking == get_default_language()) - var/new_message = ",[speaking.key]" - new_message += message - message = new_message - - if(speaking) - message = copytext(message,2+length(speaking.key)) - - //HIVEMIND languages always send to all people with that language - if(speaking && (speaking.flags & HIVEMIND)) - speaking.broadcast(src,trim(message)) + var/list/message_pieces = parse_languages(message) + if(istype(message_pieces, /datum/multilingual_say_piece)) // Little quark for dealing with hivemind/signlang languages. + var/datum/multilingual_say_piece/S = message_pieces // Yay for BYOND's hilariously broken typecasting for allowing us to do this. + S.speaking.broadcast(src, S.message) return 1 - //Self explanatory. - if(is_muzzled() && !(speaking && (speaking.flags & SIGNLANG))) + if(!LAZYLEN(message_pieces)) + log_runtime(EXCEPTION("Message failed to generate pieces. [message] - [json_encode(message_pieces)]")) + return 0 + + // If you're muzzled, you can only speak sign language + // However, sign language is handled above. + if(is_muzzled()) to_chat(src, "You're muzzled and cannot speak!") return - //Clean up any remaining junk on the left like spaces. - message = trim_left(message) - - //Autohiss handles auto-rolling tajaran R's and unathi S's/Z's - message = handle_autohiss(message, speaking) - //Whisper vars var/w_scramble_range = 5 //The range at which you get ***as*th**wi**** var/w_adverb //An adverb prepended to the verb in whispers var/w_not_heard //The message for people in watching range + var/datum/multilingual_say_piece/first_piece = message_pieces[1] + var/verb = "" //Handle language-specific verbs and adverb setup if necessary if(!whispering) //Just doing normal 'say' (for now, may change below) - verb = say_quote(message, speaking) - else if(whispering && speaking.whisper_verb) //Language has defined whisper verb - verb = speaking.whisper_verb + verb = say_quote(message, first_piece.speaking) + else if(whispering && first_piece.speaking.whisper_verb) //Language has defined whisper verb + verb = first_piece.speaking.whisper_verb w_not_heard = "[verb] something" else //Whispering but language has no whisper verb, use say verb w_adverb = pick("quietly", "softly") - verb = speaking.speech_verb - w_not_heard = "[speaking.speech_verb] something [w_adverb]" + verb = first_piece.speaking.speech_verb + w_not_heard = "[first_piece.speaking.speech_verb] something [w_adverb]" //For speech disorders (hulk, slurring, stuttering) - if(!(speaking && (speaking.flags & NO_STUTTER || speaking.flags & SIGNLANG))) - var/list/message_data = list(message, verb, whispering) - if(handle_speech_problems(message_data)) - message = message_data[1] - whispering = message_data[3] + var/list/message_data = list(message_pieces, verb, whispering) + if(handle_speech_problems(message_data)) + message_pieces = message_data[1] + whispering = message_data[3] - if(verb != message_data[2]) //They changed our verb - if(whispering) - w_adverb = pick("quietly", "softly") - verb = message_data[2] + if(verb != message_data[2]) //They changed our verb + if(whispering) + w_adverb = pick("quietly", "softly") + verb = message_data[2] //Whisper may have adverbs, add those if one was set - if(w_adverb) verb = "[verb] [w_adverb]" + if(w_adverb) + verb = "[verb] [w_adverb]" //If something nulled or emptied the message, forget it - if(!message || message == "") + if(!LAZYLEN(message_pieces)) return 0 //Radio message handling - var/list/obj/item/used_radios = new - if(handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, whispering)) + var/list/used_radios = list() + if(handle_message_mode(message_mode, message_pieces, verb, used_radios, whispering)) return 1 //For languages with actual speech sounds @@ -268,16 +262,19 @@ proc/get_radio_key_from_channel(var/channel) if(used_radios.len) italics = 1 message_range = 1 - if(speaking) - message_range = speaking.get_talkinto_msg_range(message) + + if(first_piece.speaking) + message_range = first_piece.speaking.get_talkinto_msg_range(message) var/msg - if(!speaking || !(speaking.flags & NO_TALK_MSG)) - msg = "\The [src] talks into \the [used_radios[1]]" - for(var/mob/living/M in hearers(5, src)) - if((M != src) && msg) + if(!first_piece.speaking || !(first_piece.speaking.flags & NO_TALK_MSG)) + msg = "[src] talks into [used_radios[1]]" + + if(msg) + for(var/mob/living/M in hearers(5, src) - src) M.show_message(msg) - if (speech_sound) - sound_vol *= 0.5 + + if(speech_sound) + sound_vol *= 0.5 //Set vars if we're still whispering by this point if(whispering) @@ -285,6 +282,7 @@ proc/get_radio_key_from_channel(var/channel) message_range = 1 sound_vol *= 0.5 +<<<<<<< HEAD //VOREStation edit - allows for custom say verbs, overriding all other say-verb types- e.g. "says loudly" instead of "shouts" //You'll still stammer if injured or slur if drunk, but it won't have those specific words var/ending = copytext(message, length(message)) @@ -308,6 +306,13 @@ proc/get_radio_key_from_channel(var/channel) if (speaking.flags & NONVERBAL) if (prob(30)) src.custom_emote(1, "[pick(speaking.signlang_verb)].") +======= + //Handle nonverbal languages here + for(var/datum/multilingual_say_piece/S in message_pieces) + if(S.speaking.flags & NONVERBAL) + if(prob(30)) + custom_emote(1, "[pick(S.speaking.signlang_verb)].") +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) //These will contain the main receivers of the message var/list/listening = list() @@ -318,12 +323,12 @@ proc/get_radio_key_from_channel(var/channel) if(T) //Air is too thin to carry sound at all, contact speech only var/datum/gas_mixture/environment = T.return_air() - var/pressure = (environment)? environment.return_pressure() : 0 + var/pressure = environment ? environment.return_pressure() : 0 if(pressure < SOUND_MINIMUM_PRESSURE) message_range = 1 //Air is nearing minimum levels, make text italics as a hint, and muffle sound - if (pressure < ONE_ATMOSPHERE*0.4) + if(pressure < ONE_ATMOSPHERE * 0.4) italics = 1 sound_vol *= 0.5 @@ -376,16 +381,16 @@ proc/get_radio_key_from_channel(var/channel) var/image/I1 = listening[M] || speech_bubble images_to_clients[I1] |= M.client M << I1 - M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol) + M.hear_say(message_pieces, verb, italics, src, speech_sound, sound_vol) if(whispering) //Don't even bother with these unless whispering if(dst > message_range && dst <= w_scramble_range) //Inside whisper scramble range if(M.client) var/image/I2 = listening[M] || speech_bubble images_to_clients[I2] |= M.client M << I2 - M.hear_say(stars(message), verb, speaking, alt_name, italics, src, speech_sound, sound_vol*0.2) + M.hear_say(stars_all(message_pieces), verb, italics, src, speech_sound, sound_vol*0.2) if(dst > w_scramble_range && dst <= world.view) //Inside whisper 'visible' range - M.show_message("[src.name] [w_not_heard].", 2) + M.show_message("[name] [w_not_heard].", 2) //Object message delivery for(var/obj/O in listening_obj) @@ -393,7 +398,7 @@ proc/get_radio_key_from_channel(var/channel) if(O && src) //If we still exist, when the spawn processes var/dst = get_dist(get_turf(O),get_turf(src)) if(dst <= message_range) - O.hear_talk(src, message, verb, speaking) + O.hear_talk(src, message_pieces, verb) //Remove all those images. At least it's just ONE spawn this time. spawn(30) @@ -410,7 +415,7 @@ proc/get_radio_key_from_channel(var/channel) if(message_mode) message = "([message_mode == "headset" ? "Common" : capitalize(message_mode)]) [message]" //Adds radio keys used if available if(whispering) - log_whisper(message,src) + log_whisper(message, src) else log_say(message, src) return 1 @@ -438,8 +443,41 @@ proc/get_radio_key_from_channel(var/channel) /obj/effect/speech_bubble var/mob/parent -/mob/living/proc/GetVoice() +/mob/proc/GetVoice() return name +/mob/living/emote(var/act, var/type, var/message) //emote code is terrible, this is so that anything that isn't + if(stat) //already snowflaked to shit can call the parent and handle emoting sanely + return FALSE + + if(..(act, type, message)) + return TRUE + + if(act && type && message) + log_emote(message, src) + + for(var/mob/M in dead_mob_list) + if(!M.client) + continue + + if(isnewplayer(M)) + continue + + if(isobserver(M) && M.is_preference_enabled(/datum/client_preference/ghost_sight)) + M.show_message(message) + + switch(type) + if(1) // Visible + visible_message(message) + return TRUE + if(2) // Audible + audible_message(message) + return TRUE + else + if(act == "help") + return // Mobs handle this individually + to_chat(src, "Unusable emote '[act]'. Say *help for a list.") + + /mob/proc/speech_bubble_appearance() return "normal" diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 4a5e3182d8..fa59ebf5c8 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -837,6 +837,69 @@ var/list/ai_verbs_default = list( // If that is ever fixed please update this proc. return TRUE + +/mob/living/silicon/ai/handle_track(message, verb = "says", mob/speaker = null, speaker_name, hard_to_hear) + if(hard_to_hear) + return + + var/jobname // the mob's "job" + var/mob/living/carbon/human/impersonating //The crew member being impersonated, if any. + var/changed_voice + + if(ishuman(speaker)) + var/mob/living/carbon/human/H = speaker + + if(H.wear_mask && istype(H.wear_mask,/obj/item/clothing/mask/gas/voice)) + changed_voice = 1 + var/list/impersonated = new() + var/mob/living/carbon/human/I = impersonated[speaker_name] + + if(!I) + for(var/mob/living/carbon/human/M in mob_list) + if(M.real_name == speaker_name) + I = M + impersonated[speaker_name] = I + break + + // If I's display name is currently different from the voice name and using an agent ID then don't impersonate + // as this would allow the AI to track I and realize the mismatch. + if(I && !(I.name != speaker_name && I.wear_id && istype(I.wear_id,/obj/item/weapon/card/id/syndicate))) + impersonating = I + jobname = impersonating.get_assignment() + else + jobname = "Unknown" + else + jobname = H.get_assignment() + + else if(iscarbon(speaker)) // Nonhuman carbon mob + jobname = "No id" + else if(isAI(speaker)) + jobname = "AI" + else if(isrobot(speaker)) + jobname = "Cyborg" + else if(istype(speaker, /mob/living/silicon/pai)) + jobname = "Personal AI" + else + jobname = "Unknown" + + var/track = "" + if(changed_voice) + if(impersonating) + track = "[speaker_name] ([jobname])" + else + track = "[speaker_name] ([jobname])" + else + track = "[speaker_name] ([jobname])" + + return track + +/mob/living/silicon/ai/proc/relay_speech(mob/living/M, list/message_pieces, verb) + var/message = combine_message(message_pieces, verb, M) + var/name_used = M.GetVoice() + //This communication is imperfect because the holopad "filters" voices and is only designed to connect to the master only. + var/rendered = "Relayed Speech: [name_used] [message]" + show_message(rendered, 2) + //Special subtype kept around for global announcements /mob/living/silicon/ai/announcer/ is_dummy = 1 diff --git a/code/modules/mob/living/silicon/emote.dm b/code/modules/mob/living/silicon/emote.dm new file mode 100644 index 0000000000..ff3e340419 --- /dev/null +++ b/code/modules/mob/living/silicon/emote.dm @@ -0,0 +1,113 @@ +/mob/living/silicon/emote(var/act, var/m_type = 1,var/message = null) + var/param = null + if(findtext(act, "-", 1, null)) + var/t1 = findtext(act, "-", 1, null) + param = copytext(act, t1 + 1, length(act) + 1) + act = copytext(act, 1, t1) + + if(findtext(act, "s", -1) && !findtext(act, "_", -2))//Removes ending s's unless they are prefixed with a '_' + act = copytext(act, 1, length(act)) + + switch(act) + if("beep") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] beeps at [param]." + else + message = "[src] beeps." + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) + m_type = 1 + + if("ping") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] pings at [param]." + else + message = "[src] pings." + playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) + m_type = 1 + + if("buzz") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] buzzes at [param]." + else + message = "[src] buzzes." + playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + m_type = 1 + + if("yes", "ye") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] emits an affirmative blip at [param]." + else + message = "[src] emits an affirmative blip." + playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0) + m_type = 1 + + if("dwoop") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] chirps happily at [param]" + else + message = "[src] chirps happily." + playsound(src.loc, 'sound/machines/dwoop.ogg', 50, 0) + m_type = 1 + + if("no") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] emits a negative blip at [param]." + else + message = "[src] emits a negative blip." + playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0) + m_type = 1 + + ..(act, m_type, message) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/say.dm b/code/modules/mob/living/silicon/pai/say.dm index 2c7bc900d6..4b18c42beb 100644 --- a/code/modules/mob/living/silicon/pai/say.dm +++ b/code/modules/mob/living/silicon/pai/say.dm @@ -1,5 +1,5 @@ -/mob/living/silicon/pai/say(var/msg) +/mob/living/silicon/pai/say(var/message, var/datum/language/speaking = null, var/whispering = 0) if(silence_time) to_chat(src, "Communication circuits remain uninitialized.") else - ..(msg) \ No newline at end of file + ..() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/drone/drone_say.dm b/code/modules/mob/living/silicon/robot/drone/drone_say.dm index 76e104cfb2..5e8dd6dc74 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_say.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_say.dm @@ -1,4 +1,4 @@ -/mob/living/silicon/robot/drone/say(var/message) +/mob/living/silicon/robot/drone/say(var/message, var/datum/language/speaking = null, var/whispering = 0) if(local_transmit) if (src.client) if(client.prefs.muted & MUTE_IC) @@ -36,4 +36,4 @@ if(M.client) to_chat(M, "[src] transmits, \"[message]\"") return 1 - return ..(message, 0) \ No newline at end of file + return ..() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm index 881f827929..4f2a23bce5 100644 --- a/code/modules/mob/living/silicon/robot/emote.dm +++ b/code/modules/mob/living/silicon/robot/emote.dm @@ -1,6 +1,6 @@ /mob/living/silicon/robot/emote(var/act,var/m_type=1,var/message = null) var/param = null - if (findtext(act, "-", 1, null)) + if(findtext(act, "-", 1, null)) var/t1 = findtext(act, "-", 1, null) param = copytext(act, t1 + 1, length(act) + 1) act = copytext(act, 1, t1) @@ -9,236 +9,124 @@ act = copytext(act,1,length(act)) switch(act) - if ("me") - if (src.client) - if(client.prefs.muted & MUTE_IC) - to_chat(src, "You cannot send IC messages (muted).") - return - if (stat) - return - if(!(message)) - return - else - return custom_emote(m_type, message) - - if ("custom") - return custom_emote(m_type, message) - - if ("salute") - if (!src.buckled) + if("salute") + if(!src.buckled) var/M = null - if (param) + if(param) for (var/mob/A in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break - if (!M) + if(!M) param = null - if (param) - message = "salutes to [param]." + if(param) + message = "[src] salutes to [param]." else - message = "salutes." + message = "[src] salutes." m_type = 1 - if ("bow") - if (!src.buckled) + if("bow") + if(!src.buckled) var/M = null - if (param) + if(param) for (var/mob/A in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break - if (!M) + if(!M) param = null - if (param) - message = "bows to [param]." + if(param) + message = "[src] bows to [param]." else - message = "bows." + message = "[src] bows." m_type = 1 - if ("clap") - if (!src.restrained()) - message = "claps." + if("clap") + if(!src.restrained()) + message = "[src] claps." m_type = 2 - if ("flap") - if (!src.restrained()) - message = "flaps its wings." + if("flap") + if(!src.restrained()) + message = "[src] flaps its wings." m_type = 2 - if ("aflap") - if (!src.restrained()) - message = "flaps its wings ANGRILY!" + if("aflap") + if(!src.restrained()) + message = "[src] flaps its wings ANGRILY!" m_type = 2 - if ("twitch") - message = "twitches." + if("twitch") + message = "[src] twitches." m_type = 1 - if ("twitch_v") - message = "twitches violently." + if("twitch_v") + message = "[src] twitches violently." m_type = 1 - if ("nod") - message = "nods." + if("nod") + message = "[src] nods." m_type = 1 - if ("deathgasp") - message = "shudders violently for a moment, then becomes motionless, its eyes slowly darkening." + if("deathgasp") + message = "[src] shudders violently for a moment, then becomes motionless, its eyes slowly darkening." m_type = 1 - if ("glare") - var/M = null - if (param) - for (var/mob/A in view(null, null)) - if (param == A.name) - M = A - break - if (!M) - param = null - - if (param) - message = "glares at [param]." - else - message = "glares." - - if ("stare") - var/M = null - if (param) - for (var/mob/A in view(null, null)) - if (param == A.name) - M = A - break - if (!M) - param = null - - if (param) - message = "stares at [param]." - else - message = "stares." - - if ("look") - var/M = null - if (param) - for (var/mob/A in view(null, null)) - if (param == A.name) - M = A - break - - if (!M) - param = null - - if (param) - message = "looks at [param]." - else - message = "looks." - m_type = 1 - - if("beep") + if("glare") var/M = null if(param) for (var/mob/A in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break if(!M) param = null - if (param) - message = "beeps at [param]." + if(param) + message = "[src] glares at [param]." else - message = "beeps." - playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) - m_type = 1 + message = "[src] glares." - if("ping") + if("stare") var/M = null if(param) for (var/mob/A in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break if(!M) param = null - if (param) - message = "pings at [param]." + if(param) + message = "[src] stares at [param]." else - message = "pings." - playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) - m_type = 1 + message = "[src] stares." - if("buzz") + if("look") var/M = null if(param) for (var/mob/A in view(null, null)) - if (param == A.name) + if(param == A.name) M = A break + if(!M) param = null - if (param) - message = "buzzes at [param]." - else - message = "buzzes." - playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0) - m_type = 1 - - if("yes", "ye") - var/M = null if(param) - for (var/mob/A in view(null, null)) - if (param == A.name) - M = A - break - if(!M) - param = null - - if (param) - message = "emits an affirmative blip at [param]." + message = "[src] looks at [param]." else - message = "emits an affirmative blip." - playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0) - m_type = 1 - - if("dwoop") - var/M = null - if(param) - for (var/mob/A in view(null, null)) - M = A - break - if(!M) - param = null - - if (param) - message = "chirps happily at [param]" - else - message = "chirps happily." - playsound(src.loc, 'sound/machines/dwoop.ogg', 50, 0) - m_type = 1 - - - if("no") - var/M = null - if(param) - for (var/mob/A in view(null, null)) - if (param == A.name) - M = A - break - if(!M) - param = null - - if (param) - message = "emits a negative blip at [param]." - else - message = "emits a negative blip." - playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0) + message = "[src] looks." m_type = 1 if("law") +<<<<<<< HEAD if (istype(module,/obj/item/weapon/robot_module/robot/security) || istype(module,/obj/item/weapon/robot_module/robot/knine)) //VOREStation Add - K9 message = "shows its legal authorization barcode." +======= + if(istype(module,/obj/item/weapon/robot_module/robot/security)) + message = "[src] shows its legal authorization barcode." +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) playsound(src.loc, 'sound/voice/biamthelaw.ogg', 50, 0) m_type = 2 @@ -246,20 +134,20 @@ to_chat(src, "You are not THE LAW, pal.") if("halt") +<<<<<<< HEAD if (istype(module,/obj/item/weapon/robot_module/robot/security) || istype(module,/obj/item/weapon/robot_module/robot/knine)) //VOREStation Add - K9 message = "'s speakers skreech, \"Halt! Security!\"." +======= + if(istype(module,/obj/item/weapon/robot_module/robot/security)) + message = "[src] 's speakers skreech, \"Halt! Security!\"." +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) playsound(src.loc, 'sound/voice/halt.ogg', 50, 0) m_type = 2 else to_chat(src, "You are not security.") - if ("help") + if("help") to_chat(src, "salute, bow-(none)/mob, clap, flap, aflap, twitch, twitch_s, nod, deathgasp, glare-(none)/mob, stare-(none)/mob, look, beep, ping, \nbuzz, law, halt, yes, dwoop, no") - else - to_chat(src, "Unusable emote '[act]'. Say *help for a list.") - if ((message && src.stat == 0)) - custom_emote(m_type,message) - - return + ..(act, m_type, message) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index 0867fedff8..41df4c5146 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -1,10 +1,4 @@ -/mob/living/silicon/say(var/message, var/sanitize = 1, var/whispering = 0) - return ..((sanitize ? sanitize(message) : message), whispering = whispering) - -/mob/living/silicon/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) - log_say(message, src) - -/mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) +/mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios) ..() if(message_mode) if(!is_component_functioning("radio")) @@ -17,7 +11,7 @@ /mob/living/silicon/speech_bubble_appearance() return "synthetic" -/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) +/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios) ..() if(message_mode == "department") return holopad_talk(message, verb, speaking) @@ -29,7 +23,7 @@ message_mode = null return aiRadio.talk_into(src,message,message_mode,verb,speaking) -/mob/living/silicon/pai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) +/mob/living/silicon/pai/handle_message_mode(message_mode, message, verb, speaking, used_radios) ..() if(message_mode) if(message_mode == "general") @@ -50,29 +44,24 @@ #define IS_ROBOT 2 #define IS_PAI 3 -/mob/living/silicon/say_understands(var/other,var/datum/language/speaking = null) +/mob/living/silicon/say_understands(var/other, var/datum/language/speaking = null) //These only pertain to common. Languages are handled by mob/say_understands() - if (!speaking) - if (istype(other, /mob/living/carbon)) - return 1 - if (istype(other, /mob/living/silicon)) - return 1 - if (istype(other, /mob/living/carbon/brain)) - return 1 + if(!speaking) + if(iscarbon(other)) + return TRUE + if(issilicon(other)) + return TRUE + if(isbrain(other)) + return TRUE return ..() //For holopads only. Usable by AI. -/mob/living/silicon/ai/proc/holopad_talk(var/message, verb, datum/language/speaking) - - log_say("(HPAD) [message]",src) - - message = trim(message) - - if (!message) - return +/mob/living/silicon/ai/proc/holopad_talk(list/message_pieces, verb) + log_say("(HPAD) [multilingual_to_message(message_pieces)]",src) var/obj/machinery/hologram/holopad/T = src.holo if(T && T.masters[src])//If there is a hologram and its master is the user. +<<<<<<< HEAD //Human-like, sorta, heard by those who understand humans. var/rendered_a //Speech distorted, heard by those who do not understand AIs. @@ -87,33 +76,29 @@ rendered_a = "[name] [verb], \"[message]\"" rendered_b = "[voice_name] [verb], \"[message_stars]\"" to_chat(src, "Holopad transmitted, [real_name] [verb], \"[message]\"") //The AI can "hear" its own message. +======= +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) var/list/listeners = get_mobs_and_objs_in_view_fast(get_turf(T), world.view) var/list/listening = listeners["mobs"] var/list/listening_obj = listeners["objs"] for(var/mob/M in listening) - spawn(0) - if(M.say_understands(src))//If they understand AI speak. Humans and the like will be able to. - M.show_message(rendered_a, 2) - else//If they do not. - M.show_message(rendered_b, 2) + M.hear_holopad_talk(message_pieces, verb, src) for(var/obj/O in listening_obj) if(O == T) //Don't recieve your own speech continue - spawn(0) - if(O && src) //If we still exist, when the spawn processes - O.hear_talk(src, message, verb, speaking) + O.hear_talk(src, message_pieces, verb) /*Radios "filter out" this conversation channel so we don't need to account for them. This is another way of saying that we won't bother dealing with them.*/ + to_chat(src, "Holopad transmitted, [real_name] [combine_message(message_pieces, verb, src)]") else to_chat(src, "No holopad connected.") return 0 return 1 /mob/living/silicon/ai/proc/holopad_emote(var/message) //This is called when the AI uses the 'me' verb while using a holopad. - message = trim(message) - if (!message) + if(!message) return var/obj/machinery/hologram/holopad/T = src.holo @@ -147,11 +132,11 @@ return 1 /mob/living/silicon/ai/emote(var/act, var/type, var/message) - var/obj/machinery/hologram/holopad/T = src.holo + var/obj/machinery/hologram/holopad/T = holo if(T && T.masters[src]) //Is the AI using a holopad? - src.holopad_emote(message) + . = holopad_emote(message) else //Emote normally, then. - ..() + . = ..() #undef IS_AI #undef IS_ROBOT diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 6a74eb41d5..9ad7179cca 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -193,7 +193,14 @@ //Silicon mob language procs /mob/living/silicon/can_speak(datum/language/speaking) - return universal_speak || (speaking in src.speech_synthesizer_langs) || (speaking.name == "Noise") //need speech synthesizer support to vocalize a language + if(universal_speak) + return TRUE + //need speech synthesizer support to vocalize a language + if(speaking in speech_synthesizer_langs) + return TRUE + if(speaking && speaking.flags & INNATE) + return TRUE + return FALSE /mob/living/silicon/add_language(var/language, var/can_speak=1) var/var/datum/language/added_language = GLOB.all_languages[language] @@ -213,15 +220,11 @@ ..(rem_language) speech_synthesizer_langs -= removed_language -/mob/living/silicon/check_languages() - set name = "Check Known Languages" - set category = "IC" - set src = usr - - var/dat = "Known Languages

" +/mob/living/silicon/check_lang_data() + . = "" if(default_language) - dat += "Current default language: [default_language] - reset

" + . += "Current default language: [default_language] - reset

" for(var/datum/language/L in languages) if(!(L.flags & NONGLOBAL)) @@ -232,10 +235,7 @@ default_str = " - set default" var/synth = (L in speech_synthesizer_langs) - dat += "[L.name] ([get_language_prefix()][L.key])[synth ? default_str : null]
Speech Synthesizer: [synth ? "YES" : "NOT SUPPORTED"]
[L.desc]

" - - src << browse(dat, "window=checklanguage") - return + . += "[L.name] ([get_language_prefix()][L.key])[synth ? default_str : null]
Speech Synthesizer: [synth ? "YES" : "NOT SUPPORTED"]
[L.desc]

" /mob/living/silicon/proc/toggle_sensor_mode() var/sensor_type = input("Please select sensor type.", "Sensor Integration", null) in list("Security","Medical","Disable") diff --git a/code/modules/mob/living/simple_mob/simple_mob.dm b/code/modules/mob/living/simple_mob/simple_mob.dm index c9030b0860..71e7736ebb 100644 --- a/code/modules/mob/living/simple_mob/simple_mob.dm +++ b/code/modules/mob/living/simple_mob/simple_mob.dm @@ -194,12 +194,6 @@ . = ..() to_chat(src,"You are \the [src]. [player_msg]") - -/mob/living/simple_mob/emote(var/act, var/type, var/desc) - if(act) - ..(act, type, desc) - - /mob/living/simple_mob/SelfMove(turf/n, direct) var/turf/old_turf = get_turf(src) var/old_dir = dir @@ -264,14 +258,11 @@ update_icon() -/mob/living/simple_mob/say(var/message,var/datum/language/language) - var/verb = "says" +/mob/living/simple_mob/say_quote(var/message, var/datum/language/speaking = null) if(speak_emote.len) - verb = pick(speak_emote) - - message = sanitize(message) - - ..(message, null, verb) + . = pick(speak_emote) + else if(speaking) + . = ..() /mob/living/simple_mob/get_speech_ending(verb, var/ending) return verb diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm index 6ea44df66d..e1f7535bf8 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm @@ -205,7 +205,7 @@ return // This is awful but its literally say code. -/mob/living/simple_mob/animal/borer/say(message) +/mob/living/simple_mob/animal/borer/say(var/message, var/datum/language/speaking = null, var/whispering = 0) message = sanitize(message) message = capitalize(message) @@ -224,10 +224,11 @@ if(copytext(message, 1, 2) == "*") return emote(copytext(message, 2)) - var/datum/language/L = parse_language(message) - if(L && L.flags & HIVEMIND) - L.broadcast(src,trim(copytext(message,3)), src.true_name) - return + var/list/message_pieces = parse_languages(message) + for(var/datum/multilingual_say_piece/S in message_pieces) + if(S.speaking && S.speaking.flags & HIVEMIND) + S.speaking.broadcast(src, trim(copytext(message, 3)), src.true_name) + return if(!host) if(chemicals >= 30) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer_captive.dm b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer_captive.dm index 4f117d485c..618efee6dc 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer_captive.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer_captive.dm @@ -5,7 +5,7 @@ real_name = "host brain" universal_understand = 1 -/mob/living/captive_brain/say(var/message) +/mob/living/captive_brain/say(var/message, var/datum/language/speaking = null, var/whispering = 0) if (src.client) if(client.prefs.muted & MUTE_IC) @@ -31,7 +31,12 @@ else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) to_chat(M, "The captive mind of [src] whispers, \"[message]\"") +/mob/living/captive_brain/me_verb(message as text) + to_chat(src, "You cannot emote as a captive mind.") + return + /mob/living/captive_brain/emote(var/message) + to_chat(src, "You cannot emote as a captive mind.") return /mob/living/captive_brain/process_resist() diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm b/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm index dc611e3831..427c0fff9c 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD // Parrots can talk, and may repeat things it hears. /mob/living/simple_mob/animal/passive/bird/parrot name = "parrot" @@ -249,4 +250,257 @@ if(holder.stat || !holder.say_list || !message || speaker == holder) return var/datum/say_list/S = holder.say_list +======= +// Parrots can talk, and may repeat things it hears. +/mob/living/simple_mob/animal/passive/bird/parrot + name = "parrot" + description_info = "You can give it a headset by clicking on it with a headset. \ + To remove it, click the bird while on grab intent." + has_langs = list("Galactic Common", "Bird") + + ai_holder_type = /datum/ai_holder/simple_mob/passive/parrot + + // A headset, so that talking parrots can yell at the crew over comms. + // If set to a type, on initialize it will be instantiated into that type. + var/obj/item/device/radio/headset/my_headset = null + +// Say list +/datum/say_list/bird/poly + speak = list( + "Poly wanna cracker!", + "Check the singulo, you chucklefucks!", + "Wire the solars, you lazy bums!", + "WHO TOOK THE DAMN HARDSUITS?", + "OH GOD ITS FREE CALL THE SHUTTLE", + "Danger! Crystal hyperstructure instability!", + "CRYSTAL DELAMINATION IMMINENT.", + "Tweet tweet, I'm a Teshari.", + "Chitters.", + "Meteors have been detected on a collision course with the station!" + ) + +// Lets the AI use headsets. +// Player-controlled parrots will need to do it manually. +/mob/living/simple_mob/animal/passive/bird/parrot/ISay(message) + if(my_headset && prob(50)) + var/list/keys = list() + for(var/channel in my_headset.channels) + var/key = get_radio_key_from_channel(channel) + if(key) + keys += key + if(keys.len) + var/key_used = pick(keys) + return say("[key_used] [message]") + return say(message) + +// Ugly saycode so parrots can use their headsets. +/mob/living/simple_mob/animal/passive/bird/parrot/handle_message_mode(message_mode, message, verb, speaking, used_radios) + ..() + if(message_mode) + if(my_headset && istype(my_headset, /obj/item/device/radio)) + my_headset.talk_into(src, message, message_mode, verb, speaking) + used_radios += my_headset + +// Clicked on while holding an object. +/mob/living/simple_mob/animal/passive/bird/parrot/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/device/radio/headset)) + give_headset(I, user) + return + return ..() + +// Clicked on by empty hand. +/mob/living/simple_mob/animal/passive/bird/parrot/attack_hand(mob/living/L) + if(L.a_intent == I_GRAB && my_headset) + remove_headset(L) + else + ..() + + +/mob/living/simple_mob/animal/passive/bird/parrot/proc/give_headset(obj/item/device/radio/headset/new_headset, mob/living/user) + if(!istype(new_headset)) + to_chat(user, span("warning", "\The [new_headset] isn't a headset.")) + return + if(my_headset) + to_chat(user, span("warning", "\The [src] is already wearing \a [my_headset].")) + return + else + user.drop_item(new_headset) + my_headset = new_headset + new_headset.forceMove(src) + to_chat(user, span("warning", "You place \a [new_headset] on \the [src]. You monster.")) + to_chat(src, span("notice", "\The [user] gives you \a [new_headset]. You should put it to good use immediately.")) + return + +/mob/living/simple_mob/animal/passive/bird/parrot/proc/remove_headset(mob/living/user) + if(!my_headset) + to_chat(user, "\The [src] doesn't have a headset to remove, thankfully.") + else + ISay("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") + my_headset.forceMove(get_turf(src)) + user.put_in_hands(my_headset) + to_chat(user, span("notice", "You take away \the [src]'s [my_headset.name]. Finally.")) + to_chat(src, span("warning", "\The [user] takes your [my_headset.name] away! How cruel!")) + my_headset = null + +/mob/living/simple_mob/animal/passive/bird/parrot/examine(mob/user) + ..() + if(my_headset) + to_chat(user, "It is wearing \a [my_headset].") + +/mob/living/simple_mob/animal/passive/bird/parrot/Initialize() + if(my_headset) + my_headset = new my_headset(src) + return ..() + +// Subtypes. + +// Best Bird +/mob/living/simple_mob/animal/passive/bird/parrot/poly + name = "Poly" + desc = "It's a parrot. An expert on quantum cracker theory." + icon_state = "poly" + icon_rest = "poly-held" + icon_dead = "poly-dead" + tt_desc = "E Ara macao" + my_headset = /obj/item/device/radio/headset/headset_eng + say_list_type = /datum/say_list/bird/poly + +// Best Bird with best headset. +/mob/living/simple_mob/animal/passive/bird/parrot/poly/ultimate + my_headset = /obj/item/device/radio/headset/omni + +/mob/living/simple_mob/animal/passive/bird/parrot/kea + name = "kea" + desc = "A species of parrot. On Earth, they are unique among other parrots for residing in alpine climates. \ + They are known to be intelligent and curious, which has made some consider them a pest." + icon_state = "kea" + icon_rest = "kea-held" + icon_dead = "kea-dead" + tt_desc = "E Nestor notabilis" + +/mob/living/simple_mob/animal/passive/bird/parrot/eclectus + name = "eclectus" + desc = "A species of parrot, this species features extreme sexual dimorphism in their plumage's colors. \ + A male eclectus has emerald green plumage, where as a female eclectus has red and purple plumage." + icon_state = "eclectus" + icon_rest = "eclectus-held" + icon_dead = "eclectus-dead" + tt_desc = "E Eclectus roratus" + +/mob/living/simple_mob/animal/passive/bird/parrot/eclectus/Initialize() + gender = pick(MALE, FEMALE) + if(gender == FEMALE) + icon_state = "eclectusf" + icon_rest = "eclectusf-held" + icon_dead = "eclectusf-dead" + return ..() + +/mob/living/simple_mob/animal/passive/bird/parrot/grey_parrot + name = "grey parrot" + desc = "A species of parrot. This one is predominantly grey, but has red tail feathers." + icon_state = "agrey" + icon_rest = "agrey-held" + icon_dead = "agrey-dead" + tt_desc = "E Psittacus erithacus" + +/mob/living/simple_mob/animal/passive/bird/parrot/black_headed_caique + name = "black-headed caique" + desc = "A species of parrot, these birds have a distinct black color on their heads, distinguishing them from their relative Caiques." + icon_state = "bcaique" + icon_rest = "bcaique-held" + icon_dead = "bcaique-dead" + tt_desc = "E Pionites melanocephalus" + +/mob/living/simple_mob/animal/passive/bird/parrot/white_caique + name = "white-bellied caique" + desc = "A species of parrot, they are also known as the Green-Thighed Parrot." + icon_state = "wcaique" + icon_rest = "wcaique-held" + icon_dead = "wcaique-dead" + tt_desc = "E Pionites leucogaster" + +/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar + name = "budgerigar" + desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \ + This one is has its natural colors of green and yellow." + icon_state = "gbudge" + icon_rest = "gbudge-held" + icon_dead = "gbudge-dead" + tt_desc = "E Melopsittacus undulatus" + +/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/blue + icon_state = "bbudge" + icon_rest = "bbudge-held" + icon_dead = "bbudge-dead" + desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \ + This one has a mutation which altered its color to be blue instead of green and yellow." + +/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/bluegreen + icon_state = "bgbudge" + icon_rest = "bgbudge-held" + icon_dead = "bgbudge-dead" + desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \ + This one has a mutation which altered its color to be a mix of blue and green." + +/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel + name = "cockatiel" + desc = "A species of parrot. This one has a highly visible crest." + icon_state = "tiel" + icon_rest = "tiel-held" + icon_dead = "tiel-dead" + tt_desc = "E Nymphicus hollandicus" + +/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/white + icon_state = "wtiel" + icon_rest = "wtiel-held" + icon_dead = "wtiel-dead" + +/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/yellowish + icon_state = "luttiel" + icon_rest = "luttiel-held" + icon_dead = "luttiel-dead" + +/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/grey + icon_state = "blutiel" // idk why this is blu. + icon_rest = "blutiel-held" + icon_dead = "blutiel-dead" + +// This actually might be the yellow-crested cockatoo but idk. +/mob/living/simple_mob/animal/passive/bird/parrot/sulphur_cockatoo + name = "sulphur-crested cockatoo" + desc = "A species of parrot. This one has an expressive yellow crest. Their underwing and tail feathers are also yellow." + icon_state = "too" + icon_rest = "too-held" + icon_dead = "too-dead" + tt_desc = "E Cacatua galerita" + +// This was originally called 'hooded_too', which might not mean the unbrella cockatoo but idk. +/mob/living/simple_mob/animal/passive/bird/parrot/white_cockatoo + name = "white cockatoo" + desc = "A species of parrot. This one is also known as the Umbrella Cockatoo, due to the semicircular shape of its crest." + icon_state = "utoo" + icon_rest = "utoo-held" + icon_dead = "utoo-dead" + tt_desc = "E Cacatua alba" + +/mob/living/simple_mob/animal/passive/bird/parrot/pink_cockatoo + name = "pink cockatoo" + desc = "A species of parrot. This one is also known as Major Mitchell's cockatoo, \ + in honor of a human surveyor and explorer who existed before humans fully explored their home planet." + icon_state = "mtoo" + icon_rest = "mtoo-held" + icon_dead = "mtoo-dead" + tt_desc = "E Lophochroa leadbeateri" + + +// AI +/datum/ai_holder/simple_mob/passive/parrot + speak_chance = 2 + base_wander_delay = 8 + +/datum/ai_holder/simple_mob/passive/parrot/on_hear_say(mob/living/speaker, message) + if(holder.stat || !holder.say_list || !message || speaker == holder) + return + var/datum/say_list/S = holder.say_list +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) S.speak |= message \ No newline at end of file diff --git a/code/modules/mob/living/voice/voice.dm b/code/modules/mob/living/voice/voice.dm index 92270dc145..919e302bcf 100644 --- a/code/modules/mob/living/voice/voice.dm +++ b/code/modules/mob/living/voice/voice.dm @@ -104,7 +104,7 @@ // Proc: say() // Parameters: 4 (generic say() arguments) // Description: Adds a speech bubble to the communicator device, then calls ..() to do the real work. -/mob/living/voice/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/whispering=0) +/mob/living/voice/say(var/message, var/datum/language/speaking = null, var/whispering = 0) //Speech bubbles. if(comm) var/speech_bubble_test = say_test(message) @@ -118,7 +118,7 @@ M << speech_bubble src << speech_bubble - ..(message, speaking, verb, alt_name, whispering) //mob/living/say() can do the actual talking. + ..() //mob/living/say() can do the actual talking. // Proc: speech_bubble_appearance() // Parameters: 0 @@ -126,15 +126,15 @@ /mob/living/voice/speech_bubble_appearance() return "comm" -/mob/living/voice/say_understands(var/other,var/datum/language/speaking = null) +/mob/living/voice/say_understands(var/other, var/datum/language/speaking = null) //These only pertain to common. Languages are handled by mob/say_understands() - if (!speaking) - if (istype(other, /mob/living/carbon)) - return 1 - if (istype(other, /mob/living/silicon)) - return 1 - if (istype(other, /mob/living/carbon/brain)) - return 1 + if(!speaking) + if(iscarbon(other)) + return TRUE + if(issilicon(other)) + return TRUE + if(isbrain(other)) + return TRUE return ..() /mob/living/voice/custom_emote(var/m_type=1,var/message = null,var/range=world.view) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 68ea573a72..d1d65ff21d 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1224,3 +1224,6 @@ mob/proc/yank_out_object() selfimage.loc = src return selfimage + +/mob/proc/GetAltName() + return "" diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 5450ced7ee..7c1034a77d 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -184,6 +184,12 @@ proc/getsensorlevel(A) p++ return t +/proc/stars_all(list/message_pieces, pr) + // eugh, we have to clone the list to avoid collateral damage due to the nature of these messages + . = list() + for(var/datum/multilingual_say_piece/S in message_pieces) + . += new /datum/multilingual_say_piece(S.speaking, stars(S.message)) + proc/slur(phrase) phrase = html_decode(phrase) var/leng=length(phrase) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index bfdc39b25e..81804d7119 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -605,7 +605,7 @@ return ready && ..() // Prevents lobby players from seeing say, even with ghostears -/mob/new_player/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null) +/mob/new_player/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/italics = 0, var/mob/speaker = null) return // Prevents lobby players from seeing emotes, even with ghosteyes diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index 25d506d91a..439e3c5314 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -1,4 +1,4 @@ -/mob/proc/say() +/mob/proc/say(var/message, var/datum/language/speaking = null, var/whispering = 0) return /mob/verb/whisper(message as text) @@ -30,7 +30,7 @@ set_typing_indicator(FALSE) if(use_me) - usr.emote("me",usr.emote_type,message) + custom_emote(usr.emote_type, message) else usr.emote(message) @@ -42,7 +42,7 @@ if(!client) return // Clientless mobs shouldn't be trying to talk in deadchat. - if(!src.client.holder) + if(!client.holder) if(!config.dsay_allowed) to_chat(src, "Deadchat is globally muted.") return @@ -55,55 +55,55 @@ say_dead_direct("[pick("complains","moans","whines","laments","blubbers")], \"[message]\"", src) -/mob/proc/say_understands(var/mob/other,var/datum/language/speaking = null) - - if (src.stat == DEAD) - return 1 +/mob/proc/say_understands(var/mob/other, var/datum/language/speaking = null) + if(stat == DEAD) + return TRUE //Universal speak makes everything understandable, for obvious reasons. - else if(src.universal_speak || src.universal_understand) - return 1 + else if(universal_speak || universal_understand) + return TRUE //Languages are handled after. - if (!speaking) + if(!speaking) if(!other) - return 1 + return TRUE if(other.universal_speak) - return 1 + return TRUE if(isAI(src) && ispAI(other)) - return 1 - if (istype(other, src.type) || istype(src, other.type)) - return 1 - return 0 + return TRUE + if(istype(other, type) || istype(src, other.type)) + return TRUE + return FALSE if(speaking.flags & INNATE) - return 1 + return TRUE + + //non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet. + if(speaking.flags & NONVERBAL) + if(sdisabilities & BLIND || blinded) + return FALSE + if(!other || !(other in view(src))) + return FALSE //Language check. - for(var/datum/language/L in src.languages) + for(var/datum/language/L in languages) if(speaking.name == L.name) - return 1 + return TRUE - return 0 - -/* - ***Deprecated*** - let this be handled at the hear_say or hear_radio proc - This is left in for robot speaking when humans gain binary channel access until I get around to rewriting - robot_talk() proc. - There is no language handling build into it however there is at the /mob level so we accept the call - for it but just ignore it. -*/ + return FALSE /mob/proc/say_quote(var/message, var/datum/language/speaking = null) - var/verb = "says" - var/ending = copytext(message, length(message)) - if(ending=="!") - verb=pick("exclaims","shouts","yells") - else if(ending=="?") - verb="asks" + var/verb = "says" + var/ending = copytext(message, length(message)) - return verb + if(speaking) + verb = speaking.get_spoken_verb(ending) + else + if(ending == "!") + verb = pick("exclaims", "shouts", "yells") + else if(ending == "?") + verb = "asks" + return verb /mob/proc/emote(var/act, var/type, var/message) @@ -120,38 +120,123 @@ /mob/proc/say_test(var/text) var/ending = copytext(text, length(text)) - if (ending == "?") + if(ending == "?") return "1" - else if (ending == "!") + else if(ending == "!") return "2" return "0" //parses the message mode code (e.g. :h, :w) from text, such as that supplied to say. //returns the message mode string or null for no message mode. //standard mode is the mode returned for the special ';' radio code. -/mob/proc/parse_message_mode(var/message, var/standard_mode="headset") - if(length(message) >= 1 && copytext(message,1,2) == ";") +/mob/proc/parse_message_mode(var/message, var/standard_mode = "headset") + if(length(message) >= 1 && copytext(message, 1, 2) == ";") return standard_mode if(length(message) >= 2) - var/channel_prefix = copytext(message, 1 ,3) + var/channel_prefix = copytext(message, 1, 3) return department_radio_keys[channel_prefix] return null -//parses the language code (e.g. :j) from text, such as that supplied to say. -//returns the language object only if the code corresponds to a language that src can speak, otherwise null. -/mob/proc/parse_language(var/message) - var/prefix = copytext(message,1,2) - // This is for audible emotes - if(length(message) >= 1 && prefix == "!") - return GLOB.all_languages["Noise"] +/datum/multilingual_say_piece + var/datum/language/speaking = null + var/message = "" - if(length(message) >= 2 && is_language_prefix(prefix)) - var/language_prefix = copytext(message, 2 ,3) - var/datum/language/L = GLOB.language_keys[language_prefix] - if (can_speak(L)) - return L +/datum/multilingual_say_piece/New(datum/language/new_speaking, new_message) + . = ..() + speaking = new_speaking + if(new_message) + message = new_message + +/mob/proc/find_valid_prefixes(message) + var/list/prefixes = list() // [["Common", start, end], ["Gutter", start, end]] + for(var/i in 1 to length(message)) + // This grabs trimmed 3 character substrings, to allow for up to 1 prefix and 1 letter language keys + var/selection = trim_right(lowertext(copytext(message, i, i + 2))) + // The first character in the selection will always be the prefix (if this is a valid language invocation) + var/prefix = copytext(selection, 1, 2) + var/language_key = copytext(selection, 2, 3) + if(is_language_prefix(prefix)) + // Okay, we're definitely now trying to invoke a language (probably) + // This "[]" is probably unnecessary but BYOND will runtime if a number is used + var/datum/language/L = GLOB.language_keys["[language_key]"] + // It's kinda silly that we have to check L != null and this isn't done for us by can_speak (it runtimes instead), but w/e + if(L && can_speak(L)) + // So we have a valid language invocation, and we can speak that language, let's make a piece for it + // This language will be the language until the next prefixes[] index, or the end of the message if there are none. + prefixes[++prefixes.len] = list(L, i, i + length(selection)) + else if(L) + // We found a valid language, but they can't speak it. Let's make them speak gibberish instead. + prefixes[++prefixes.len] = list(GLOB.all_languages[LANGUAGE_GIBBERISH], i, i + length(selection)) + continue + if(i == 1) + // This covers the case of "no prefixes in use." + prefixes[++prefixes.len] = list(get_default_language(), i, i) + + return prefixes + +/mob/proc/strip_prefixes(message, mob/prefixer = null) + . = "" + var/last_index = 1 + for(var/i in 1 to length(message)) + var/selection = trim_right(lowertext(copytext(message, i, i + 2))) + // The first character in the selection will always be the prefix (if this is a valid language invocation) + var/prefix = copytext(selection, 1, 2) + var/language_key = copytext(selection, 2, 3) + if(is_language_prefix(prefix)) + var/datum/language/L = GLOB.language_keys["[language_key]"] + if(L) + . += copytext(message, last_index, i) + last_index = i + 2 + if(i + 1 > length(message)) + . += copytext(message, last_index) + +// this returns a structured message with language sections +// list(/datum/multilingual_say_piece(common, "hi"), /datum/multilingual_say_piece(farwa, "squik"), /datum/multilingual_say_piece(common, "meow!")) +/mob/proc/parse_languages(message) + . = list() + + // Noise language is a snowflake. + if(copytext(message, 1, 2) == "!" && length(message) > 1) + // Note that list() here is intended + // Returning a raw /datum/multilingual_say_piece is supported, but only for hivemind languages + // What we actually want is a normal say piece that's all noise lang + return list(new /datum/multilingual_say_piece(GLOB.all_languages["Noise"], trim(strip_prefixes(copytext(message, 2))))) + + // Scan the message for prefixes + var/list/prefix_locations = find_valid_prefixes(message) + if(!LAZYLEN(prefix_locations)) // There are no prefixes... or at least, no _valid_ prefixes. + . += new /datum/multilingual_say_piece(get_default_language(), trim(strip_prefixes(message))) // So we'll just strip those pesky things and still make the message. + + for(var/i in 1 to length(prefix_locations)) + var/current = prefix_locations[i] // ["Common", start, end] + + // There are a few things that will make us want to ignore all other languages in - namely, HIVEMIND languages. + var/datum/language/L = current[1] + if(L && (L.flags & HIVEMIND || L.flags & SIGNLANG)) + return new /datum/multilingual_say_piece(L, trim(strip_prefixes(message))) + + if(i + 1 > length(prefix_locations)) // We are out of lookaheads, that means the rest of the message is in cur lang + var/spoke_message = handle_autohiss(trim(copytext(message, current[3])), L) + . += new /datum/multilingual_say_piece(current[1], spoke_message) else - return GLOB.all_languages[LANGUAGE_GIBBERISH] - return null + var/next = prefix_locations[i + 1] // We look ahead at the next message to see where we need to stop. + var/spoke_message = handle_autohiss(trim(copytext(message, current[3], next[2])), L) + . += new /datum/multilingual_say_piece(current[1], spoke_message) + +/* These are here purely because it would be hell to try to convert everything over to using the multi-lingual system at once */ +/proc/message_to_multilingual(message, datum/language/speaking = null) + . = list(new /datum/multilingual_say_piece(speaking, message)) + +/proc/multilingual_to_message(list/message_pieces, var/requires_machine_understands = FALSE, var/with_capitalization = FALSE) + . = "" + for(var/datum/multilingual_say_piece/S in message_pieces) + var/message_to_append = S.message + if(S.speaking) + if(with_capitalization) + message_to_append = S.speaking.format_message_plain(S.message) + if(requires_machine_understands && !S.speaking.machine_understands) + message_to_append = S.speaking.scramble(S.message) + . += message_to_append + " " + . = trim_right(.) diff --git a/code/modules/multiz/zshadow.dm b/code/modules/multiz/zshadow.dm index 99b5314ade..eaa91e4a2b 100644 --- a/code/modules/multiz/zshadow.dm +++ b/code/modules/multiz/zshadow.dm @@ -41,12 +41,12 @@ return owner.examine(user, distance, infix, suffix) // Relay some stuff they hear -/mob/zshadow/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) +/mob/zshadow/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) if(speaker && speaker.z != src.z) return // Only relay speech on our acutal z, otherwise we might relay sounds that were themselves relayed up! if(isliving(owner)) verb += " from above" - return owner.hear_say(message, verb, language, alt_name, italics, speaker, speech_sound, sound_vol) + return owner.hear_say(message, verb, language, italics, speaker, speech_sound, sound_vol) /mob/zshadow/proc/sync_icon(var/mob/M) name = M.name diff --git a/code/modules/xenoarcheaology/finds/special.dm b/code/modules/xenoarcheaology/finds/special.dm index d93e47a1dd..3ed9ce38e8 100644 --- a/code/modules/xenoarcheaology/finds/special.dm +++ b/code/modules/xenoarcheaology/finds/special.dm @@ -29,11 +29,11 @@ var/mob/living/M = src.loc M.say(pick(heard_talk)) -/obj/item/clothing/mask/gas/poltergeist/hear_talk(mob/M as mob, text) +/obj/item/clothing/mask/gas/poltergeist/hear_talk(mob/M, list/message_pieces, verb) ..() if(heard_talk.len > max_stored_messages) heard_talk.Remove(pick(heard_talk)) - heard_talk.Add(text) + heard_talk.Add(multilingual_to_message(message_pieces)) if(istype(src.loc, /mob/living) && world.time - last_twitch > 50) last_twitch = world.time @@ -116,7 +116,7 @@ else if(get_dist(W, src) > 10) shadow_wights.Remove(wight_check_index) -/obj/item/weapon/vampiric/hear_talk(mob/M as mob, text) +/obj/item/weapon/vampiric/hear_talk(mob/M, list/message_pieces, verb) ..() if(world.time - last_bloodcall >= bloodcall_interval && M in view(7, src)) bloodcall(M) diff --git a/code/modules/xenobio2/mob/xeno procs.dm b/code/modules/xenobio2/mob/xeno procs.dm index 4b05bbf2e9..0acdcba2e7 100644 --- a/code/modules/xenobio2/mob/xeno procs.dm +++ b/code/modules/xenobio2/mob/xeno procs.dm @@ -112,7 +112,11 @@ Divergence proc, used in mutation to make unique datums. /mob/living/simple_mob/xeno/proc/RandomizeTraits() return +<<<<<<< HEAD /mob/living/simple_mob/xeno/hear_say(var/message, var/verb = "says", var/datum/language/language, var/alt_name = "",var/italics = 0, var/mob/speaker = null) +======= +/mob/living/simple_animal/xeno/hear_say(var/message, var/verb = "says", var/datum/language/language, var/italics = 0, var/mob/speaker = null) +>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956) if(traitdat.traits[TRAIT_XENO_CANLEARN]) /* Until this gets sorted out to a functioning point, or waiting on Psi's saycode update. @@ -128,7 +132,7 @@ Divergence proc, used in mutation to make unique datums. */ if(!(message in speak)) speech_buffer.Add(message) - ..(message,verb,language,alt_name,italics,speaker) + ..(message,verb,language,italics,speaker) /mob/living/simple_mob/xeno/proc/ProcessSpeechBuffer() if(speech_buffer.len) diff --git a/vorestation.dme b/vorestation.dme index 7515d44cbd..7ee3eed2cc 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2373,7 +2373,6 @@ #include "code\modules\mob\living\carbon\alien\emote.dm" #include "code\modules\mob\living\carbon\alien\life.dm" #include "code\modules\mob\living\carbon\alien\progression.dm" -#include "code\modules\mob\living\carbon\alien\say.dm" #include "code\modules\mob\living\carbon\alien\update_icons.dm" #include "code\modules\mob\living\carbon\alien\diona\diona.dm" #include "code\modules\mob\living\carbon\alien\diona\diona_attacks.dm" @@ -2490,6 +2489,7 @@ #include "code\modules\mob\living\carbon\metroid\subtypes.dm" #include "code\modules\mob\living\carbon\metroid\update_icons.dm" #include "code\modules\mob\living\silicon\death.dm" +#include "code\modules\mob\living\silicon\emote.dm" #include "code\modules\mob\living\silicon\laws.dm" #include "code\modules\mob\living\silicon\login.dm" #include "code\modules\mob\living\silicon\say.dm"