Multilingualism

This commit adjusts the speech parsing system to allow for an infinite
number of languages to be present in the same message. You can
transition freely between any language you are able to speak simply by
putting it's language key in the middle of the sentence.

Honestly, this was a massive pain in the ass, and there's probably still
broken stuff, even though I've spent around 8 hours testing and refining
this.
This commit is contained in:
tigercat2000
2018-11-24 00:22:05 -08:00
parent e410f4324d
commit e56750481c
54 changed files with 465 additions and 525 deletions
-2
View File
@@ -11,8 +11,6 @@
//Language flags.
#define WHITELISTED 1 // Language is available if the speaker is whitelisted.
#define RESTRICTED 2 // Language can only be accquired by spawning or an admin.
#define NONVERBAL 4 // Language has a significant non-verbal component. Speech is garbled without line-of-sight
#define SIGNLANG 8 // Language is completely non-verbal. Speech is displayed through emotes for those who can understand.
#define HIVEMIND 16 // Broadcast to all mobs with this language.
#define NONGLOBAL 32 // Do not add to general languages list
#define INNATE 64 // All mobs can be assumed to speak and understand this language (audible emotes)
@@ -3,7 +3,6 @@
real_name = "host brain"
/mob/living/captive_brain/say(message)
if(client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, "<span class='warning'>You cannot speak in IC (muted).</span>")
@@ -152,13 +151,13 @@
stat("Chemicals", chemicals)
/mob/living/simple_animal/borer/say(var/message)
var/datum/language/dialect = parse_language(message)
if(!dialect)
dialect = get_default_language()
if(!istype(dialect, /datum/language/corticalborer) && loc == host && !talk_inside_host)
to_chat(src, "<span class='warning'>You've disabled audible speech while inside a host! Re-enable it under the borer tab, or stick to borer communications.</span>")
return
..()
var/list/message_pieces = parse_languages(message)
for(var/datum/multilingual_say_piece/S in message_pieces)
if(!istype(S.speaking, /datum/language/corticalborer) && loc == host && !talk_inside_host)
to_chat(src, "<span class='warning'>You've disabled audible speech while inside a host! Re-enable it under the borer tab, or stick to borer communications.</span>")
return
. = ..()
/mob/living/simple_animal/borer/verb/Communicate()
set category = "Borer"
+4 -4
View File
@@ -373,19 +373,19 @@ var/list/holopads = list()
/*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(atom/movable/speaker, message, verb, datum/language/message_language)
/obj/machinery/hologram/holopad/hear_talk(atom/movable/speaker, list/message_pieces, verb)
if(speaker && masters.len)//Master is mostly a safety in case lag hits or something. Radio_freq so AIs dont hear holopad stuff through radios.
for(var/mob/living/silicon/ai/master in masters)
if(masters[master] && speaker != master)
master.relay_speech(speaker, message, verb, message_language)
master.relay_speech(speaker, message_pieces, verb)
for(var/I in holo_calls)
var/datum/holocall/HC = I
if(HC.connected_holopad == src && speaker != HC.hologram)
HC.user.hear_say(message, verb, message_language, speaker = speaker)
HC.user.hear_say(message_pieces, verb, speaker = speaker)
if(outgoing_call && speaker == outgoing_call.user)
outgoing_call.hologram.atom_say(message)
outgoing_call.hologram.atom_say(multilingual_to_message(message_pieces))
+17 -18
View File
@@ -57,7 +57,7 @@ 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"],,
signal.data["compression"], signal.data["level"], signal.frequency,
signal.data["verb"], signal.data["language"] )
signal.data["verb"] )
/** #### - Simple Broadcast - #### **/
@@ -83,7 +83,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept
signal.data["radio"], signal.data["message"],
signal.data["name"], signal.data["job"],
signal.data["realname"], signal.data["vname"], 4, signal.data["compression"], signal.data["level"], signal.frequency,
signal.data["verb"], signal.data["language"])
signal.data["verb"])
if(!message_delay)
message_delay = 1
@@ -146,7 +146,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept
signal.data["radio"], signal.data["message"],
signal.data["name"], signal.data["job"],
signal.data["realname"], signal.data["vname"],, signal.data["compression"], list(0), connection.frequency,
signal.data["verb"], signal.data["language"])
signal.data["verb"])
else
if(intercept)
Broadcast_Message(signal.data["connection"], signal.data["mob"],
@@ -154,7 +154,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept
signal.data["radio"], signal.data["message"],
signal.data["name"], signal.data["job"],
signal.data["realname"], signal.data["vname"], 3, signal.data["compression"], list(0), connection.frequency,
signal.data["verb"], signal.data["language"])
signal.data["verb"])
#define CREW_RADIO_TYPE 0
#define CENTCOMM_RADIO_TYPE 1
@@ -234,9 +234,9 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept
**/
/proc/Broadcast_Message(var/datum/radio_frequency/connection, var/mob/M,
var/vmask, var/vmessage, var/obj/item/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/vmask, list/vmessage_pieces, var/obj/item/radio/radio,
list/message_pieces, var/name, var/job, var/realname, var/vname,
var/data, var/compression, var/list/level, var/freq, var/verbage = "says",
var/atom/follow_target = null)
@@ -339,7 +339,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 -
@@ -364,12 +364,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 ---
@@ -414,38 +413,38 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept
if(length(heard_masked))
for(var/mob/R in heard_masked)
R.hear_radio(message,verbage, speaking, part_a, part_b, M, 0, name, follow_target=follow_target)
R.hear_radio(message_pieces, verbage, part_a, part_b, M, 0, name, follow_target=follow_target)
/* --- Process all the mobs that heard the voice normally (understood) --- */
if(length(heard_normal))
for(var/mob/R in heard_normal)
R.hear_radio(message, verbage, speaking, part_a, part_b, M, 0, realname, follow_target=follow_target)
R.hear_radio(message_pieces, verbage, part_a, part_b, M, 0, realname, follow_target=follow_target)
/* --- Process all the mobs that heard the voice normally (did not understand) --- */
if(length(heard_voice))
for(var/mob/R in heard_voice)
R.hear_radio(message,verbage, speaking, part_a, part_b, M,0, vname, follow_target=follow_target)
R.hear_radio(message_pieces, verbage, part_a, part_b, M,0, vname, follow_target=follow_target)
/* --- 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))
for(var/mob/R in heard_garbled)
R.hear_radio(message, verbage, speaking, part_a, part_b, M, 1, vname, follow_target=follow_target)
R.hear_radio(message_pieces, verbage, part_a, part_b, M, 1, vname, follow_target=follow_target)
/* --- Complete gibberish. Usually happens when there's a compressed message --- */
if(length(heard_gibberish))
for(var/mob/R in heard_gibberish)
R.hear_radio(message, verbage, speaking, part_a, part_b, M, 1, follow_target=follow_target)
R.hear_radio(message_pieces, verbage, part_a, part_b, M, 1, follow_target=follow_target)
return 1
/proc/Broadcast_SimpleMessage(var/source, var/frequency, var/text, var/data, var/mob/M, var/compression, var/level)
/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)
/* ###### Prepare the radio connection ###### */
var/mob/living/carbon/human/H
+16 -11
View File
@@ -316,16 +316,20 @@ GLOBAL_DATUM_INIT(nttc_config, /datum/nttc_configuration, new())
signal.data["name"] = new_name
signal.data["realname"] = new_name // this is required because the broadcaster uses this directly if the speaker doesn't have a voice changer on
// This is hacky stuff for multilingual messages...
var/list/message_pieces = signal.data["message"]
// Makes heads of staff bold
if(toggle_command_bold)
var/job = signal.data["job"]
if((job in ert_jobs) || (job in heads))
signal.data["message"] = "<b>" + signal.data["message"] + "</b>"
for(var/datum/multilingual_say_piece/S in message_pieces)
S.message = "<b>[S.message]</b>"
// Hacks!
// Censor dat shit like nobody's business
if(toggle_gibberish)
signal.data["message"] = Gibberish(signal.data["message"], 80)
Gibberish_all(message_pieces, 80)
// Replace everything with HONK!
if(toggle_honk)
@@ -334,24 +338,25 @@ GLOBAL_DATUM_INIT(nttc_config, /datum/nttc_configuration, new())
var/new_message = ""
for(var/i in 1 to honklength)
new_message += pick("HoNK!", "HONK", "HOOOoONK", "HONKHONK!", "HoNnnkKK!!!", "HOOOOOOOOOOONK!!!!11!", "henk!") + " "
signal.data["message"] = new_message
signal.data["message"] = message_to_multilingual(new_message)
// Language Conversion
if(setting_language && valid_languages[setting_language])
if(setting_language == "--DISABLE--")
setting_language = null
else
signal.data["language"] = GLOB.all_languages[setting_language]
for(var/datum/multilingual_say_piece/S in message_pieces)
S.speaking = GLOB.all_languages[setting_language]
// Regex replacements
if(islist(regex) && regex.len > 0)
var/original = signal.data["message"]
var/new_message = original
for(var/reg in regex)
var/replacePattern = pencode_to_html(regex[reg])
var/regex/start = regex("[reg]", "gi")
new_message = start.Replace(new_message, replacePattern)
signal.data["message"] = new_message
for(var/datum/multilingual_say_piece/S in message_pieces)
var/new_message = S.message
for(var/reg in regex)
var/replacePattern = pencode_to_html(regex[reg])
var/regex/start = regex("[reg]", "gi")
new_message = start.Replace(new_message, replacePattern)
S.message = new_message
// Make sure the message is valid after we tinkered with it, otherwise reject it
if(signal.data["message"] == "" || !signal.data["message"])
@@ -438,7 +438,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/radio/headset/server_radio = null
/obj/machinery/telecomms/server/Initialize()
@@ -463,11 +462,10 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
log.parameters["mobtype"] = signal.data["mobtype"]
log.parameters["race"] = signal.data["race"]
log.parameters["job"] = signal.data["job"]
log.parameters["language"] = signal.data["language"]
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"]
@@ -478,7 +476,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)
+2 -2
View File
@@ -171,9 +171,9 @@
for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment)
to_chat(user, "[bicon(ME)] [ME]")
/obj/mecha/hear_talk(mob/M, text)
/obj/mecha/hear_talk(mob/M, list/message_pieces)
if(M == occupant && radio.broadcasting)
radio.talk_into(M, text)
radio.talk_into(M, message_pieces)
/obj/mecha/proc/click_action(atom/target, mob/user, params)
if(!occupant || occupant != user )
+4 -2
View File
@@ -47,8 +47,10 @@
message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN))
if(!message)
return
message = user.handle_speech_problems(message)[1]
message = capitalize(message)
var/list/message_pieces = message_to_multilingual(message)
user.handle_speech_problems(message_pieces)
message = multilingual_to_message(message_pieces)
if((loc == user && !user.incapacitated()))
if(emagged)
if(insults)
@@ -69,7 +71,7 @@
audible_message("<span class='game say'><span class='name'>[user.GetVoice()]</span> [user.GetAltName()] broadcasts, <span class='reallybig'>\"[message]\"</span></span>", hearing_distance = 14)
log_say(message, user)
for(var/obj/O in oview(14, get_turf(src)))
O.hear_talk(user, "<span class='reallybig'>[message]</span>")
O.hear_talk(user, message_to_multilingual("<span class='reallybig'>[message]</span>"))
/obj/item/megaphone/emag_act(user as mob)
if(!emagged)
@@ -50,15 +50,15 @@
to_chat(user, "The following channels are available:")
to_chat(user, radio_desc)
/obj/item/radio/headset/handle_message_mode(mob/living/M as mob, message, channel)
/obj/item/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)
binary.broadcast(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)
hivemind.broadcast(M, strip_prefixes(multilingual_to_message(message_pieces)))
return RADIO_CONNECTION_NON_SUBSPACE
return RADIO_CONNECTION_FAIL
+11 -14
View File
@@ -285,7 +285,7 @@ var/global/list/default_medbay_channels = list(
qdel(src)
// Interprets the message mode when talking into a radio, possibly returning a connection datum
/obj/item/radio/proc/handle_message_mode(mob/living/M as mob, message, message_mode)
/obj/item/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
@@ -301,11 +301,11 @@ var/global/list/default_medbay_channels = list(
// If we were to send to a channel we don't have, drop it.
return RADIO_CONNECTION_FAIL
/obj/item/radio/talk_into(mob/living/M as mob, message, channel, var/verb = "says", var/datum/language/speaking = null)
/obj/item/radio/talk_into(mob/living/M as mob, list/message_pieces, channel, var/verb = "says")
if(!on)
return 0 // the device has to be on
// Fix for permacell radios, but kinda eh about actually fixing them.
if(!M || !message)
if(!M || !message_pieces)
return 0
// Uncommenting this. To the above comment:
@@ -328,7 +328,7 @@ var/global/list/default_medbay_channels = list(
*/
//#### Grab the connection datum ####//
var/message_mode = handle_message_mode(M, message, channel)
var/message_mode = handle_message_mode(M, message_pieces, channel)
switch(message_mode) //special cases
if(RADIO_CONNECTION_FAIL)
return 0
@@ -361,7 +361,7 @@ var/global/list/default_medbay_channels = list(
var/jobname // the mob's "job"
if(jammed)
message = Gibberish(message, 100)
Gibberish_all(message_pieces, 100)
// --- Human: use their actual job ---
if(ishuman(M))
@@ -432,7 +432,7 @@ var/global/list/default_medbay_channels = list(
// Other tags:
"compression" = rand(45,50), // compressed radio signal
"message" = message, // the actual sent message
"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
@@ -441,7 +441,6 @@ var/global/list/default_medbay_channels = list(
"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
"language" = speaking,
"verb" = verb
)
signal.frequency = connection.frequency // Quick frequency set
@@ -490,7 +489,7 @@ var/global/list/default_medbay_channels = list(
"vmask" = voicemask, // 1 if the mob is using a voice gas mas
"compression" = 0, // uncompressed radio signal
"message" = message, // the actual sent message
"message" = message_pieces, // the actual sent message
"connection" = connection, // the radio connection to use
"radio" = src, // stores the radio used for transmission
"slow" = 0,
@@ -499,7 +498,6 @@ var/global/list/default_medbay_channels = list(
"server" = null,
"reject" = 0,
"level" = position.z,
"language" = speaking,
"verb" = verb
)
signal.frequency = connection.frequency // Quick frequency set
@@ -522,15 +520,14 @@ var/global/list/default_medbay_channels = list(
if(!connection) return 0 //~Carn
return Broadcast_Message(connection, M, voicemask, pick(M.speak_emote),
src, message, displayname, jobname, real_name, M.voice_name,
filter_type, signal.data["compression"], list(position.z), connection.frequency,verb,speaking)
src, message_pieces, displayname, jobname, real_name, M.voice_name,
filter_type, signal.data["compression"], list(position.z), connection.frequency,verb)
/obj/item/radio/hear_talk(mob/M as mob, msg, var/verb = "says", var/datum/language/speaking = null)
/obj/item/radio/hear_talk(mob/M as mob, list/message_pieces, var/verb = "says")
if(broadcasting)
if(get_dist(src, M) <= canhear_range)
talk_into(M, msg,null,verb,speaking)
talk_into(M, message_pieces, null, verb)
/*
@@ -85,7 +85,8 @@
icon_state = "taperecorder_idle"
/obj/item/taperecorder/hear_talk(mob/living/M as mob, msg)
/obj/item/taperecorder/hear_talk(mob/living/M as mob, list/message_pieces)
var/msg = multilingual_to_message(message_pieces)
if(mytape && recording)
var/ending = copytext(msg, length(msg))
mytape.timestamp += mytape.used_capacity
@@ -75,10 +75,10 @@
return
attached_device.HasProximity(AM)
/obj/item/transfer_valve/hear_talk(mob/living/M, msg)
/obj/item/transfer_valve/hear_talk(mob/living/M, list/message_pieces)
..()
for(var/obj/O in contents)
O.hear_talk(M, msg)
O.hear_talk(M, message_pieces)
/obj/item/transfer_valve/hear_message(mob/living/M, msg)
..()
@@ -247,9 +247,9 @@
if(nadeassembly)
nadeassembly.on_found(finder)
/obj/item/grenade/chem_grenade/hear_talk(mob/living/M, msg)
/obj/item/grenade/chem_grenade/hear_talk(mob/living/M, list/message_pieces)
if(nadeassembly)
nadeassembly.hear_talk(M, msg)
nadeassembly.hear_talk(M, message_pieces)
/obj/item/grenade/chem_grenade/hear_message(mob/living/M, msg)
if(nadeassembly)
@@ -67,7 +67,7 @@
origin_tech = null //wipe out any origin tech if it's unlocked in any way so you can't double-dip tech levels at R&D.
return
/obj/item/storage/lockbox/hear_talk(mob/living/M as mob, msg)
/obj/item/storage/lockbox/hear_talk(mob/living/M as mob, list/message_pieces)
/obj/item/storage/lockbox/hear_message(mob/living/M as mob, msg)
@@ -158,7 +158,7 @@
to_chat(usr, "<span class='notice'>[src] is locked!</span>")
return 0
/obj/item/storage/secure/hear_talk(mob/living/M as mob, msg)
/obj/item/storage/secure/hear_talk(mob/living/M as mob, list/message_pieces)
return
/obj/item/storage/secure/hear_message(mob/living/M as mob, msg)
@@ -473,10 +473,10 @@
O.emp_act(severity)
..()
/obj/item/storage/hear_talk(mob/living/M as mob, msg)
/obj/item/storage/hear_talk(mob/living/M as mob, list/message_pieces)
..()
for(var/obj/O in contents)
O.hear_talk(M, msg)
O.hear_talk(M, message_pieces)
/obj/item/storage/hear_message(mob/living/M as mob, msg)
..()
+1 -1
View File
@@ -173,7 +173,7 @@
return
/obj/proc/hear_talk(mob/M as mob, text)
/obj/proc/hear_talk(mob/M, list/message_pieces)
return
/obj/proc/hear_message(mob/M as mob, text)
+2 -2
View File
@@ -85,9 +85,9 @@
if(bombassembly)
bombassembly.on_found(finder)
/obj/item/onetankbomb/hear_talk(mob/living/M, msg)
/obj/item/onetankbomb/hear_talk(mob/living/M, list/message_pieces)
if(bombassembly)
bombassembly.hear_talk(M, msg)
bombassembly.hear_talk(M, message_pieces)
/obj/item/onetankbomb/hear_message(mob/living/M, msg)
if(bombassembly)
+3 -3
View File
@@ -98,11 +98,11 @@
a_right.on_found(finder)
/obj/item/assembly_holder/hear_talk(mob/living/M, msg)
/obj/item/assembly_holder/hear_talk(mob/living/M, list/message_pieces)
if(a_left)
a_left.hear_talk(M, msg)
a_left.hear_talk(M, message_pieces)
if(a_right)
a_right.hear_talk(M, msg)
a_right.hear_talk(M, message_pieces)
/obj/item/assembly_holder/hear_message(mob/living/M, msg)
if(a_left)
+4 -4
View File
@@ -16,11 +16,11 @@
else
return "[src] is deactivated."
/obj/item/assembly/voice/hear_talk(mob/living/M as mob, msg)
hear_input(M, msg, 0)
/obj/item/assembly/voice/hear_talk(mob/living/M as mob, list/message_pieces)
hear_input(M, multilingual_to_message(message_pieces), 0)
/obj/item/assembly/voice/hear_message(mob/living/M as mob, msg)
hear_input(M, msg, 1)
hear_input(M, msg, 1)
/obj/item/assembly/voice/proc/hear_input(mob/living/M as mob, msg, type)
if(!istype(M,/mob/living))
@@ -68,7 +68,7 @@
/obj/item/assembly/voice/noise/describe()
return "[src] does not appear to have any controls."
/obj/item/assembly/voice/noise/hear_talk(mob/living/M as mob, msg)
/obj/item/assembly/voice/noise/hear_talk(mob/living/M as mob, list/message_pieces)
return
/obj/item/assembly/voice/noise/hear_message(mob/living/M as mob, msg)
+2 -2
View File
@@ -182,9 +182,9 @@
trigger.HasProximity(AM)
/obj/item/clothing/mask/muzzle/safety/shock/hear_talk(mob/living/M as mob, msg)
/obj/item/clothing/mask/muzzle/safety/shock/hear_talk(mob/living/M as mob, list/message_pieces)
if(trigger)
trigger.hear_talk(M, msg)
trigger.hear_talk(M, message_pieces)
/obj/item/clothing/mask/muzzle/safety/shock/hear_message(mob/living/M as mob, msg)
if(trigger)
+2 -2
View File
@@ -28,8 +28,8 @@
pockets.emp_act(severity)
..()
/obj/item/clothing/suit/storage/hear_talk(mob/M, var/msg)
pockets.hear_talk(M, msg)
/obj/item/clothing/suit/storage/hear_talk(mob/M, list/message_pieces)
pockets.hear_talk(M, message_pieces)
..()
/obj/item/clothing/suit/storage/hear_message(mob/M, var/msg)
@@ -40,8 +40,8 @@
hold.emp_act(severity)
..()
/obj/item/clothing/accessory/storage/hear_talk(mob/M, var/msg, verb, datum/language/speaking)
hold.hear_talk(M, msg, verb, speaking)
/obj/item/clothing/accessory/storage/hear_talk(mob/M, list/message_pieces, verb)
hold.hear_talk(M, message_pieces, verb)
..()
/obj/item/clothing/accessory/storage/hear_message(mob/M, var/msg, verb, datum/language/speaking)
+3 -3
View File
@@ -728,7 +728,7 @@ var/list/non_fakeattack_weapons = list(/obj/item/gun/projectile, /obj/item/ammo_
people += H
if(person) //Basic talk
var/image/speech_overlay = image('icons/mob/talk.dmi', person, "h0", layer = ABOVE_MOB_LAYER)
target.hear_say(pick(speak_messages),language = pick(person.languages),speaker = person)
target.hear_say(message_to_multilingual(pick(speak_messages), pick(person.languages)), speaker = person)
if(target.client)
target.client.images |= speech_overlay
sleep(30)
@@ -738,7 +738,7 @@ var/list/non_fakeattack_weapons = list(/obj/item/gun/projectile, /obj/item/ammo_
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
humans += H
person = pick(humans)
target.hear_radio(pick(radio_messages),language = pick(person.languages),speaker = person, part_a = "<span class='[frequency_span_class(PUB_FREQ)]'><b>\[[get_frequency_name(PUB_FREQ)]\]</b> <span class='name'>", part_b = "</span> <span class='message'>")
target.hear_radio(message_to_multilingual(pick(radio_messages), pick(person.languages)), speaker = person, part_a = "<span class='[frequency_span_class(PUB_FREQ)]'><b>\[[get_frequency_name(PUB_FREQ)]\]</b> <span class='name'>", part_b = "</span> <span class='message'>")
qdel(src)
/obj/effect/hallucination/message
@@ -754,7 +754,7 @@ var/list/non_fakeattack_weapons = list(/obj/item/gun/projectile, /obj/item/ammo_
"<span class='warning'>You feel a tiny prick!</span>",
"<B>[target]</B> sneezes.",
"<span class='warning'>You feel faint.</span>",
"<span class='noticealien'>You hear a strange, alien voice in your head...</span>[pick("Hiss","Ssss")]",
"<span class='noticealien'>You hear a strange, alien voice in your head...</span> [pick("Hiss","Ssss")]",
"<span class='notice'>You can see...everything!</span>")
to_chat(target, chosen)
qdel(src)
@@ -112,9 +112,9 @@
activation_method = pick("touch","laser","bullet","energy","bomb","mob_bump","weapon","speech") // "heat" removed due to lack of is_hot()
..()
/obj/machinery/anomalous_crystal/hear_talk(mob/speaker, message)
/obj/machinery/anomalous_crystal/hear_talk(mob/speaker, list/message_pieces)
..()
if(isliving(speaker) && message)
if(isliving(speaker) && LAZYLEN(message_pieces))
ActivationReaction(speaker, "speech")
/obj/machinery/anomalous_crystal/attack_hand(mob/user)
+1 -1
View File
@@ -38,7 +38,7 @@
. = src.emote_dead(message)
/mob/dead/observer/handle_track(var/message, var/verb = "says", var/datum/language/language, var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear)
/mob/dead/observer/handle_track(var/message, var/verb = "says", var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear)
return "[speaker_name] ([ghost_follow_link(follow_target, ghost=src)])"
/mob/dead/observer/handle_speaker_name(var/mob/speaker = null, var/vname, var/hard_to_hear)
+84 -87
View File
@@ -1,6 +1,53 @@
// At minimum every mob has a hear_say proc.
/mob/proc/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)
/mob/proc/combine_message(var/list/message_pieces, var/verb, var/mob/speaker, always_stars = 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
if(SP.speaking && SP.speaking.flags & INNATE) // Fucking snowflake noise lang
return SP.speaking.format_message(piece)
if(iteration_count == 1)
piece = capitalize(piece)
if(SP.speaking)
if(!say_understands(speaker, SP.speaking))
if(isanimal(speaker))
var/mob/living/simple_animal/S = speaker
if(LAZYLEN(S.speak))
piece = pick(S.speak)
else
piece = stars(piece)
else
piece = SP.speaking.scramble(piece)
if(always_stars)
piece = stars(piece)
piece = SP.speaking.format_message(piece)
else
if(!say_understands(speaker, null))
piece = stars(piece)
if(isanimal(speaker))
var/mob/living/simple_animal/S = speaker
if(LAZYLEN(S.speak))
piece = pick(S.speak)
if(always_stars)
piece = stars(piece)
piece = "<span class='message'><span class='body'>[piece]</span></span>"
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/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)
return 0
@@ -23,35 +70,18 @@
sound_vol *= 0.5
if(sleeping || stat == UNCONSCIOUS)
hear_sleep(message)
hear_sleep(message_pieces)
return 0
//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(!has_vision(information_only = TRUE)) //blind people can't see dumbass
message = stars(message)
if(!speaker || !(speaker in view(src)))
message = stars(message)
if(!say_understands(speaker, language))
if(isanimal(speaker))
var/mob/living/simple_animal/S = speaker
if(S.speak.len)
message = pick(S.speak)
else
message = stars(message)
else
if(language)
message = language.scramble(message)
else
message = stars(message)
var/speaker_name = speaker.name
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(italics)
message = "<i>[message]</i>"
@@ -66,74 +96,47 @@
message = "<b>[message]</b>"
if(!can_hear())
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, "<span class='warning'>You cannot hear yourself speak!</span>")
else
to_chat(src, "<span class='name'>[speaker_name]</span>[speaker.GetAltName()] talks but you cannot hear [speaker.p_them()].")
else
if(language)
to_chat(src, "<span class='game say'><span class='name'>[speaker_name]</span>[speaker.GetAltName()] [track][language.format_message(message, verb)]</span>")
// 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(!language || !(language.flags & INNATE))
if(speaker == src)
to_chat(src, "<span class='warning'>You cannot hear yourself speak!</span>")
else
to_chat(src, "<span class='game say'><span class='name'>[speaker_name]</span>[speaker.GetAltName()] [track][verb], <span class='message'><span class='body'>\"[message]\"</span></span></span>")
to_chat(src, "<span class='name'>[speaker_name]</span>[speaker.GetAltName()] talks but you cannot hear [speaker.p_them()].")
else
to_chat(src, "<span class='game say'><span class='name'>[speaker_name]</span>[speaker.GetAltName()] [track][message]</span>")
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)
/mob/proc/hear_radio(var/message, var/verb = "says", var/datum/language/language = null, var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/vname = "", var/atom/follow_target)
/mob/proc/hear_radio(list/message_pieces, verb = "says", part_a, part_b, mob/speaker = null, hard_to_hear = 0, vname = "", atom/follow_target)
if(!client)
return
if(sleeping || stat == UNCONSCIOUS) //If unconscious or sleeping
hear_sleep(message)
hear_sleep(multilingual_to_message(message_pieces))
return
var/message = combine_message(message_pieces, verb, speaker, always_stars = hard_to_hear)
if(message == "")
return
var/track = null
if(!follow_target)
follow_target = speaker
//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(!has_vision(information_only=TRUE)) //blind people can't see dumbass
message = stars(message)
if(!speaker || !(speaker in view(src)))
message = stars(message)
if(!say_understands(speaker, language))
if(isanimal(speaker))
var/mob/living/simple_animal/S = speaker
if(S.speak && S.speak.len)
message = pick(S.speak)
else
return
else
if(language)
message = language.scramble(message)
else
message = stars(message)
if(hard_to_hear)
message = stars(message)
var/speaker_name = handle_speaker_name(speaker, vname, hard_to_hear)
track = handle_track(message, verb, language, speaker, speaker_name, follow_target, hard_to_hear)
track = handle_track(message, verb, speaker, speaker_name, follow_target, hard_to_hear)
var/formatted
if(language)
formatted = language.format_message_radio(message, verb)
else
formatted = "[verb], <span class=\"body\">\"[message]\"</span>"
if(!can_hear())
if(prob(20))
to_chat(src, "<span class='warning'>You feel your headset vibrate but can hear nothing from it!</span>")
else if(track)
to_chat(src, "[part_a][track][part_b][formatted]</span></span>")
to_chat(src, "[part_a][track][part_b][message]</span></span>")
else
to_chat(src, "[part_a][speaker_name][part_b][formatted]</span></span>")
to_chat(src, "[part_a][speaker_name][part_b][message]</span></span>")
/mob/proc/handle_speaker_name(var/mob/speaker = null, var/vname, var/hard_to_hear)
/mob/proc/handle_speaker_name(mob/speaker = null, vname, hard_to_hear)
var/speaker_name = "unknown"
if(speaker)
speaker_name = speaker.name
@@ -146,26 +149,10 @@
return speaker_name
/mob/proc/handle_track(var/message, var/verb = "says", var/datum/language/language, var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear)
/mob/proc/handle_track(message, verb = "says", mob/speaker = null, speaker_name, atom/follow_target, hard_to_hear)
return
/mob/proc/hear_signlang(var/message, var/verb = "gestures", var/datum/language/language, var/mob/speaker = null)
if(!client)
return
if(say_understands(speaker, language))
message = "<B>[src]</B> [verb], \"[message]\""
else
message = "<B>[src]</B> [verb]."
if(src.status_flags & PASSEMOTES)
for(var/obj/item/holder/H in src.contents)
H.show_message(message)
for(var/mob/living/M in src.contents)
M.show_message(message)
src.show_message(message)
/mob/proc/hear_sleep(var/message)
/mob/proc/hear_sleep(message)
var/heard = ""
if(prob(15))
message = strip_html_properly(message)
@@ -177,9 +164,19 @@
heardword = copytext(heardword,2)
if(copytext(heardword,-1) in punctuation)
heardword = copytext(heardword,1,lentext(heardword))
heard = "<span class = 'game_say'>...You hear something about...[heardword]</span>"
heard = "<span class='game say'>...<i>You hear something about<i>... '[heardword]'...</span>"
else
heard = "<span class = 'game_say'>...<i>You almost hear someone talking</i>...</span>"
heard = "<span class='game say'>...<i>You almost hear someone talking</i>...</span>"
to_chat(src, heard)
/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 = "<span class='game say'><span class='name'>[name]</span> [message]</span>"
to_chat(src, rendered)
+10 -13
View File
@@ -11,7 +11,6 @@
var/ask_verb = "asks" // Used when sentence ends in a ?
var/exclaim_verb = "exclaims" // Used when sentence ends in a !
var/whisper_verb // Optional. When not specified speech_verb + quietly/softly is used instead.
var/signlang_verb = list() // list of emotes that might be displayed if this language has NONVERBAL or SIGNLANG flags
var/colour = "body" // CSS style to use for strings in this language.
var/key = "x" // Character used to speak in language eg. :o for Unathi.
var/flags = 0 // Various language flags.
@@ -85,11 +84,11 @@
return scrambled_text
/datum/language/proc/format_message(message, verb)
return "[verb], <span class='message'><span class='[colour]'>\"[capitalize(message)]\"</span></span>"
/datum/language/proc/format_message(message)
return "<span class='message'><span class='[colour]'>[message]</span></span>"
/datum/language/proc/format_message_radio(message, verb)
return "[verb], <span class='[colour]'>\"[capitalize(message)]\"</span>"
/datum/language/proc/format_message_radio(message)
return "<span class='[colour]'>[message]</span>"
/datum/language/proc/get_talkinto_msg_range(message)
// if you yell, you'll be heard from two tiles over instead of one
@@ -103,11 +102,11 @@
if(!speaker_mask)
speaker_mask = speaker.name
var/msg = "<i><span class='game say'>[name], <span class='name'>[speaker_mask]</span> [format_message(message, get_spoken_verb(message))]</span></i>"
var/msg = "<i><span class='game say'>[name], <span class='name'>[speaker_mask]</span> [get_spoken_verb(message)], [format_message(message)]</span></i>"
for(var/mob/player in GLOB.player_list)
if(istype(player,/mob/dead) && follow)
var/msg_dead = "<i><span class='game say'>[name], <span class='name'>[speaker_mask]</span> ([ghost_follow_link(speaker, ghost=player)]) [format_message(message, get_spoken_verb(message))]</span></i>"
var/msg_dead = "<i><span class='game say'>[name], <span class='name'>[speaker_mask]</span> ([ghost_follow_link(speaker, ghost=player)]) [get_spoken_verb(message)], [format_message(message)]</span></i>"
to_chat(player, msg_dead)
continue
@@ -135,10 +134,10 @@
key = ""
flags = RESTRICTED|NONGLOBAL|INNATE|NO_TALK_MSG|NO_STUTTER
/datum/language/noise/format_message(message, verb)
/datum/language/noise/format_message(message)
return "<span class='message'><span class='[colour]'>[message]</span></span>"
/datum/language/noise/format_message_radio(message, verb)
/datum/language/noise/format_message_radio(message)
return "<span class='[colour]'>[message]</span>"
/datum/language/noise/get_talkinto_msg_range(message)
@@ -635,10 +634,9 @@
// Language handling.
/mob/proc/add_language(language)
var/datum/language/new_language = GLOB.all_languages[language]
if(!istype(new_language) || new_language in languages)
if(!istype(new_language) || (new_language in languages))
return FALSE
languages |= new_language
@@ -657,8 +655,7 @@
// Can we speak this language, as opposed to just understanding it?
/mob/proc/can_speak_language(datum/language/speaking)
return (universal_speak || (speaking && speaking.flags & INNATE) || speaking in languages)
return universal_speak || (speaking && speaking.flags & INNATE) || (speaking in languages)
//TBD
/mob/proc/check_lang_data()
+1 -1
View File
@@ -1,4 +1,4 @@
/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)
+4 -4
View File
@@ -29,7 +29,7 @@
to_chat(usr, "<span class='warning'>You cannot speak, as your internal speaker is turned off.</span>")
. = FALSE
/mob/living/carbon/brain/handle_message_mode(var/message_mode, var/message, var/verb, var/speaking, var/used_radios)
/mob/living/carbon/brain/handle_message_mode(var/message_mode, list/message_pieces, var/verb, var/used_radios)
switch(message_mode)
if("headset")
var/radio_worked = 0 // If any of the radios our brainmob could use functioned, this is set true so that we don't use any others
@@ -39,12 +39,12 @@
if(!radio_worked && c.mecha)
var/obj/mecha/metalgear = c.mecha
if(metalgear.radio)
radio_worked = metalgear.radio.talk_into(src, message, message_mode, verb, speaking)
radio_worked = metalgear.radio.talk_into(src, message_pieces, message_mode, verb)
else if(!radio_worked && c.radio)
radio_worked = c.radio.talk_into(src, message, message_mode, verb, speaking)
radio_worked = c.radio.talk_into(src, message_pieces, message_mode, verb)
return radio_worked
if("whisper")
whisper_say(message, speaking)
whisper_say(message_pieces)
return 1
else return 0
@@ -233,7 +233,6 @@
var/obj/item/organ/external/picked = pick(parts)
if(picked.receive_damage(brute, burn, sharp, updating_health))
UpdateDamageIcon()
speech_problem_flag = 1
//Heal MANY external organs, in random order
@@ -256,7 +255,6 @@
if(updating_health)
updatehealth("heal overall damage")
speech_problem_flag = 1
if(update)
UpdateDamageIcon()
@@ -42,8 +42,6 @@ var/global/default_martial_art = new/datum/martial_art
var/voice = "" //Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life()
var/speech_problem_flag = 0
var/datum/personal_crafting/handcrafting
var/datum/martial_art/martial_art = null
@@ -580,14 +580,14 @@
return FALSE
saveVoice()
/mob/living/carbon/human/interactive/hear_say(message, verb = "says", datum/language/language = null, italics = 0, mob/speaker = null, sound/speech_sound, sound_vol)
/mob/living/carbon/human/interactive/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol)
if(!istype(speaker, /mob/living/carbon/human/interactive))
knownStrings |= html_decode(message)
knownStrings |= html_decode(multilingual_to_message(message_pieces))
..()
/mob/living/carbon/human/interactive/hear_radio(message, verb = "says", datum/language/language=null, part_a, part_b, mob/speaker = null, hard_to_hear = 0, vname = "", atom/follow_target)
/mob/living/carbon/human/interactive/hear_radio(list/message_pieces, verb = "says", part_a, part_b, mob/speaker = null, hard_to_hear = 0, vname = "", atom/follow_target)
if(!istype(speaker, /mob/living/carbon/human/interactive))
knownStrings |= html_decode(message)
knownStrings |= html_decode(multilingual_to_message(message_pieces))
..()
/mob/living/carbon/human/interactive/proc/doProcess()
@@ -71,7 +71,6 @@
drop_item()
emote("cough")
if(disabilities & TOURETTES)
speech_problem_flag = 1
if((prob(10) && paralysis <= 1))
Stun(10)
switch(rand(1, 3))
@@ -86,12 +85,10 @@
animate(pixel_x = initial(pixel_x) , pixel_y = initial(pixel_y), time = 1)
if(disabilities & NERVOUS)
speech_problem_flag = 1
if(prob(10))
Stuttering(10)
if(getBrainLoss() >= 60 && stat != DEAD)
speech_problem_flag = 1
if(prob(3))
var/list/s1 = list("IM A [pick("PONY","LIZARD","taJaran","kitty","Vulpakin","drASK","BIRDIE","voxxie","race car","combat meCH","SPESSSHIP")] [pick("NEEEEEEIIIIIIIIIGH","sKREEEEEE","MEOW","NYA~","rawr","Barkbark","Hissssss","vROOOOOM","pewpew","choo Choo")]!",
"without oxigen blob don't evoluate?",
@@ -158,7 +155,6 @@
if(!gene.block)
continue
if(gene.is_active(src))
speech_problem_flag = 1
gene.OnMobLife(src)
if(!ignore_gene_stability && gene_stability < GENETIC_DAMAGE_STAGE_1)
var/instability = DEFAULT_GENE_STABILITY - gene_stability
@@ -741,7 +737,6 @@
stat = UNCONSCIOUS
else if(sleeping)
speech_problem_flag = 1
stat = UNCONSCIOUS
@@ -1003,29 +998,6 @@
This proc below is only called when those HUD elements need to change as determined by the mobs hud_updateflag.
*/
/mob/living/carbon/human/handle_silent()
if(..())
speech_problem_flag = 1
return silent
/mob/living/carbon/human/handle_slurring()
if(..())
speech_problem_flag = 1
return slurring
/mob/living/carbon/human/handle_stunned()
if(..())
speech_problem_flag = 1
return stunned
/mob/living/carbon/human/handle_stuttering()
if(..())
speech_problem_flag = 1
return stuttering
/mob/living/carbon/human/proc/can_heartattack()
if(NO_BLOOD in dna.species.species_traits)
return FALSE
+40 -47
View File
@@ -107,65 +107,58 @@
/mob/living/carbon/human/proc/GetSpecialVoice()
return special_voice
/mob/living/carbon/human/handle_speech_problems(var/message, var/verb)
var/list/returns[3]
var/speech_problem_flag = 0
/mob/living/carbon/human/handle_speech_problems(list/message_pieces, var/verb)
var/span = ""
if(mind)
span = mind.speech_span
if(silent || (disabilities & MUTE))
message = ""
speech_problem_flag = 1
if((COMIC in mutations) \
|| (locate(/obj/item/organ/internal/cyberimp/brain/clown_voice) in internal_organs) \
|| istype(get_item_by_slot(slot_wear_mask), /obj/item/clothing/mask/gas/voice/clown))
span = "sans"
var/list/parent = ..()
verb = parent["verb"]
if(istype(wear_mask, /obj/item/clothing/mask/horsehead))
var/obj/item/clothing/mask/horsehead/hoers = wear_mask
if(hoers.voicechange)
message = pick("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!")
verb = pick("whinnies","neighs", "says")
speech_problem_flag = 1
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking && S.speaking.flags & NO_STUTTER)
continue
if(dna)
for(var/datum/dna/gene/gene in dna_genes)
if(!gene.block)
continue
if(gene.is_active(src))
message = gene.OnSay(src,message)
speech_problem_flag = 1
if(silent || (disabilities & MUTE))
S.message = ""
if(message != "")
var/list/parent = ..()
message = parent[1]
verb = parent[2]
if(parent[3])
speech_problem_flag = 1
if(istype(wear_mask, /obj/item/clothing/mask/horsehead))
var/obj/item/clothing/mask/horsehead/hoers = wear_mask
if(hoers.voicechange)
S.message = pick("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!")
verb = pick("whinnies", "neighs", "says")
if(dna)
for(var/datum/dna/gene/gene in dna_genes)
if(!gene.block)
continue
if(gene.is_active(src))
S.message = gene.OnSay(src, S.message)
var/braindam = getBrainLoss()
if(braindam >= 60)
speech_problem_flag = 1
if(prob(braindam/4))
message = stutter(message)
if(prob(braindam / 4))
S.message = stutter(S.message)
verb = "gibbers"
if(prob(braindam))
message = uppertext(message)
S.message = uppertext(S.message)
verb = "yells loudly"
if((COMIC in mutations) || (locate(/obj/item/organ/internal/cyberimp/brain/clown_voice) in internal_organs) || istype(get_item_by_slot(slot_wear_mask), /obj/item/clothing/mask/gas/voice/clown))
span = "sans"
if(span)
S.message = "<span class='[span]'>[S.message]</span>"
return list("verb" = verb)
if(span)
message = "<span class='[span]'>[message]</span>"
returns[1] = message
returns[2] = verb
returns[3] = speech_problem_flag
return returns
/mob/living/carbon/human/handle_message_mode(var/message_mode, var/message, var/verb, var/speaking, var/used_radios)
/mob/living/carbon/human/handle_message_mode(var/message_mode, list/message_pieces, var/verb, var/used_radios)
switch(message_mode)
if("intercom")
for(var/obj/item/radio/intercom/I in view(1, src))
spawn(0)
I.talk_into(src, message, null, verb, speaking)
I.talk_into(src, message_pieces, null, verb)
used_radios += I
if("headset")
@@ -173,13 +166,13 @@
if(isradio(l_ear))
R = l_ear
used_radios += R
if(R.talk_into(src, message, null, verb, speaking))
if(R.talk_into(src, message_pieces, null, verb))
return
if(isradio(r_ear))
R = r_ear
used_radios += R
if(R.talk_into(src, message, null, verb, speaking))
if(R.talk_into(src, message_pieces, null, verb))
return
if("right ear")
@@ -190,7 +183,7 @@
R = r_hand
if(R)
used_radios += R
R.talk_into(src, message, null, verb, speaking)
R.talk_into(src, message_pieces, null, verb)
if("left ear")
var/obj/item/radio/R
@@ -200,21 +193,21 @@
R = l_hand
if(R)
used_radios += R
R.talk_into(src, message, null, verb, speaking)
R.talk_into(src, message_pieces, null, verb)
if("whisper")
whisper_say(message, speaking)
whisper_say(message_pieces)
return 1
else
if(message_mode)
if(isradio(l_ear))
used_radios += l_ear
if(l_ear.talk_into(src, message, message_mode, verb, speaking))
if(l_ear.talk_into(src, message_pieces, message_mode, verb))
return
if(isradio(r_ear))
used_radios += r_ear
if(r_ear.talk_into(src, message, message_mode, verb, speaking))
if(r_ear.talk_into(src, message_pieces, message_mode, verb))
return
/mob/living/carbon/human/handle_speech_sound()
@@ -3,19 +3,11 @@
message = trim_strip_html_properly(message) //bit of duplicate code, acceptable because the workaround would be annoying
//parse the language code and consume it
var/datum/language/speaking = parse_language(message)
if(speaking)
message = copytext(message, 2 + length(speaking.key))
else
speaking = get_default_language()
// This is broadcast to all mobs with the language,
// irrespective of distance or anything else.
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 quirk to just easily deal with HIVEMIND languages
var/datum/multilingual_say_piece/S = message_pieces // Yay BYOND's hilarious typecasting
S.speaking.broadcast(src, S.message)
return 1
message = trim_left(message)
message = handle_autohiss(message, speaking)
whisper_say(message, speaking)
whisper_say(message, message_pieces)
+4 -4
View File
@@ -14,16 +14,16 @@
return 1
return ..()
/mob/living/carbon/slime/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)
/mob/living/carbon/slime/hear_say(list/message_pieces, var/verb = "says", 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)))
speech_buffer.Add(lowertext(html_decode(multilingual_to_message(message_pieces))))
..()
/mob/living/carbon/slime/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="", var/atom/follow_target)
/mob/living/carbon/slime/hear_radio(list/message_pieces, var/verb="says", var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="", var/atom/follow_target)
if(speaker in Friends)
speech_buffer = list()
speech_buffer.Add(speaker)
speech_buffer.Add(lowertext(html_decode(message)))
speech_buffer.Add(lowertext(html_decode(multilingual_to_message(message_pieces))))
..()
+80 -122
View File
@@ -54,51 +54,48 @@ proc/get_radio_key_from_channel(var/channel)
/mob/living/proc/binarycheck()
return FALSE
/mob/living/proc/get_default_language()
/mob/proc/get_default_language()
return null
/mob/living/get_default_language()
return default_language
/mob/living/proc/handle_speech_problems(var/message, var/verb)
var/list/returns[3]
var/speech_problem_flag = 0
/mob/living/proc/handle_speech_problems(list/message_pieces, var/verb)
var/robot = isSynthetic()
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking && S.speaking.flags & NO_STUTTER)
continue
if((HULK in mutations) && health >= 25)
S.message = "[uppertext(S.message)]!!!"
verb = pick("yells", "roars", "hollers")
if((HULK in mutations) && health >= 25 && length(message))
message = "[uppertext(message)]!!!"
verb = pick("yells","roars","hollers")
speech_problem_flag = 1
if(slurring)
if(robot)
S.message = slur(S.message, list("@", "!", "#", "$", "%", "&", "?"))
else
S.message = slur(S.message)
verb = "slurs"
if(slurring)
if(robot)
message = slur(message, list("@", "!", "#", "$", "%", "&", "?"))
else
message = slur(message)
verb = "slurs"
speech_problem_flag = 1
if(stuttering)
if(robot)
message = robostutter(message)
else
message = stutter(message)
verb = "stammers"
speech_problem_flag = 1
if(cultslurring)
message = cultslur(message)
verb = "slurs"
speech_problem_flag = 1
if(!IsVocal())
message = ""
speech_problem_flag = 1
if(stuttering)
if(robot)
S.message = robostutter(S.message)
else
S.message = stutter(S.message)
verb = "stammers"
returns[1] = message
returns[2] = verb
returns[3] = speech_problem_flag
return returns
if(cultslurring)
S.message = cultslur(S.message)
verb = "slurs"
/mob/living/proc/handle_message_mode(message_mode, message, verb, speaking, used_radios)
if(!IsVocal())
S.message = ""
return list("verb" = verb)
/mob/living/proc/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
switch(message_mode)
if("whisper") //all mobs can whisper by default
whisper_say(message, speaking)
whisper_say(message_pieces)
return 1
return 0
@@ -109,7 +106,7 @@ proc/get_radio_key_from_channel(var/channel)
return returns
/mob/living/say(var/message, var/datum/language/speaking = null, var/verb = "says", var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
/mob/living/say(var/message, var/verb = "says", var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
if(client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
@@ -138,19 +135,17 @@ proc/get_radio_key_from_channel(var/channel)
message = trim_left(message)
//parse the language code and consume it
if(!speaking)
speaking = parse_language(message)
if(speaking)
message = copytext(message, 2 + length(speaking.key))
else
speaking = get_default_language()
// This is broadcast to all mobs with the language,
// irrespective of distance or anything else.
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 quirk to just easily deal with HIVEMIND languages
var/datum/multilingual_say_piece/S = message_pieces // Yay BYOND's hilarious typecasting
S.speaking.broadcast(src, S.message)
return 1
if(!LAZYLEN(message_pieces))
log_runtime(EXCEPTION("Message failed to generate pieces. [message] - [json_encode(message_pieces)]"))
return 0
if(message_mode == "cords")
if(iscarbon(src))
var/mob/living/carbon/C = src
@@ -160,7 +155,8 @@ proc/get_radio_key_from_channel(var/channel)
V.speak_with(message) //words come before actions
return 1
verb = say_quote(message, speaking)
var/datum/multilingual_say_piece/first_piece = message_pieces[1]
verb = say_quote(message, first_piece.speaking)
if(is_muzzled())
var/obj/item/clothing/mask/muzzle/G = wear_mask
@@ -168,25 +164,19 @@ proc/get_radio_key_from_channel(var/channel)
to_chat(src, "<span class='danger'>You're muzzled and cannot speak!</span>")
return
else if(G.mute == MUZZLE_MUTE_MUFFLE)
message = muffledspeech(message)
muffledspeech_all(message_pieces)
verb = "mumbles"
message = trim_left(message)
if(!ignore_speech_problems)
var/list/hsp = handle_speech_problems(message_pieces, verb)
verb = hsp["verb"]
message = handle_autohiss(message, speaking)
if(!ignore_speech_problems && (speaking && !(speaking.flags & NO_STUTTER)))
var/list/handle_s = handle_speech_problems(message, verb)
message = handle_s[1]
verb = handle_s[2]
if(!message || message == "")
return 0
var/list/used_radios = list()
if(handle_message_mode(message_mode, message, verb, speaking, used_radios))
if(handle_message_mode(message_mode, message_pieces, verb, used_radios))
return 1
var/list/handle_v = handle_speech_sound()
var/sound/speech_sound = handle_v[1]
var/sound_vol = handle_v[2]
@@ -198,11 +188,12 @@ 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 = "<span class='notice'>\The [src] talks into \the [used_radios[1]]</span>"
if(!first_piece.speaking || !(first_piece.speaking.flags & NO_TALK_MSG))
msg = "<span class='notice'>[src] talks into [used_radios[1]]</span>"
if(msg)
for(var/mob/living/M in hearers(5, src) - src)
@@ -213,16 +204,6 @@ proc/get_radio_key_from_channel(var/channel)
var/turf/T = get_turf(src)
//handle nonverbal and sign languages here
if(speaking)
if(speaking.flags & NONVERBAL)
if(prob(30))
custom_emote(1, "[pick(speaking.signlang_verb)].")
if(speaking.flags & SIGNLANG)
return say_signlang(message, pick(speaking.signlang_verb), speaking)
var/list/listening = list()
var/list/listening_obj = list()
@@ -268,7 +249,7 @@ proc/get_radio_key_from_channel(var/channel)
var/speech_bubble_test = say_test(message)
for(var/mob/M in listening)
M.hear_say(message, verb, speaking, italics, src, speech_sound, sound_vol)
M.hear_say(message_pieces, verb, italics, src, speech_sound, sound_vol)
if(M.client)
speech_bubble_recipients.Add(M.client)
spawn(0)
@@ -281,19 +262,13 @@ proc/get_radio_key_from_channel(var/channel)
for(var/obj/O in listening_obj)
spawn(0)
if(O) //It's possible that it could be deleted in the meantime.
O.hear_talk(src, message, verb, speaking)
O.hear_talk(src, message_pieces, verb)
//Log of what we've said, plain message, no spans or junk
say_log += message
log_say(message, src)
return 1
/mob/living/proc/say_signlang(var/message, var/verb="gestures", var/datum/language/language)
for(var/mob/O in viewers(src, null))
O.hear_signlang(message, verb, language, src)
return 1
/obj/effect/speech_bubble
var/mob/parent
@@ -338,28 +313,19 @@ proc/get_radio_key_from_channel(var/channel)
message = trim_strip_html_properly(message)
//parse the language code and consume it
var/datum/language/speaking = parse_language(message)
if(speaking)
message = copytext(message, 2 + length(speaking.key))
else
speaking = get_default_language()
// This is broadcast to all mobs with the language,
// irrespective of distance or anything else.
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 quirk to just easily deal with HIVEMIND languages
var/datum/multilingual_say_piece/S = message_pieces // Yay BYOND's hilarious typecasting
S.speaking.broadcast(src, S.message)
return 1
message = trim_left(message)
message = handle_autohiss(message, speaking)
whisper_say(message, speaking)
whisper_say(message_pieces)
// for weird circumstances where you're inside an atom that is also you, like pai's
/mob/living/proc/get_whisper_loc()
return src
/mob/living/proc/whisper_say(var/message, var/datum/language/speaking = null, var/verb="whispers")
/mob/living/proc/whisper_say(list/message_pieces, verb = "whispers")
if(client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
@@ -367,7 +333,7 @@ proc/get_radio_key_from_channel(var/channel)
if(stat)
if(stat == DEAD)
return say_dead(message)
return say_dead(message_pieces)
return
if(is_muzzled())
@@ -382,37 +348,29 @@ proc/get_radio_key_from_channel(var/channel)
var/watching_range = 5
var/italics = 1
var/adverb_added = FALSE
var/not_heard //the message displayed to people who could not hear the whispering
if(speaking)
if(speaking.whisper_verb)
verb = speaking.whisper_verb
var/datum/multilingual_say_piece/first_piece = message_pieces[1]
if(first_piece.speaking)
if(first_piece.speaking.whisper_verb)
verb = first_piece.speaking.whisper_verb
not_heard = "[verb] something"
else
var/adverb = pick("quietly", "softly")
adverb_added = TRUE
verb = "[speaking.speech_verb] [adverb]"
not_heard = "[speaking.speech_verb] something [adverb]"
verb = "[first_piece.speaking.speech_verb] [adverb]"
not_heard = "[first_piece.speaking.speech_verb] something [adverb]"
else
not_heard = "[verb] something"
message = trim(message)
var/speech_problem_flag = 0
var/list/handle_s = handle_speech_problems(message, verb)
message = handle_s[1]
verb = handle_s[2]
speech_problem_flag = handle_s[3]
var/list/hsp = handle_speech_problems(message_pieces, verb)
verb = hsp["verb"]
if(verb == "yells loudly")
verb = "slurs emphatically"
else if(speech_problem_flag && !adverb_added)
else if(!adverb_added)
var/adverb = pick("quietly", "softly")
verb = "[verb] [adverb]"
if(!message)
return
var/atom/whisper_loc = get_whisper_loc()
var/list/listening = hear(message_range, whisper_loc)
listening |= src
@@ -450,7 +408,7 @@ proc/get_radio_key_from_channel(var/channel)
for(var/obj/O in view(message_range, whisper_loc))
spawn(0)
if(O)
O.hear_talk(src, message, verb, speaking)
O.hear_talk(src, message_pieces, verb)
var/list/eavesdropping = hearers(eavesdropping_range, whisper_loc)
eavesdropping -= src
@@ -463,17 +421,17 @@ proc/get_radio_key_from_channel(var/channel)
//now mobs
var/list/speech_bubble_recipients = list()
var/speech_bubble_test = say_test(message)
var/speech_bubble_test = say_test(multilingual_to_message(message_pieces))
for(var/mob/M in listening)
M.hear_say(message, verb, speaking, italics, src)
M.hear_say(message_pieces, verb, italics, src)
if(M.client)
speech_bubble_recipients.Add(M.client)
if(eavesdropping.len)
var/new_message = stars(message) //hopefully passing the message twice through stars() won't hurt... I guess if you already don't understand the language, when they speak it too quietly to hear normally you would be able to catch even less.
stars_all(message_pieces) //hopefully passing the message twice through stars() won't hurt... I guess if you already don't understand the language, when they speak it too quietly to hear normally you would be able to catch even less.
for(var/mob/M in eavesdropping)
M.hear_say(new_message, verb, speaking, italics, src)
M.hear_say(message_pieces, verb, italics, src)
if(M.client)
speech_bubble_recipients.Add(M.client)
@@ -487,7 +445,7 @@ proc/get_radio_key_from_channel(var/channel)
for(var/mob/M in watching)
M.show_message(rendered, 2)
log_whisper(message, src)
log_whisper(multilingual_to_message(message_pieces), src)
return 1
/mob/living/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list())
+3 -11
View File
@@ -1184,19 +1184,11 @@ var/list/ai_verbs_default = list(
var/list/viewscale = getviewsize(client.view)
return get_dist(src, A) <= max(viewscale[1]*0.5,viewscale[2]*0.5)
/mob/living/silicon/ai/proc/relay_speech(mob/living/M, text, verb, datum/language/speaking)
if(!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)
/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
if(speaking)
rendered = "<i><span class='game say'>Relayed Speech: <span class='name'>[name_used]</span> [speaking.format_message(text, verb)]</span></i>"
else
rendered = "<i><span class='game say'>Relayed Speech: <span class='name'>[name_used]</span> [verb], <span class='message'>\"[text]\"</span></span></i>"
var/rendered = "<i><span class='game say'>Relayed Speech: <span class='name'>[name_used]</span> [message]</span></i>"
show_message(rendered, 2)
/mob/living/silicon/ai/proc/malfhacked(obj/machinery/power/apc/apc)
@@ -141,6 +141,6 @@
acceleration = !acceleration
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
/mob/camera/aiEye/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)
/mob/camera/aiEye/hear_say(list/message_pieces, var/verb = "says", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
if(relay_speech)
ai.relay_speech(speaker, message, verb, language)
ai.relay_speech(speaker, message_pieces, verb)
+1 -1
View File
@@ -3,7 +3,7 @@
*/
/mob/living/silicon/ai/handle_track(var/message, var/verb = "says", var/datum/language/language, var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear)
/mob/living/silicon/ai/handle_track(var/message, var/verb = "says", var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear)
if(hard_to_hear)
return
@@ -17,7 +17,6 @@
ventcrawler = 2
magpulse = 1
mob_size = MOB_SIZE_SMALL
default_language = "Drone"
// We need to keep track of a few module items so we don't need to do list operations
// every time we need them. These get set in New() after the module is chosen.
@@ -38,7 +37,6 @@
/mob/living/silicon/robot/drone/New()
..()
remove_language("Robot Talk")
@@ -1,15 +1,14 @@
/mob/living/silicon/robot/drone/say(var/message, var/datum/language/speaking = null)
/mob/living/silicon/robot/drone/say(var/message)
if(copytext(message, 1, 2) == "*")
return emote(copytext(message, 2))
if(!speaking)
speaking = parse_language(message)
if(!speaking)
speaking = istype(get_default_language(), /datum/language) ? get_default_language() : GLOB.all_languages[get_default_language()]
message = speaking.key + " " + message; // Prepend key to prevent the message from getting trimmed
if(speaking)
return ..()
return ..()
/mob/living/silicon/robot/drone/whisper_say(var/message, var/datum/language/speaking = null, var/verb="whispers")
say(message) //drones do not get to whisper, only speak normally
return 1
/mob/living/silicon/robot/drone/whisper_say(list/message_pieces)
say(multilingual_to_message(message_pieces)) //drones do not get to whisper, only speak normally
return 1
/mob/living/silicon/robot/drone/get_default_language()
if(default_language)
return default_language
return GLOB.all_languages["Drone"]
+14 -41
View File
@@ -1,9 +1,9 @@
/mob/living/silicon/handle_message_mode(message_mode, message, verb, speaking, used_radios)
log_say(message, src)
/mob/living/silicon/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
log_say(multilingual_to_message(message_pieces), src)
if(..())
return 1
/mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios)
/mob/living/silicon/robot/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
if(..())
return 1
if(message_mode)
@@ -13,14 +13,14 @@
return 0
if(message_mode == "general")
message_mode = null
return radio.talk_into(src,message,message_mode,verb,speaking)
return radio.talk_into(src,message_pieces,message_mode,verb)
/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios)
/mob/living/silicon/ai/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
if(..())
return 1
if(message_mode == "department")
used_radios += aiRadio
return holopad_talk(message, verb, speaking)
return holopad_talk(message_pieces, verb)
else if(message_mode)
used_radios += aiRadio
if(aiRadio.disabledAi || aiRestorePowerRoutine || stat)
@@ -28,19 +28,19 @@
return 0
if(message_mode == "general")
message_mode = null
return aiRadio.talk_into(src,message,message_mode,verb,speaking)
return aiRadio.talk_into(src, message_pieces, message_mode, verb)
/mob/living/silicon/pai/handle_message_mode(message_mode, message, verb, speaking, used_radios)
/mob/living/silicon/pai/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
if(..())
return 1
else if(message_mode == "whisper")
whisper_say(message, speaking)
whisper_say(message_pieces)
return 1
else if(message_mode)
if(message_mode == "general")
message_mode = null
used_radios += radio
return radio.talk_into(src,message,message_mode,verb,speaking)
return radio.talk_into(src, message_pieces, message_mode, verb)
/mob/living/silicon/say_quote(var/text)
var/ending = copytext(text, length(text))
@@ -70,41 +70,14 @@
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 = current
if(istype(T) && T.masters[src])
//Human-like, sorta, heard by those who understand humans.
var/rendered_a
//Speach distorted, heard by those who do not understand AIs.
var/message_stars = stars(message)
var/rendered_b
if(speaking)
rendered_a = "<span class='game say'><span class='name'>[name]</span> [speaking.format_message(message, verb)]</span>"
rendered_b = "<span class='game say'><span class='name'>[voice_name]</span> [speaking.format_message(message_stars, verb)]</span>"
to_chat(src, "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> [speaking.format_message(message, verb)]</span></i>")//The AI can "hear" its own message.
else
rendered_a = "<span class='game say'><span class='name'>[name]</span> [verb], <span class='message'>\"[message]\"</span></span>"
rendered_b = "<span class='game say'><span class='name'>[voice_name]</span> [verb], <span class='message'>\"[message_stars]\"</span></span>"
to_chat(src, "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> [verb], <span class='message'><span class='body'>\"[message]\"</span></span></span></i>")//The AI can "hear" its own message.
for(var/mob/M in hearers(T.loc))//The location is the object, default distance.
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)
/*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.*/
M.hear_holopad_talk(message_pieces, verb, src)
to_chat(src, "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> [combine_message(message_pieces, verb, src)]</span></i>")
else
to_chat(src, "No holopad connected.")
return
@@ -704,21 +704,21 @@
available_channels = list(":e")
..()
/mob/living/simple_animal/parrot/handle_message_mode(var/message_mode, var/message, var/verb, var/speaking, var/used_radios)
/mob/living/simple_animal/parrot/handle_message_mode(var/message_mode, list/message_pieces, var/verb, var/used_radios)
if(message_mode && istype(ears))
ears.talk_into(src, message, message_mode, verb, speaking)
ears.talk_into(src, message_pieces, message_mode, verb)
used_radios += ears
/mob/living/simple_animal/parrot/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/italics = 0, var/mob/speaker = null)
/mob/living/simple_animal/parrot/hear_say(list/message_pieces, var/verb = "says", var/italics = 0, var/mob/speaker = null)
if(speaker != src && prob(50))
parrot_hear(html_decode(message))
parrot_hear(html_decode(multilingual_to_message(message_pieces)))
..()
/mob/living/simple_animal/parrot/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/atom/follow_target)
/mob/living/simple_animal/parrot/hear_radio(list/message_pieces, var/verb="says", var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/atom/follow_target)
if(speaker != src && prob(50))
parrot_hear(html_decode(message))
parrot_hear(html_decode(multilingual_to_message(message_pieces)))
..()
+1 -1
View File
@@ -44,7 +44,7 @@
. = !(disabilities & DEAF)
// Whether the mob is able to see
// `information_only` is for stuff that's purely informational - like understanding nonverbal languages, or blindness overlays
// `information_only` is for stuff that's purely informational - like blindness overlays
// This flag exists because certain things like angel statues expect this to be false for dead people
/mob/living/has_vision(information_only = FALSE)
return (information_only && stat == DEAD) || !(eye_blind || (disabilities & BLIND) || stat)
+13
View File
@@ -177,6 +177,10 @@
p++
return t
/proc/stars_all(list/message_pieces, pr)
for(var/datum/multilingual_say_piece/S in message_pieces)
S.message = stars(S.message, pr)
/proc/slur(phrase, var/list/slurletters = ("'"))//use a different list as an input if you want to make robots slur with $#@%! characters
phrase = html_decode(phrase)
var/leng=lentext(phrase)
@@ -266,6 +270,11 @@
return returntext
/proc/Gibberish_all(list/message_pieces, p)
for(var/datum/multilingual_say_piece/S in message_pieces)
S.message = Gibberish(S.message, p)
proc/muffledspeech(phrase)
phrase = html_decode(phrase)
var/leng=lentext(phrase)
@@ -284,6 +293,10 @@ proc/muffledspeech(phrase)
counter-=1
return newphrase
/proc/muffledspeech_all(list/message_pieces)
for(var/datum/multilingual_say_piece/S in message_pieces)
S.message = muffledspeech(S.message)
/proc/shake_camera(mob/M, duration, strength=1)
if(!M || !M.client || M.shakecamera)
+72 -12
View File
@@ -132,17 +132,77 @@
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)
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)
var/language_prefix = trim_right(lowertext(copytext(message, 1 ,4)))
var/datum/language/L = GLOB.language_keys[language_prefix]
if(can_speak_language(L))
return L
/datum/multilingual_say_piece/New(datum/language/new_speaking, new_message)
. = ..()
speaking = new_speaking
if(new_message)
message = new_message
return null
/mob/proc/find_valid_prefixes(message)
var/list/prefixes = list() // [["Common", start, end], ["Gutter", start, end]]
for(var/i in 1 to length(message))
var/selection = trim_right(lowertext(copytext(message, i, i + 3)))
var/datum/language/L = GLOB.language_keys[selection]
if(L != null && can_speak_language(L)) // What the fuck... remove the L != null check if you ever find out what the fuck is adding `null` to the languages list on absolutely random mobs... seriously what the hell...
prefixes[++prefixes.len] = list(L, i, i + length(selection))
else if(!L && i == 1)
prefixes[++prefixes.len] = list(get_default_language(), i, i)
else
return prefixes
/proc/strip_prefixes(message)
. = ""
var/last_index = 1
for(var/i in 1 to length(message))
var/selection = trim_right(lowertext(copytext(message, i, i + 3)))
var/datum/language/L = GLOB.language_keys[selection]
if(L)
. += copytext(message, last_index, i)
last_index = i + 3
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)
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", keypos]
// 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)
. = new /datum/multilingual_say_piece(L, trim(strip_prefixes(message)))
break
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
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)
. = ""
for(var/datum/multilingual_say_piece/S in message_pieces)
. += S.message + " "
. = trim_right(.)
+2 -2
View File
@@ -297,10 +297,10 @@
toggle_tilt(usr)
/obj/structure/sign/picture_frame/hear_talk(mob/living/M as mob, msg)
/obj/structure/sign/picture_frame/hear_talk(mob/living/M as mob, list/message_pieces)
..()
for(var/obj/O in contents)
O.hear_talk(M, msg)
O.hear_talk(M, message_pieces)
/obj/structure/sign/picture_frame/hear_message(mob/living/M as mob, msg)
..()
+2 -1
View File
@@ -541,7 +541,8 @@ var/list/SpookyGhosts = list("ghost","shade","shade2","ghost-narsie","horror","s
if(..(user, 1))
to_chat(user, "This video camera can send live feeds to the entertainment network. It's [camera ? "" : "in"]active.")
/obj/item/videocam/hear_talk(mob/M as mob, msg)
/obj/item/videocam/hear_talk(mob/M as mob, list/message_pieces)
var/msg = multilingual_to_message(message_pieces)
if(camera && on)
if(get_dist(src, M) <= canhear_range)
talk_into(M, msg)
@@ -245,9 +245,9 @@
if(assembly)
assembly.on_found(finder)
/obj/item/reagent_containers/glass/beaker/hear_talk(mob/living/M, msg)
/obj/item/reagent_containers/glass/beaker/hear_talk(mob/living/M, list/message_pieces)
if(assembly)
assembly.hear_talk(M, msg)
assembly.hear_talk(M, message_pieces)
/obj/item/reagent_containers/glass/beaker/hear_message(mob/living/M, msg)
if(assembly)
+2 -2
View File
@@ -181,9 +181,9 @@
if(rig)
rig.Crossed(AM)
/obj/structure/reagent_dispensers/fueltank/hear_talk(mob/living/M, msg)
/obj/structure/reagent_dispensers/fueltank/hear_talk(mob/living/M, list/message_pieces)
if(rig)
rig.hear_talk(M, msg)
rig.hear_talk(M, message_pieces)
/obj/structure/reagent_dispensers/fueltank/hear_message(mob/living/M, msg)
if(rig)
+2 -2
View File
@@ -522,8 +522,8 @@ obj/spacepod/proc/add_equipment(mob/user, var/obj/item/spacepod_equipment/SPE, v
to_chat(user, "<span class='warning'>You need an open hand to do that.</span>")
/obj/spacepod/hear_talk/hear_talk(mob/M, var/msg)
cargo_hold.hear_talk(M, msg)
/obj/spacepod/hear_talk/hear_talk(mob/M, list/message_pieces)
cargo_hold.hear_talk(M, message_pieces)
..()
/obj/spacepod/hear_message(mob/M, var/msg)
@@ -52,8 +52,8 @@
pocket.emp_act(severity)
..()
/obj/item/organ/internal/headpocket/hear_talk(mob/living/M as mob, msg)
pocket.hear_talk(M, msg)
/obj/item/organ/internal/headpocket/hear_talk(mob/living/M as mob, list/message_pieces)
pocket.hear_talk(M, message_pieces)
..()
/obj/item/organ/internal/headpocket/hear_message(mob/living/M as mob, msg)