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
+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(.)