Saycode Overhaul -- Multilingualism (#6956)

* Port ParadiseSS13/Paradise#2100 - Saycode refactor

* Removed unused old carbon slimes code

* Port ParadiseSS13/Paradise#5099 - Saycode part 2

* Ported ParadiseSS13/Paradise#7170's /datum/browser Check Known Languages

* Port ParadiseSS13/Paradise#9240 - Get rid of alt_name in favor of GetAltName()

* Port ParadiseSS13/Paradise#10330 - You can now use multiple languages in one message

* Addressed Atermonera's review.

Translators now print the full message if they find any languages within the
message that the user doesn't understand, minus languages it cannot translate.

Additionally, the combine_message proc has been significantly simplified
by eliminating an ugly tree structure with the help of a little helper
proc.

The removal of the extra span inside each piece doesn't seem to have
visually changed the messages in any other way than changing where the
wordwrap happens, strangely enough. Must be something in IE's code being
picky about invisible elements. On the bright side, it splits *later*
than it did before, thus reducing the lines a message will take up by a
tiny amount.

Also, a bunch of things now have the 'filter_say' class from
PolarisSS13/Polaris#6998. Since span classes with no definition are
totally valid and just don't do anything, this PR does **not** depend on
that PR being merged first.

* Always gotta be one
This commit is contained in:
ShadowLarkens
2020-04-20 01:11:53 -07:00
committed by GitHub
parent 1ed5556b8f
commit 54a8a5823d
72 changed files with 1338 additions and 3284 deletions

View File

@@ -220,30 +220,22 @@
..()
// Proc: hear_talk()
// Parameters: 4 (M - the mob the speech originated from, text - what is being said, verb - the word used to describe how text is being said, speaking - language
// being used)
// Parameters: 3 (M - the mob the speech originated from,
// list/message_pieces - what is being said w/ baked languages,
// verb - the word used to describe how text is being said)
// Description: Relays the speech to all linked communicators.
/obj/item/device/communicator/hear_talk(mob/living/M, text, verb, datum/language/speaking)
/obj/item/device/communicator/hear_talk(mob/M, list/message_pieces, verb)
for(var/obj/item/device/communicator/comm in communicating)
var/turf/T = get_turf(comm)
if(!T) return
var/list/in_range = get_mobs_and_objs_in_view_fast(T,world.view,0)
var/list/mobs_to_relay = in_range["mobs"]
for(var/mob/mob in mobs_to_relay)
//Can whoever is hearing us understand?
if(!mob.say_understands(M, speaking))
if(speaking)
text = speaking.scramble(text)
else
text = stars(text)
var/message = mob.combine_message(message_pieces, verb, M)
var/name_used = M.GetVoice()
var/rendered = null
if(speaking) //Language being used
rendered = "<span class='game say'>[bicon(src)] <span class='name'>[name_used]</span> [speaking.format_message(text, verb)]</span>"
else
rendered = "<span class='game say'>[bicon(src)] <span class='name'>[name_used]</span> [verb], <span class='message'>\"[text]\"</span></span>"
rendered = "<span class='game say'>[bicon(src)] <span class='name'>[name_used]</span> [message]</span>"
mob.show_message(rendered, 2)
// Proc: show_message()

View File

@@ -10,53 +10,52 @@
var/list/insultmsg = list("FUCK EVERYONE!", "I'M A TERRORIST!", "ALL SECURITY TO SHOOT ME ON SIGHT!", "I HAVE A BOMB!", "CAPTAIN IS A COMDOM!", "GLORY TO ALMACH!")
/obj/item/device/megaphone/proc/can_broadcast(var/mob/living/user)
if (user.client)
if(user.client)
if(user.client.prefs.muted & MUTE_IC)
to_chat(user, "<span class='warning'>You cannot speak in IC (muted).</span>")
return 0
return FALSE
if(!(ishuman(user) || user.isSynthetic()))
to_chat(user, "<span class='warning'>You don't know how to use this!</span>")
return 0
return FALSE
if(user.silent)
return 0
if(spamcheck)
to_chat(user, "<span class='warning'>\The [src] needs to recharge!</span>")
return 0
return 1
return FALSE
if(spamcheck > world.time)
to_chat(user, "<span class='warning'>[src] needs to recharge!</span>")
return FALSE
if(loc != user)
return FALSE
if(user.stat != CONSCIOUS)
return FALSE
return TRUE
/obj/item/device/megaphone/proc/do_broadcast(var/mob/living/user, var/message)
if ((src.loc == user && usr.stat == 0))
if(emagged)
if(insults)
user.audible_message("<B>[user]</B> broadcasts, <FONT size=3>\"[pick(insultmsg)]\"</FONT>")
insults--
else
to_chat(user, "<span class='warning'>*BZZZZzzzzzt*</span>")
if(emagged)
if(insults)
user.audible_message("<B>[user.GetVoice()]</B>[user.GetAltName()] broadcasts, <FONT size=3>\"[pick(insultmsg)]\"</FONT>")
insults--
else
user.audible_message("<B>[user]</B> broadcasts, <FONT size=3>\"[message]\"</FONT>")
spamcheck = 1
spawn(20)
spamcheck = 0
return
/obj/item/device/megaphone/attack_self(mob/living/user as mob)
if(!can_broadcast(user))
return
to_chat(user, "<span class='warning'>*BZZZZzzzzzt*</span>")
else
user.audible_message("<B>[user.GetVoice()]</B>[user.GetAltName()] broadcasts, <FONT size=3>\"[message]\"</FONT>")
/obj/item/device/megaphone/attack_self(var/mob/living/user)
var/message = sanitize(input(user, "Shout a message?", "Megaphone", null) as text)
if(!message)
return
message = capitalize(message)
if(!can_broadcast(user))
return
spamcheck = world.time + 20
do_broadcast(user, message)
/obj/item/device/megaphone/emag_act(var/remaining_charges, var/mob/user)
if(!emagged)
to_chat(user, "<span class='warning'>You overload \the [src]'s voice synthesizer.</span>")
emagged = 1
to_chat(user, "<span class='warning'>You overload [src]'s voice synthesizer.</span>")
emagged = TRUE
insults = rand(1, 3)//to prevent caps spam.
return 1
return TRUE
/obj/item/device/megaphone/super
name = "gigaphone"
@@ -130,41 +129,35 @@
broadcast_color = new_color
/obj/item/device/megaphone/super/do_broadcast(var/mob/living/user, var/message)
if ((src.loc == user && usr.stat == 0))
if(emagged)
if(insults)
user.audible_message("<B>[user]</B> broadcasts, <FONT size=[broadcast_size] face='[broadcast_font]' color='[broadcast_color]'>\"[pick(insultmsg)]\"</FONT>")
if(broadcast_size >= 11)
var/turf/T = get_turf(user)
playsound(T, 'sound/items/AirHorn.ogg', 100, 1)
for(var/mob/living/carbon/M in oviewers(4, T))
if(M.get_ear_protection() >= 2)
continue
M.sleeping = 0
M.stuttering += 20
M.ear_deaf += 30
M.Weaken(3)
if(prob(30))
M.Stun(10)
M.Paralyse(4)
else
M.make_jittery(50)
insults--
else
user.audible_message("<span class='critical'>*BZZZZzzzzzt*</span>")
if(prob(40) && insults <= 0)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(2, 1, get_turf(user))
s.start()
user.visible_message("<span class='warning'>\The [src] sparks violently!</span>")
spawn(30)
explosion(get_turf(src), -1, -1, 1, 3, adminlog = 1)
qdel(src)
return
if(emagged)
if(insults)
user.audible_message("<B>[user.GetVoice()]</B>[user.GetAltName()] broadcasts, <FONT size=[broadcast_size] face='[broadcast_font]' color='[broadcast_color]'>\"[pick(insultmsg)]\"</FONT>")
if(broadcast_size >= 11)
var/turf/T = get_turf(user)
playsound(T, 'sound/items/AirHorn.ogg', 100, 1)
for(var/mob/living/carbon/M in oviewers(4, T))
if(M.get_ear_protection() >= 2)
continue
M.sleeping = 0
M.stuttering += 20
M.ear_deaf += 30
M.Weaken(3)
if(prob(30))
M.Stun(10)
M.Paralyse(4)
else
M.make_jittery(50)
insults--
else
user.audible_message("<B>[user]</B> broadcasts, <FONT size=[broadcast_size] face='[broadcast_font]' color='[broadcast_color]'>\"[message]\"</FONT>")
spamcheck = 1
spawn(20)
spamcheck = 0
return
user.audible_message("<span class='critical'>*BZZZZzzzzzt*</span>")
if(prob(40) && insults <= 0)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(2, 1, get_turf(user))
s.start()
user.visible_message("<span class='warning'>\The [src] sparks violently!</span>")
spawn(30)
explosion(get_turf(src), -1, -1, 1, 3, adminlog = 1)
qdel(src)
return
else
user.audible_message("<B>[user.GetVoice()]</B>[user.GetAltName()] broadcasts, <FONT size=[broadcast_size] face='[broadcast_font]' color='[broadcast_color]'>\"[message]\"</FONT>")

View File

@@ -43,15 +43,17 @@
to_chat(user, "The following channels are available:")
to_chat(user, radio_desc)
/obj/item/device/radio/headset/handle_message_mode(mob/living/M as mob, message, channel)
if (channel == "special")
if (translate_binary)
/obj/item/device/radio/headset/handle_message_mode(mob/living/M as mob, list/message_pieces, channel)
if(channel == "special")
if(translate_binary)
var/datum/language/binary = GLOB.all_languages["Robot Talk"]
binary.broadcast(M, message)
if (translate_hive)
binary.broadcast(M, M.strip_prefixes(multilingual_to_message(message_pieces)))
return RADIO_CONNECTION_NON_SUBSPACE
if(translate_hive)
var/datum/language/hivemind = GLOB.all_languages["Hivemind"]
hivemind.broadcast(M, message)
return null
hivemind.broadcast(M, M.strip_prefixes(multilingual_to_message(message_pieces)))
return RADIO_CONNECTION_NON_SUBSPACE
return RADIO_CONNECTION_FAIL
return ..()

View File

@@ -169,7 +169,7 @@ var/global/list/default_medbay_channels = list(
return can_admin_interact()
/obj/item/device/radio/proc/text_wires()
if (b_stat)
if(b_stat)
return wires.GetInteractWindow()
return
@@ -197,31 +197,31 @@ var/global/list/default_medbay_channels = list(
return TRUE
usr.set_machine(src)
if (href_list["track"])
if(href_list["track"])
var/mob/target = locate(href_list["track"])
var/mob/living/silicon/ai/A = locate(href_list["track2"])
if(A && target)
A.ai_actual_track(target)
. = 1
else if (href_list["freq"])
else if(href_list["freq"])
var/new_frequency = (frequency + text2num(href_list["freq"]))
if ((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ))
if((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ))
new_frequency = sanitize_frequency(new_frequency)
set_frequency(new_frequency)
if(hidden_uplink)
if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency))
usr << browse(null, "window=radio")
. = 1
else if (href_list["talk"])
else if(href_list["talk"])
ToggleBroadcast()
. = 1
else if (href_list["listen"])
else if(href_list["listen"])
var/chan_name = href_list["ch_name"]
if (!chan_name)
if(!chan_name)
ToggleReception()
else
if (channels[chan_name] & FREQ_LISTENING)
if(channels[chan_name] & FREQ_LISTENING)
channels[chan_name] &= ~FREQ_LISTENING
else
channels[chan_name] |= FREQ_LISTENING
@@ -240,46 +240,46 @@ var/global/list/default_medbay_channels = list(
/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel) //BS12 EDIT
var/datum/radio_frequency/connection = null
if(channel && channels && channels.len > 0)
if (channel == "department")
if(channel == "department")
//to_world("DEBUG: channel=\"[channel]\" switching to \"[channels[1]]\"")
channel = channels[1]
connection = secure_radio_connections[channel]
else
connection = radio_connection
channel = null
if (!istype(connection))
if(!istype(connection))
return
var/static/mob/living/silicon/ai/announcer/A = new /mob/living/silicon/ai/announcer(src, null, null, 1)
A.SetName(from)
Broadcast_Message(connection, A,
0, "*garbled automated announcement*", src,
message, from, "Automated Announcement", from, "synthesized voice",
message_to_multilingual(message), from, "Automated Announcement", from, "synthesized voice",
4, 0, list(0), connection.frequency, "states")
// Interprets the message mode when talking into a radio, possibly returning a connection datum
/obj/item/device/radio/proc/handle_message_mode(mob/living/M as mob, message, message_mode)
/obj/item/device/radio/proc/handle_message_mode(mob/living/M as mob, list/message_pieces, message_mode)
// If a channel isn't specified, send to common.
if(!message_mode || message_mode == "headset")
return radio_connection
// Otherwise, if a channel is specified, look for it.
if(channels && channels.len > 0)
if (message_mode == "department") // Department radio shortcut
if(message_mode == "department") // Department radio shortcut
message_mode = channels[1]
if (channels[message_mode]) // only broadcast if the channel is set on
if(channels[message_mode]) // only broadcast if the channel is set on
return secure_radio_connections[message_mode]
// If we were to send to a channel we don't have, drop it.
return null
return RADIO_CONNECTION_FAIL
/obj/item/device/radio/talk_into(mob/living/M as mob, message, channel, var/verb = "says", var/datum/language/speaking = null)
if(!on) return FALSE // the device has to be on
/obj/item/device/radio/talk_into(mob/living/M as mob, list/message_pieces, channel, var/verb = "says")
if(!on)
return FALSE // the device has to be on
// Fix for permacell radios, but kinda eh about actually fixing them.
if(!M || !message) return FALSE
if(speaking && (speaking.flags & (SIGNLANG|NONVERBAL))) return FALSE
if(!M || !message_pieces)
return FALSE
if(istype(M)) M.trigger_aiming(TARGET_CAN_RADIO)
@@ -303,10 +303,17 @@ var/global/list/default_medbay_channels = list(
*/
//#### Grab the connection datum ####//
var/datum/radio_frequency/connection = handle_message_mode(M, message, channel)
if (!istype(connection))
var/message_mode = handle_message_mode(M, message_pieces, channel)
switch(message_mode)
if(RADIO_CONNECTION_FAIL)
return FALSE
if(RADIO_CONNECTION_NON_SUBSPACE)
return TRUE
if(!istype(message_mode, /datum/radio_frequency)) //if not a special case, it should be returning a radio connection
return FALSE
var/datum/radio_frequency/connection = message_mode
var/turf/position = get_turf(src)
//#### Tagging the signal with all appropriate identity values ####//
@@ -323,24 +330,24 @@ var/global/list/default_medbay_channels = list(
var/jobname // the mob's "job"
// --- Human: use their actual job ---
if (ishuman(M))
if(ishuman(M))
var/mob/living/carbon/human/H = M
jobname = H.get_assignment()
// --- Carbon Nonhuman ---
else if (iscarbon(M)) // Nonhuman carbon mob
else if(iscarbon(M)) // Nonhuman carbon mob
jobname = "No id"
// --- AI ---
else if (isAI(M))
else if(isAI(M))
jobname = "AI"
// --- Cyborg ---
else if (isrobot(M))
else if(isrobot(M))
jobname = "Cyborg"
// --- Personal AI (pAI) ---
else if (istype(M, /mob/living/silicon/pai))
else if(istype(M, /mob/living/silicon/pai))
jobname = "Personal AI"
// --- Unidentifiable mob ---
@@ -351,7 +358,7 @@ var/global/list/default_medbay_channels = list(
// --- Modifications to the mob's identity ---
// The mob is disguising their identity:
if (ishuman(M) && M.GetVoice() != real_name)
if(ishuman(M) && M.GetVoice() != real_name)
displayname = M.GetVoice()
jobname = "Unknown"
voicemask = 1
@@ -390,7 +397,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
@@ -399,7 +406,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
@@ -421,8 +427,8 @@ var/global/list/default_medbay_channels = list(
to_chat(loc, "<span class='warning'>\The [src] pings as it falls back to local radio transmission.</span>")
subspace_transmission = FALSE
return Broadcast_Message(connection, M, voicemask, pick(M.speak_emote),
src, message, displayname, jobname, real_name, M.voice_name,
signal.transmission_method, signal.data["compression"], GetConnectedZlevels(position.z), connection.frequency,verb,speaking)
src, message_pieces, displayname, jobname, real_name, M.voice_name,
signal.transmission_method, signal.data["compression"], GetConnectedZlevels(position.z), connection.frequency,verb)
/* ###### Intercoms and station-bounced radios ###### */
@@ -452,7 +458,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,
@@ -461,7 +467,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
@@ -482,20 +487,20 @@ var/global/list/default_medbay_channels = list(
//THIS IS TEMPORARY. YEAH RIGHT
if(!connection) return FALSE //~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"], GetConnectedZlevels(position.z), connection.frequency,verb,speaking)
src, message_pieces, displayname, jobname, real_name, M.voice_name,
filter_type, signal.data["compression"], GetConnectedZlevels(position.z), connection.frequency, verb)
/obj/item/device/radio/hear_talk(mob/M as mob, msg, var/verb = "says", var/datum/language/speaking = null)
if (broadcasting)
/obj/item/device/radio/hear_talk(mob/M, list/message_pieces, verb)
if(broadcasting)
if(get_dist(src, M) <= canhear_range)
talk_into(M, msg,null,verb,speaking)
talk_into(M, message_pieces, null, verb)
/*
/obj/item/device/radio/proc/accept_rad(obj/item/device/radio/R as obj, message)
if ((R.frequency == frequency && message))
if((R.frequency == frequency && message))
return TRUE
else if
@@ -510,7 +515,7 @@ var/global/list/default_medbay_channels = list(
// what the range is in which mobs will hear the radio
// returns: -1 if can't receive, range otherwise
if (wires.IsIndexCut(WIRE_RECEIVE))
if(wires.IsIndexCut(WIRE_RECEIVE))
return -1
if(!listening)
return -1
@@ -526,20 +531,20 @@ var/global/list/default_medbay_channels = list(
if(freq in CENT_FREQS)
if(!(src.centComm))//Checks to see if it's allowed on that frequency, based on the encryption keys
return -1
if (!on)
if(!on)
return -1
if (!freq) //recieved on main frequency
if (!listening)
if(!freq) //recieved on main frequency
if(!listening)
return -1
else
var/accept = (freq==frequency && listening)
if (!accept)
if(!accept)
for (var/ch_name in channels)
var/datum/radio_frequency/RF = secure_radio_connections[ch_name]
if (RF && RF.frequency==freq && (channels[ch_name]&FREQ_LISTENING))
if(RF && RF.frequency==freq && (channels[ch_name]&FREQ_LISTENING))
accept = 1
break
if (!accept)
if(!accept)
return -1
return canhear_range
@@ -552,8 +557,8 @@ var/global/list/default_medbay_channels = list(
/obj/item/device/radio/examine(mob/user)
. = ..()
if ((in_range(src, user) || loc == user))
if (b_stat)
if((in_range(src, user) || loc == user))
if(b_stat)
user.show_message("<span class='notice'>\The [src] can be attached and modified!</span>")
else
user.show_message("<span class='notice'>\The [src] can not be modified or attached!</span>")
@@ -562,11 +567,11 @@ var/global/list/default_medbay_channels = list(
/obj/item/device/radio/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
user.set_machine(src)
if (!W.is_screwdriver())
if(!W.is_screwdriver())
return
b_stat = !( b_stat )
if(!istype(src, /obj/item/device/radio/beacon))
if (b_stat)
if(b_stat)
user.show_message("<span class='notice'>\The [src] can now be attached and modified!</span>")
else
user.show_message("<span class='notice'>\The [src] can no longer be modified or attached!</span>")
@@ -606,7 +611,7 @@ var/global/list/default_medbay_channels = list(
/obj/item/device/radio/borg/talk_into()
. = ..()
if (isrobot(src.loc))
if(isrobot(src.loc))
var/mob/living/silicon/robot/R = src.loc
var/datum/robot_component/C = R.components["radio"]
R.cell_use_power(C.active_usage)
@@ -614,7 +619,7 @@ var/global/list/default_medbay_channels = list(
/obj/item/device/radio/borg/attackby(obj/item/weapon/W as obj, mob/user as mob)
// ..()
user.set_machine(src)
if (!(W.is_screwdriver() || istype(W, /obj/item/device/encryptionkey)))
if(!(W.is_screwdriver() || istype(W, /obj/item/device/encryptionkey)))
return
if(W.is_screwdriver())
@@ -688,7 +693,7 @@ var/global/list/default_medbay_channels = list(
/obj/item/device/radio/borg/Topic(href, href_list)
if(..())
return TRUE
if (href_list["mode"])
if(href_list["mode"])
var/enable_subspace_transmission = text2num(href_list["mode"])
if(enable_subspace_transmission != subspace_transmission)
subspace_transmission = !subspace_transmission
@@ -702,7 +707,7 @@ var/global/list/default_medbay_channels = list(
else
recalculateChannels()
. = 1
if (href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio.
if(href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio.
var/do_shut_up = text2num(href_list["shutup"])
if(do_shut_up != shut_up)
shut_up = !shut_up

View File

@@ -126,10 +126,7 @@
linkedmonitor.unpair(src)
linkedmonitor = null
..()
/*
/obj/item/device/camerabug/hear_talk(mob/M, var/msg, verb, datum/language/speaking)
radio.hear_talk(M, msg, speaking)
*/
/obj/item/device/bug_monitor
name = "mobile camera pod monitor"
desc = "A portable camera console designed to work with mobile camera pods."
@@ -208,10 +205,7 @@
return
return 1
/*
/obj/item/device/bug_monitor/hear_talk(mob/M, var/msg, verb, datum/language/speaking)
return radio.hear_talk(M, msg, speaking)
*/
/obj/item/device/bug_monitor/spy
name = "\improper PDA"
desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge."

View File

@@ -86,15 +86,10 @@
update_icon()
/obj/item/device/taperecorder/hear_talk(mob/living/M as mob, msg, var/verb="says", datum/language/speaking=null)
/obj/item/device/taperecorder/hear_talk(mob/M, list/message_pieces, verb)
var/msg = multilingual_to_message(message_pieces, requires_machine_understands = TRUE, with_capitalization = TRUE)
if(mytape && recording)
if(speaking)
if(!speaking.machine_understands)
msg = speaking.scramble(msg)
mytape.record_speech("[M.name] [speaking.format_message_plain(msg, verb)]")
else
mytape.record_speech("[M.name] [verb], \"[msg]\"")
mytape.record_speech("[M.name] [verb], \"[msg]\"")
/obj/item/device/taperecorder/see_emote(mob/M as mob, text, var/emote_type)

View File

@@ -33,8 +33,8 @@
icon_state = "[initial(icon_state)]"
to_chat(user, "<span class='notice'>You disable \the [src].</span>")
/obj/item/device/universal_translator/hear_talk(var/mob/speaker, var/message, var/vrb, var/datum/language/language)
if(!listening || !istype(speaker))
/obj/item/device/universal_translator/hear_talk(mob/M, list/message_pieces, verb)
if(!listening || !istype(M))
return
//Show the "I heard something" animation.
@@ -46,34 +46,38 @@
return
var/mob/living/L = loc
if(visual && ((L.sdisabilities & BLIND) || L.eye_blind))
return
if(audio && ((L.sdisabilities & DEAF) || L.ear_deaf))
return
if(!language)
return //Borgs were causing runtimes when passing language=null
// Using two for loops kinda sucks, but I think it's more efficient
// to shortcut past string building if we're just going to discard the string
// anyways.
if(user_understands(M, L, message_pieces))
return
if (language && (language.flags & NONVERBAL))
return //Not gonna translate sign language
var/new_message = ""
if (!language.machine_understands)
return //Any other languages that it can't translate.
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking.flags & NONVERBAL)
continue
if(!S.speaking.machine_understands)
new_message += stars(S.message) + " "
continue
if (visual && ((L.sdisabilities & BLIND) || L.eye_blind))
return //Can't see the screen, don't get the message
new_message += (S.message + " ")
if (audio && ((L.sdisabilities & DEAF) || L.ear_deaf))
return //Can't hear the translation, don't get the message
if(!L.say_understands(null, langset))
new_message = langset.scramble(new_message)
//Only translate if they can't understand, otherwise pointlessly spammy
//I'll just assume they don't look at the screen in that case
to_chat(L, "<span class='filter_say'><i><b>[src]</b> translates, </i>\"<span class='[langset.colour]'>[new_message]</span>\"</span>")
//They don't understand the spoken language we're translating FROM
if(!L.say_understands(speaker,language))
//They understand the output language
if(L.say_understands(null,langset))
to_chat(L, "<i><b>[src]</b> translates, </i>\"<span class='[langset.colour]'>[message]</span>\"")
//They don't understand the output language
else
to_chat(L, "<i><b>[src]</b> translates, </i>\"<span class='[langset.colour]'>[langset.scramble(message)]</span>\"")
/obj/item/device/universal_translator/proc/user_understands(mob/M, mob/living/L, list/message_pieces)
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking && !L.say_understands(M, S.speaking))
return FALSE
return TRUE
//Let's try an ear-worn version
/obj/item/device/universal_translator/ear

View File

@@ -38,9 +38,9 @@
radio.icon_state = src.icon_state
update_icon()
/obj/item/device/tvcamera/hear_talk(mob/living/M, msg, var/verb="says", datum/language/speaking=null)
radio.hear_talk(M,msg,verb,speaking)
..()
/obj/item/device/tvcamera/hear_talk(mob/M, list/message_pieces, verb)
radio.hear_talk(M, message_pieces, verb)
. = ..()
/obj/item/device/tvcamera/attack_self(mob/user)
add_fingerprint(user)

View File

@@ -227,7 +227,8 @@ Implant Specifics:<BR>"}
<b>Integrity:</b> Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."}
return dat
/obj/item/weapon/implant/explosive/hear_talk(mob/M as mob, msg)
/obj/item/weapon/implant/explosive/hear_talk(mob/M, list/message_pieces, verb)
var/msg = multilingual_to_message(message_pieces)
hear(msg)
return