Files
VOREStation/code/modules/mob/say.dm
ShadowLarkens 6835103f31 Fix language keys not working after multilingualism
Sort of a "fix", sort of a tweak; the system deliberately never checked
for anything but the lowercase version of a language key to make it
easier to use, but a lot of the VOREStation languages use uppercase
invocation keys. Easy enough to fix by just making it check for the
literal version of the key instead of the lowertext version.
2020-04-25 11:29:49 -07:00

243 lines
9.2 KiB
Plaintext

/mob/proc/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
return
/mob/verb/whisper(message as text)
set name = "Whisper"
set category = "IC"
usr.say(message,whispering=1)
/mob/verb/say_verb(message as text)
set name = "Say"
set category = "IC"
set_typing_indicator(FALSE)
usr.say(message)
/mob/verb/me_verb(message as text)
set name = "Me"
set category = "IC"
if(say_disabled) //This is here to try to identify lag problems
to_chat(usr, "<font color='red'>Speech is currently admin-disabled.</font>")
return
//VOREStation Edit Start
if(muffled)
return me_verb_subtle(message)
message = sanitize_or_reflect(message,src) //VOREStation Edit - Reflect too-long messages (within reason)
//VOREStation Edit End
set_typing_indicator(FALSE)
if(use_me)
custom_emote(usr.emote_type, message)
else
usr.emote(message)
/mob/proc/say_dead(var/message)
if(say_disabled) //This is here to try to identify lag problems
to_chat(usr, "<span class='danger'>Speech is currently admin-disabled.</span>")
return
if(!client)
return // Clientless mobs shouldn't be trying to talk in deadchat.
if(!client.holder)
if(!config.dsay_allowed)
to_chat(src, "<span class='danger'>Deadchat is globally muted.</span>")
return
if(!is_preference_enabled(/datum/client_preference/show_dsay))
to_chat(usr, "<span class='danger'>You have deadchat muted.</span>")
return
message = encode_html_emphasis(message)
say_dead_direct("[pick("complains","moans","whines","laments","blubbers")], <span class='message'>\"[message]\"</span>", src)
/mob/proc/say_understands(var/mob/other, var/datum/language/speaking = null)
if(stat == DEAD)
return TRUE
//Universal speak makes everything understandable, for obvious reasons.
else if(universal_speak || universal_understand)
return TRUE
//Languages are handled after.
if(!speaking)
if(!other)
return TRUE
if(other.universal_speak)
return TRUE
if(isAI(src) && ispAI(other))
return TRUE
if(istype(other, type) || istype(src, other.type))
return TRUE
return FALSE
if(speaking.flags & INNATE)
return TRUE
//non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet.
if(speaking.flags & NONVERBAL)
if(sdisabilities & BLIND || blinded)
return FALSE
if(!other || !(other in view(src)))
return FALSE
//Language check.
for(var/datum/language/L in languages)
if(speaking.name == L.name)
return TRUE
return FALSE
/mob/proc/say_quote(var/message, var/datum/language/speaking = null)
var/verb = "says"
var/ending = copytext(message, length(message))
if(speaking)
verb = speaking.get_spoken_verb(ending)
else
if(ending == "!")
verb = pick("exclaims", "shouts", "yells")
else if(ending == "?")
verb = "asks"
return verb
/mob/proc/emote(var/act, var/type, var/message)
if(act == "me")
return custom_emote(type, message)
/mob/proc/get_ear()
// returns an atom representing a location on the map from which this
// mob can hear things
// should be overloaded for all mobs whose "ear" is separate from their "mob"
return get_turf(src)
/mob/proc/say_test(var/text)
var/ending = copytext(text, length(text))
if(ending == "?")
return "1"
else if(ending == "!")
return "2"
return "0"
//parses the message mode code (e.g. :h, :w) from text, such as that supplied to say.
//returns the message mode string or null for no message mode.
//standard mode is the mode returned for the special ';' radio code.
/mob/proc/parse_message_mode(var/message, var/standard_mode = "headset")
if(length(message) >= 1 && copytext(message, 1, 2) == ";")
return standard_mode
if(length(message) >= 2)
var/channel_prefix = copytext(message, 1, 3)
return department_radio_keys[channel_prefix]
return null
/datum/multilingual_say_piece
var/datum/language/speaking = null
var/message = ""
/datum/multilingual_say_piece/New(datum/language/new_speaking, new_message)
. = ..()
speaking = new_speaking
if(new_message)
message = new_message
/mob/proc/find_valid_prefixes(message)
var/list/prefixes = list() // [["Common", start, end], ["Gutter", start, end]]
for(var/i in 1 to length(message))
// This grabs trimmed 3 character substrings, to allow for up to 1 prefix and 1 letter language keys
var/selection = trim_right(copytext(message, i, i + 2)) // VOREStation Edit: We use uppercase keys to avoid Polaris key duplication, but this had lowertext() in it
// The first character in the selection will always be the prefix (if this is a valid language invocation)
var/prefix = copytext(selection, 1, 2)
var/language_key = copytext(selection, 2, 3)
if(is_language_prefix(prefix))
// Okay, we're definitely now trying to invoke a language (probably)
// This "[]" is probably unnecessary but BYOND will runtime if a number is used
var/datum/language/L = GLOB.language_keys["[language_key]"]
// It's kinda silly that we have to check L != null and this isn't done for us by can_speak (it runtimes instead), but w/e
if(L && can_speak(L))
// So we have a valid language invocation, and we can speak that language, let's make a piece for it
// This language will be the language until the next prefixes[] index, or the end of the message if there are none.
prefixes[++prefixes.len] = list(L, i, i + length(selection))
else if(L)
// We found a valid language, but they can't speak it. Let's make them speak gibberish instead.
prefixes[++prefixes.len] = list(GLOB.all_languages[LANGUAGE_GIBBERISH], i, i + length(selection))
continue
if(i == 1)
// This covers the case of "no prefixes in use."
prefixes[++prefixes.len] = list(get_default_language(), i, i)
return prefixes
/mob/proc/strip_prefixes(message, mob/prefixer = null)
. = ""
var/last_index = 1
for(var/i in 1 to length(message))
var/selection = trim_right(lowertext(copytext(message, i, i + 2)))
// The first character in the selection will always be the prefix (if this is a valid language invocation)
var/prefix = copytext(selection, 1, 2)
var/language_key = copytext(selection, 2, 3)
if(is_language_prefix(prefix))
var/datum/language/L = GLOB.language_keys["[language_key]"]
if(L)
. += copytext(message, last_index, i)
last_index = i + 2
if(i + 1 > length(message))
. += copytext(message, last_index)
// this returns a structured message with language sections
// list(/datum/multilingual_say_piece(common, "hi"), /datum/multilingual_say_piece(farwa, "squik"), /datum/multilingual_say_piece(common, "meow!"))
/mob/proc/parse_languages(message)
. = list()
// Noise language is a snowflake.
if(copytext(message, 1, 2) == "!" && length(message) > 1)
// Note that list() here is intended
// Returning a raw /datum/multilingual_say_piece is supported, but only for hivemind languages
// What we actually want is a normal say piece that's all noise lang
return list(new /datum/multilingual_say_piece(GLOB.all_languages["Noise"], trim(strip_prefixes(copytext(message, 2)))))
// Scan the message for prefixes
var/list/prefix_locations = find_valid_prefixes(message)
if(!LAZYLEN(prefix_locations)) // There are no prefixes... or at least, no _valid_ prefixes.
. += new /datum/multilingual_say_piece(get_default_language(), trim(strip_prefixes(message))) // So we'll just strip those pesky things and still make the message.
for(var/i in 1 to length(prefix_locations))
var/current = prefix_locations[i] // ["Common", start, end]
// There are a few things that will make us want to ignore all other languages in - namely, HIVEMIND languages.
var/datum/language/L = current[1]
if(L && (L.flags & HIVEMIND || L.flags & SIGNLANG))
return new /datum/multilingual_say_piece(L, trim(sanitize(strip_prefixes(message))))
if(i + 1 > length(prefix_locations)) // We are out of lookaheads, that means the rest of the message is in cur lang
var/spoke_message = sanitize(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 = sanitize(handle_autohiss(trim(copytext(message, current[3], next[2])), L))
. += new /datum/multilingual_say_piece(current[1], spoke_message)
/* These are here purely because it would be hell to try to convert everything over to using the multi-lingual system at once */
/proc/message_to_multilingual(message, datum/language/speaking = null)
. = list(new /datum/multilingual_say_piece(speaking, message))
/proc/multilingual_to_message(list/message_pieces, var/requires_machine_understands = FALSE, var/with_capitalization = FALSE)
. = ""
for(var/datum/multilingual_say_piece/S in message_pieces)
var/message_to_append = S.message
if(S.speaking)
if(with_capitalization)
message_to_append = S.speaking.format_message_plain(S.message)
if(requires_machine_understands && !S.speaking.machine_understands)
message_to_append = S.speaking.scramble(S.message)
. += message_to_append + " "
. = trim_right(.)