diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm
index 6d3852cf4e6a..2eacecbf0e64 100644
--- a/code/__DEFINES/say.dm
+++ b/code/__DEFINES/say.dm
@@ -3,6 +3,10 @@
Currently contains speech spans and message modes
*/
+#define RADIO_EXTENSION "department specific"
+#define RADIO_KEY "department specific key"
+#define LANGUAGE_EXTENSION "language specific"
+
//Message modes. Each one defines a radio channel, more or less.
#define MODE_HEADSET "headset"
#define MODE_ROBOT "robot"
@@ -20,6 +24,7 @@
#define MODE_KEY_BINARY "b"
#define MODE_TOKEN_BINARY ":b"
+#define WHISPER_MODE "the type of whisper"
#define MODE_WHISPER "whisper"
#define MODE_WHISPER_CRIT "whispercrit"
@@ -45,6 +50,8 @@
#define MODE_MONKEY "monkeyhive"
+#define MODE_SING "sing"
+
#define MODE_DARKSPAWN "mindlink"
//Spans. Robot speech, italics, etc. Applied in compose_message().
@@ -56,6 +63,7 @@
#define SPAN_REALLYBIG "reallybig"
#define SPAN_COMMAND "command_headset"
#define SPAN_CLOWN "clown"
+#define SPAN_SINGING "singing"
//bitflag #defines for return value of the radio() proc.
#define ITALICS (1<<0)
diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm
index 1584e9c6a84a..aceaa5440ba0 100644
--- a/code/datums/brain_damage/imaginary_friend.dm
+++ b/code/datums/brain_damage/imaginary_friend.dm
@@ -146,10 +146,10 @@
friend_talk(message)
-/mob/camera/imaginary_friend/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
+/mob/camera/imaginary_friend/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
- create_chat_message(speaker, message_language, raw_message, spans, message_mode)
- to_chat(src, compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode))
+ create_chat_message(speaker, message_language, raw_message, spans)
+ to_chat(src, compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mods))
/mob/camera/imaginary_friend/proc/friend_talk(message)
message = capitalize(trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN)))
diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm
index 396714763e6c..48760cc02eb0 100644
--- a/code/datums/chatmessage.dm
+++ b/code/datums/chatmessage.dm
@@ -47,6 +47,7 @@
var/datum/chatmessage/prev
/// The current index used for adjusting the layer of each sequential chat message such that recent messages will overlay older ones
var/static/current_z_idx = 0
+
/**
* Constructs a chat message overlay
*
@@ -91,7 +92,7 @@
* Arguments:
* * text - The text content of the overlay
* * target - The target atom to display the overlay at
- * * owner - The mob that owns this overlay, only this mob will be able to view it#
+ * * owner - The mob that owns this overlay, only this mob will be able to view it
* * language - The language this message was spoken in
* * extra_classes - Extra classes to apply to the span that holds the text
* * lifespan - The lifespan of the message in deciseconds
@@ -224,7 +225,6 @@
* * message_language - The language that the message is said in
* * raw_message - The text content of the message
* * spans - Additional classes to be added to the message
- * * message_mode - Bitflags relating to the mode of the message
*/
/mob/proc/create_chat_message(atom/movable/speaker, datum/language/message_language, raw_message, list/spans, runechat_flags = NONE)
// Ensure the list we are using, if present, is a copy so we don't modify the list provided to us
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index bd9c578fd3e4..d4621d620531 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -16,6 +16,7 @@
var/verb_ask = "asks"
var/verb_exclaim = "exclaims"
var/verb_whisper = "whispers"
+ var/verb_sing = "sings"
var/verb_yell = "yells"
var/speech_span
var/inertia_dir = 0
diff --git a/code/game/machinery/doors/passworddoor.dm b/code/game/machinery/doors/passworddoor.dm
index fcbb214bb66a..6ad4fd80e965 100644
--- a/code/game/machinery/doors/passworddoor.dm
+++ b/code/game/machinery/doors/passworddoor.dm
@@ -22,7 +22,7 @@
if(voice_activated)
flags_1 |= HEAR_1
-/obj/machinery/door/password/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
+/obj/machinery/door/password/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
if(!density || !voice_activated || radio_freq)
return
diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm
index 8229ef77e62c..560d98fc8568 100644
--- a/code/game/machinery/hologram.dm
+++ b/code/game/machinery/hologram.dm
@@ -420,17 +420,17 @@ obj/machinery/holopad/secure/Initialize()
/*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/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
+/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
if(speaker && LAZYLEN(masters) && !radio_freq)//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(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
+ master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mods)
for(var/I in holo_calls)
var/datum/holocall/HC = I
if(HC.connected_holopad == src && speaker != HC.hologram)
- HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
+ HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mods)
if(outgoing_call && speaker == outgoing_call.user)
outgoing_call.hologram.say(raw_message)
diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm
index b9c52d441df9..f1a368256751 100644
--- a/code/game/machinery/requests_console.dm
+++ b/code/game/machinery/requests_console.dm
@@ -344,7 +344,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments)
updateUsrDialog()
-/obj/machinery/requests_console/say_mod(input, message_mode)
+/obj/machinery/requests_console/say_mod(input, list/message_mods = list())
if(spantext_char(input, "!", -3))
return "blares"
else
diff --git a/code/game/machinery/telecomms/broadcasting.dm b/code/game/machinery/telecomms/broadcasting.dm
index 1fc3a3b98fd0..7c320f600d01 100644
--- a/code/game/machinery/telecomms/broadcasting.dm
+++ b/code/game/machinery/telecomms/broadcasting.dm
@@ -103,6 +103,7 @@
datum/language/language, // the language of the message
message, // the text content of the message
spans, // the list of spans applied to the message
+ list/message_mods, // the list of modification applied to the message. Whispering, singing, ect
lvls = null //Yogs -- For NTSL. It's the list of Z-levels that should hear this message.
)
src.source = source
@@ -116,7 +117,8 @@
"message" = message,
"compression" = rand(35, 65),
"language" = lang_instance.name,
- "spans" = spans
+ "spans" = spans,
+ "mods" = message_mods
)
//Yogs start
if(lvls)
@@ -188,9 +190,10 @@
// Render the message and have everybody hear it.
// Always call this on the virtualspeaker to avoid issues.
var/spans = data["spans"]
+ var/list/message_mods = data["mods"]
var/rendered = virt.compose_message(virt, language, message, frequency, spans)
for(var/atom/movable/hearer in receive)
- hearer.Hear(rendered, virt, language, message, frequency, spans)
+ hearer.Hear(rendered, virt, language, message, frequency, spans, message_mods)
// This following recording is intended for research and feedback in the use of department radio channels
if(length(receive))
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 836e832bc44a..15cc984113c8 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -462,11 +462,11 @@
/obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits.
return
-/obj/mecha/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
+/obj/mecha/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
if(speaker == occupant)
if(radio?.broadcasting)
- radio.talk_into(speaker, text, , spans, message_language)
+ radio.talk_into(speaker, text, , spans, message_language, message_mods)
//flick speech bubble
var/list/speech_bubble_recipients = list()
for(var/mob/M in get_hearers_in_view(7,src))
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 124b2665ac9b..434286fa4775 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -376,7 +376,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
return 1
return 0
-/obj/item/proc/talk_into(mob/M, input, channel, spans, datum/language/language)
+/obj/item/proc/talk_into(mob/M, input, channel, spans, datum/language/language, list/message_mods)
return ITALICS | REDUCE_RANGE
/obj/item/proc/dropped(mob/user)
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index 92a4548a8d0e..755c28039fc7 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -60,7 +60,7 @@ GLOBAL_LIST_INIT(channel_tokens, list(
QDEL_NULL(keyslot2)
return ..()
-/obj/item/radio/headset/talk_into(mob/living/M, message, channel, list/spans,datum/language/language)
+/obj/item/radio/headset/talk_into(mob/living/M, message, channel, list/spans, datum/language/language, list/message_mods)
if (!listening)
return ITALICS | REDUCE_RANGE
return ..()
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index 40c7b9051fcd..8232354b9203 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -112,8 +112,8 @@
return TRUE
-/obj/item/radio/intercom/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode)
- if (message_mode == MODE_INTERCOM)
+/obj/item/radio/intercom/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, list/message_mods = list())
+ if(message_mods[RADIO_EXTENSION] == MODE_INTERCOM)
return // Avoid hearing the same thing twice
if(!anyai && !(speaker in ai)) // set the intercomms in AI cores to 0 when this gets implemented
return
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 3f0860e91df4..1245106a308c 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -189,15 +189,15 @@
recalculateChannels()
. = TRUE
-/obj/item/radio/talk_into(atom/movable/M, message, channel, list/spans, datum/language/language)
+/obj/item/radio/talk_into(atom/movable/M, message, channel, list/spans, datum/language/language, list/message_mods)
if(!spans)
spans = list(M.speech_span)
if(!language)
language = M.get_selected_language()
- INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language)
+ INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language, message_mods)
return ITALICS | REDUCE_RANGE
-/obj/item/radio/proc/talk_into_impl(atom/movable/M, message, channel, list/spans, datum/language/language)
+/obj/item/radio/proc/talk_into_impl(atom/movable/M, message, channel, list/spans, datum/language/language, list/message_mods)
if(!on)
return // the device has to be on
if(!M || !message)
@@ -246,7 +246,7 @@
var/atom/movable/virtualspeaker/speaker = new(null, M, src)
// Construct the signal
- var/datum/signal/subspace/vocal/signal = new(src, freq, speaker, language, message, spans)
+ var/datum/signal/subspace/vocal/signal = new(src, freq, speaker, language, message, spans, message_mods)
// Independent radios, on the CentCom frequency, reach all independent radios
if (independent && (freq == FREQ_CENTCOM || freq == FREQ_CTF_RED || freq == FREQ_CTF_BLUE))
@@ -278,21 +278,18 @@
signal.levels = list(T.z)
signal.broadcast()
-/obj/item/radio/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
+/obj/item/radio/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
if(radio_freq || !broadcasting || get_dist(src, speaker) > canhear_range)
return
- if(message_mode == MODE_WHISPER || message_mode == MODE_WHISPER_CRIT)
- // radios don't pick up whispers very well
- raw_message = stars(raw_message)
- else if(message_mode == MODE_L_HAND || message_mode == MODE_R_HAND)
+ if(message_mods[RADIO_EXTENSION] == MODE_L_HAND || message_mods[RADIO_EXTENSION] == MODE_R_HAND)
// try to avoid being heard double
if (loc == speaker && ismob(speaker))
var/mob/M = speaker
var/idx = M.get_held_index_of_item(src)
// left hands are odd slots
- if (idx && (idx % 2) == (message_mode == MODE_L_HAND))
+ if (idx && (idx % 2) == (message_mods[RADIO_EXTENSION] == MODE_L_HAND))
return
talk_into(speaker, raw_message, , spans, language=message_language)
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index 85f26c1d1dcc..e5b8790fc8bd 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -114,7 +114,7 @@
icon_state = "taperecorder_idle"
-/obj/item/taperecorder/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
+/obj/item/taperecorder/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, list/message_mods = list())
. = ..()
if(mytape && recording)
mytape.timestamp += mytape.used_capacity
diff --git a/code/game/objects/items/eightball.dm b/code/game/objects/items/eightball.dm
index 95a4389498be..86f46b8c562d 100644
--- a/code/game/objects/items/eightball.dm
+++ b/code/game/objects/items/eightball.dm
@@ -153,7 +153,7 @@
interact(user)
return ..()
-/obj/item/toy/eightball/haunted/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
+/obj/item/toy/eightball/haunted/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, list/message_mods = list())
. = ..()
last_message = raw_message
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 6d298607a695..7d76988c0d6f 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -1569,7 +1569,7 @@ obj/item/toy/turn_tracker
to_chat(user, "You name the dummy as \"[doll_name]\"")
name = "[initial(name)] - [doll_name]"
-/obj/item/toy/dummy/talk_into(atom/movable/A, message, channel, list/spans, datum/language/language)
+/obj/item/toy/dummy/talk_into(atom/movable/A, message, channel, list/spans, datum/language/language, list/message_mods)
var/mob/M = A
if (istype(M))
M.log_talk(message, LOG_SAY, tag="dummy toy")
diff --git a/code/game/say.dm b/code/game/say.dm
index 00120579768d..e43f6a3554cb 100644
--- a/code/game/say.dm
+++ b/code/game/say.dm
@@ -31,19 +31,19 @@ GLOBAL_LIST_INIT(freqtospan, list(
language = get_selected_language()
send_speech(message, 7, src, , spans, message_language=language)
-/atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
+/atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
SEND_SIGNAL(src, COMSIG_MOVABLE_HEAR, args)
/atom/movable/proc/can_speak()
return 1
-/atom/movable/proc/send_speech(message, range = 7, obj/source = src, bubble_type, list/spans, datum/language/message_language = null, message_mode)
- var/rendered = compose_message(src, message_language, message, , spans, message_mode)
+/atom/movable/proc/send_speech(message, range = 7, obj/source = src, bubble_type, list/spans, datum/language/message_language = null, list/message_mods = list())
+ var/rendered = compose_message(src, message_language, message, , spans, message_mods)
for(var/_AM in get_hearers_in_view(range, source))
var/atom/movable/AM = _AM
- AM.Hear(rendered, src, message_language, message, , spans, message_mode)
+ AM.Hear(rendered, src, message_language, message, , spans, message_mods)
-/atom/movable/proc/compose_message(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, face_name = FALSE)
+/atom/movable/proc/compose_message(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), face_name = FALSE)
//This proc uses text() because it is faster than appending strings. Thanks BYOND.
//Basic span
var/spanpart1 = ""
@@ -61,7 +61,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
var/endspanpart = ""// Yogs
//Message
- var/messagepart = " [lang_treat(speaker, message_language, raw_message, spans, message_mode)]"
+ var/messagepart = " [lang_treat(speaker, message_language, raw_message, spans, message_mods)]"
var/languageicon = ""
var/datum/language/D = GLOB.language_datum_instances[message_language]
@@ -77,10 +77,12 @@ GLOBAL_LIST_INIT(freqtospan, list(
/atom/movable/proc/compose_job(atom/movable/speaker, message_langs, raw_message, radio_freq)
return ""
-/atom/movable/proc/say_mod(input, message_mode)
+/atom/movable/proc/say_mod(input, list/message_mods = list())
var/ending = copytext_char(input, -1)
if(copytext_char(input, -2) == "!!")
return verb_yell
+ else if(message_mods[MODE_SING])
+ . = verb_sing
else if(ending == "?")
return verb_ask
else if(ending == "!")
@@ -88,7 +90,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
else
return verb_say
-/atom/movable/proc/say_quote(input, list/spans=list(speech_span), message_mode)
+/atom/movable/proc/say_quote(input, list/spans=list(speech_span), list/message_mods = list())
if(!input)
input = "..."
@@ -96,23 +98,23 @@ GLOBAL_LIST_INIT(freqtospan, list(
spans |= SPAN_YELL
var/spanned = attach_spans(input, spans)
- return "[say_mod(input, message_mode)], \"[spanned]\""
+ return "[say_mod(input, message_mods)], \"[spanned]\""
-/atom/movable/proc/lang_treat(atom/movable/speaker, datum/language/language, raw_message, list/spans, message_mode, no_quote = FALSE)
+/atom/movable/proc/lang_treat(atom/movable/speaker, datum/language/language, raw_message, list/spans, list/message_mods = list(), no_quote = FALSE)
if(has_language(language))
var/atom/movable/AM = speaker.GetSource()
if(AM) //Basically means "if the speaker is virtual"
- return no_quote ? raw_message : AM.say_quote(raw_message, spans, message_mode)
+ return no_quote ? raw_message : AM.say_quote(raw_message, spans, message_mods)
else
- return no_quote ? raw_message : speaker.say_quote(raw_message, spans, message_mode)
+ return no_quote ? raw_message : speaker.say_quote(raw_message, spans, message_mods)
else if(language)
var/atom/movable/AM = speaker.GetSource()
var/datum/language/D = GLOB.language_datum_instances[language]
raw_message = D.scramble(raw_message)
if(AM)
- return no_quote ? raw_message : AM.say_quote(raw_message, spans, message_mode)
+ return no_quote ? raw_message : AM.say_quote(raw_message, spans, message_mods)
else
- return no_quote ? raw_message : speaker.say_quote(raw_message, spans, message_mode)
+ return no_quote ? raw_message : speaker.say_quote(raw_message, spans, message_mods)
else
return "makes a strange sound."
@@ -210,13 +212,13 @@ INITIALIZE_IMMEDIATE(/atom/movable/virtualspeaker)
return job
// Yogs start -- Returns the TRUE voice if bool is true
-/atom/movable/virtualspeaker/GetVoice(bool)
+/atom/movable/virtualspeaker/GetVoice(bool)
if(bool && realvoice)
return realvoice
else
return "[src]"
-/*
+/*
// Commented out because this was causing NTSL to not properly be capable of editing verb_say & al.
// However, I don't exactly know why it was even in here in the first place, so,
// if there's some weird bugs involving virtualspeaker, check here first.
diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm
index c754b8e45ae5..7d5860c2345b 100644
--- a/code/modules/antagonists/disease/disease_mob.dm
+++ b/code/modules/antagonists/disease/disease_mob.dm
@@ -113,7 +113,7 @@ the new instance inside the host to be updated to the template's stats.
follow_next(Dir & NORTHWEST)
last_move_tick = world.time
-/mob/camera/disease/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
+/mob/camera/disease/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
var/atom/movable/to_follow = speaker
if(radio_freq)
@@ -126,9 +126,9 @@ the new instance inside the host to be updated to the template's stats.
link = ""
// Create map text prior to modifying message for goonchat
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
- create_chat_message(speaker, message_language, raw_message, spans, message_mode)
+ create_chat_message(speaker, message_language, raw_message, spans)
// Recompose the message, because it's scrambled by default
- message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
+ message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mods)
to_chat(src, "[link] [message]")
diff --git a/code/modules/assembly/voice.dm b/code/modules/assembly/voice.dm
index cd92269d88bc..1457b51e0e96 100644
--- a/code/modules/assembly/voice.dm
+++ b/code/modules/assembly/voice.dm
@@ -25,7 +25,7 @@
. = ..()
. += "Use a multitool to swap between \"inclusive\", \"exclusive\", \"recognizer\", and \"voice sensor\" mode."
-/obj/item/assembly/voice/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
+/obj/item/assembly/voice/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
if(speaker == src)
return
diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm
index 506d3896246c..5a11343de6b0 100644
--- a/code/modules/atmospherics/machinery/components/components_base.dm
+++ b/code/modules/atmospherics/machinery/components/components_base.dm
@@ -145,8 +145,8 @@
if(!parent)
WARNING("Component is missing a pipenet! Rebuilding...")
SSair.add_to_rebuild_queue(src)
- parent = parents[i]
- parent.update = 1
+ else
+ parent.update = 1
/obj/machinery/atmospherics/components/returnPipenets()
. = list()
diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm
index 66475be45a21..7bc6043fd76c 100644
--- a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm
+++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm
@@ -35,7 +35,7 @@
else
environment_temperature = T.return_temperature()
- if(abs(environment_temperature-pipe_air.return_temperature()) > minimum_temperature_difference)
+ if(abs(environment_temperature-pipe_air?.return_temperature()) > minimum_temperature_difference)
parent.temperature_interact(T, volume, thermal_conductivity)
diff --git a/code/modules/clothing/neck/bodycamera.dm b/code/modules/clothing/neck/bodycamera.dm
index 31ff70bf87a5..56603d7ba8de 100644
--- a/code/modules/clothing/neck/bodycamera.dm
+++ b/code/modules/clothing/neck/bodycamera.dm
@@ -112,7 +112,7 @@
/obj/item/clothing/neck/bodycam/dropped(mob/wearer)
..()
- if (bodcam.status)//if it's on
+ if (bodcam?.status)//if it's on
attack_self(wearer) //turn it off
GLOB.cameranet.updatePortableCamera(bodcam)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
diff --git a/code/modules/language/aphasia.dm b/code/modules/language/aphasia.dm
index 91f14f91118b..26b93bfafb63 100644
--- a/code/modules/language/aphasia.dm
+++ b/code/modules/language/aphasia.dm
@@ -11,3 +11,4 @@
space_chance = 20
default_priority = 10
icon_state = "aphasia"
+ sing_verb = "gibbers"
\ No newline at end of file
diff --git a/code/modules/language/beachbum.dm b/code/modules/language/beachbum.dm
index 528e9a8da2f4..f0e656c8a7c9 100644
--- a/code/modules/language/beachbum.dm
+++ b/code/modules/language/beachbum.dm
@@ -20,3 +20,4 @@
"tail", "trim", "tube", "wobble", "roll", "gnarly", "epic")
icon_state = "beach"
+ sing_verb = "parties"
\ No newline at end of file
diff --git a/code/modules/language/common.dm b/code/modules/language/common.dm
index 8d06dd8fa039..ea92df712357 100644
--- a/code/modules/language/common.dm
+++ b/code/modules/language/common.dm
@@ -9,6 +9,7 @@
default_priority = 100
icon_state = "galcom"
+ sing_verb = "sings"
//Syllable Lists
/*
diff --git a/code/modules/language/draconic.dm b/code/modules/language/draconic.dm
index aaa998c2c0dc..ca5b64f97b50 100644
--- a/code/modules/language/draconic.dm
+++ b/code/modules/language/draconic.dm
@@ -18,3 +18,4 @@
)
icon_state = "lizard"
default_priority = 90
+ sing_verb = "sings"
\ No newline at end of file
diff --git a/code/modules/language/drone.dm b/code/modules/language/drone.dm
index 390e0027cf83..00d3949c9c65 100644
--- a/code/modules/language/drone.dm
+++ b/code/modules/language/drone.dm
@@ -14,3 +14,4 @@
default_priority = 20
icon_state = "drone"
+ sing_verb = "chimes"
\ No newline at end of file
diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm
index ff4a19b92459..6bc108d49acd 100644
--- a/code/modules/language/language.dm
+++ b/code/modules/language/language.dm
@@ -21,7 +21,7 @@
var/list/spans = list()
var/list/scramble_cache = list()
var/default_priority = 0 // the language that an atom knows with the highest "default_priority" is selected by default.
-
+ var/sing_verb = "sings" // Used for singing.
// if you are seeing someone speak popcorn language, then something is wrong.
var/icon = 'icons/misc/language.dmi'
var/icon_state = "popcorn"
diff --git a/code/modules/language/machine.dm b/code/modules/language/machine.dm
index b7ef701e3020..7dd851161d79 100644
--- a/code/modules/language/machine.dm
+++ b/code/modules/language/machine.dm
@@ -12,6 +12,7 @@
default_priority = 90
icon_state = "eal"
+ sing_verb = "whistles melodically"
/datum/language/machine/get_random_name()
if(prob(70))
diff --git a/code/modules/language/monkey.dm b/code/modules/language/monkey.dm
index 53e598b02b25..7bf871b5e674 100644
--- a/code/modules/language/monkey.dm
+++ b/code/modules/language/monkey.dm
@@ -8,5 +8,5 @@
space_chance = 100
syllables = list("oop", "aak", "chee", "eek")
default_priority = 80
-
+ sing_verb = "chimpers tunefully"
icon_state = "animal"
diff --git a/code/modules/language/mushroom.dm b/code/modules/language/mushroom.dm
index b896d11449c3..aea98952ff52 100644
--- a/code/modules/language/mushroom.dm
+++ b/code/modules/language/mushroom.dm
@@ -9,3 +9,4 @@
sentence_chance = 0
default_priority = 80
syllables = list("poof", "pff", "pFfF", "piff", "puff", "pooof", "pfffff", "piffpiff", "puffpuff", "poofpoof", "pifpafpofpuf")
+ sing_verb = "puffs musically"
\ No newline at end of file
diff --git a/code/modules/language/narsian.dm b/code/modules/language/narsian.dm
index 70966ad8802e..aeb35ed58bbd 100644
--- a/code/modules/language/narsian.dm
+++ b/code/modules/language/narsian.dm
@@ -6,6 +6,7 @@
exclaim_verb = "invokes"
key = "n"
sentence_chance = 8
+ sing_verb = "intones"
space_chance = 95 //very high due to the potential length of each syllable
var/static/list/base_syllables = list(
"h", "v", "c", "e", "g", "d", "r", "n", "h", "o", "p",
diff --git a/code/modules/language/piratespeak.dm b/code/modules/language/piratespeak.dm
index 10d307395cad..a0300002283b 100644
--- a/code/modules/language/piratespeak.dm
+++ b/code/modules/language/piratespeak.dm
@@ -13,3 +13,4 @@
"shiver","timbers","matey","swashbuckler"
)
icon_state = "pirate"
+ sing_verb = "shanties"
\ No newline at end of file
diff --git a/code/modules/language/slime.dm b/code/modules/language/slime.dm
index 7171c07b3915..ffa95eec8400 100644
--- a/code/modules/language/slime.dm
+++ b/code/modules/language/slime.dm
@@ -7,5 +7,5 @@
key = "k"
syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix","*","!")
default_priority = 70
-
+ sing_verb = "warbles"
icon_state = "slime"
diff --git a/code/modules/language/swarmer.dm b/code/modules/language/swarmer.dm
index 2549f836692a..7c04f46f9a23 100644
--- a/code/modules/language/swarmer.dm
+++ b/code/modules/language/swarmer.dm
@@ -10,7 +10,7 @@
space_chance = 100
sentence_chance = 0
default_priority = 60
-
+ sing_verb = "tones"
icon_state = "swarmer"
// since various flats and sharps are the same,
diff --git a/code/modules/language/sylvan.dm b/code/modules/language/sylvan.dm
index 11e8866cfc3d..24b9a6d66ddd 100644
--- a/code/modules/language/sylvan.dm
+++ b/code/modules/language/sylvan.dm
@@ -7,6 +7,7 @@
exclaim_verb = "declares"
key = "h"
space_chance = 20
+ sing_verb = "serenades"
syllables = list(
"fii", "sii", "rii", "rel", "maa", "ala", "san", "tol", "tok", "dia", "eres",
"fal", "tis", "bis", "qel", "aras", "losk", "rasa", "eob", "hil", "tanl", "aere",
diff --git a/code/modules/language/xenocommon.dm b/code/modules/language/xenocommon.dm
index f046ecd34a63..b932a0a0766a 100644
--- a/code/modules/language/xenocommon.dm
+++ b/code/modules/language/xenocommon.dm
@@ -7,5 +7,5 @@
key = "4"
syllables = list("sss","sSs","SSS")
default_priority = 50
-
+ sing_verb = "hisses musically"
icon_state = "xeno"
diff --git a/code/modules/mob/dead/observer/say.dm b/code/modules/mob/dead/observer/say.dm
index 88998cb0d038..e5c69f24bcef 100644
--- a/code/modules/mob/dead/observer/say.dm
+++ b/code/modules/mob/dead/observer/say.dm
@@ -1,16 +1,27 @@
+/mob/dead/observer/check_emote(message, forced)
+ if(message == "*spin" || message == "*flip")
+ emote(copytext(message, length(message[1]) + 1), intentional = !forced)
+ return TRUE
+
+//Modified version of get_message_mods, removes the trimming, the only thing we care about here is admin channels
+/mob/dead/observer/get_message_mods(message, list/mods)
+ var/key = message[1]
+ if((key in GLOB.department_radio_prefixes) && length(message) > length(key) + 1 && !mods[RADIO_EXTENSION])
+ mods[RADIO_KEY] = lowertext(message[1 + length(key)])
+ mods[RADIO_EXTENSION] = GLOB.department_radio_keys[mods[RADIO_KEY]]
+ return message
+
/mob/dead/observer/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
if (!message)
return
-
- var/message_mode = get_message_mode(message)
- if(client && (message_mode == MODE_ADMIN || message_mode == MODE_DEADMIN))
- message = copytext_char(message, 3)
- message = trim_left(message)
-
- if(message_mode == MODE_ADMIN)
+ var/list/message_mods = list()
+ message = get_message_mods(message, message_mods)
+ if(client && (message_mods[RADIO_EXTENSION] == MODE_ADMIN || message_mods[RADIO_EXTENSION] == MODE_DEADMIN))
+ message = trim_left(copytext_char(message, length(message_mods[RADIO_KEY]) + 2))
+ if(message_mods[RADIO_EXTENSION] == MODE_ADMIN)
client.cmd_admin_say(message)
- else if(message_mode == MODE_DEADMIN)
+ else if(message_mods[RADIO_EXTENSION] == MODE_DEADMIN)
client.dsay(message)
return
@@ -19,7 +30,7 @@
. = say_dead(message)
-/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
+/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
var/atom/movable/to_follow = speaker
if(radio_freq)
@@ -33,7 +44,7 @@
var/link = FOLLOW_LINK(src, to_follow)
// Create map text prior to modifying message for goonchat
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
- create_chat_message(speaker, message_language, raw_message, spans, message_mode)
+ create_chat_message(speaker, message_language, raw_message, spans)
// Recompose the message, because it's scrambled by default
- message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
+ message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mods)
to_chat(src, "[link] [message]")
diff --git a/code/modules/mob/living/brain/say.dm b/code/modules/mob/living/brain/say.dm
index c37873e0cb34..ea2fa7aa2f84 100644
--- a/code/modules/mob/living/brain/say.dm
+++ b/code/modules/mob/living/brain/say.dm
@@ -10,11 +10,11 @@
..()
-/mob/living/brain/radio(message, message_mode, list/spans, language)
- if(message_mode == MODE_HEADSET && istype(container, /obj/item/mmi))
+/mob/living/brain/radio(message, list/message_mods = list(), list/spans, language)
+ if(message_mods[MODE_HEADSET] && istype(container, /obj/item/mmi))
var/obj/item/mmi/R = container
if(R.radio)
- R.radio.talk_into(src, message, language = language)
+ R.radio.talk_into(src, message, language = language, message_mods = message_mods)
return ITALICS | REDUCE_RANGE
else
return ..()
diff --git a/code/modules/mob/living/carbon/alien/say.dm b/code/modules/mob/living/carbon/alien/say.dm
index 1ad0a1e7ffd6..988d76827e07 100644
--- a/code/modules/mob/living/carbon/alien/say.dm
+++ b/code/modules/mob/living/carbon/alien/say.dm
@@ -20,4 +20,4 @@
/mob/living/carbon/hivecheck()
var/obj/item/organ/alien/hivenode/N = getorgan(/obj/item/organ/alien/hivenode)
if(N && !N.recent_queen_death) //Mob has alien hive node and is not under the dead queen special effect.
- return N
+ return TRUE
diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm
index 1f79dad4604b..834112d55d97 100644
--- a/code/modules/mob/living/carbon/human/say.dm
+++ b/code/modules/mob/living/carbon/human/say.dm
@@ -52,25 +52,22 @@
if(dongle.translate_binary)
return TRUE
-/mob/living/carbon/human/radio(message, message_mode, list/spans, language)
+/mob/living/carbon/human/radio(message, list/message_mods = list(), list/spans, language) //Poly has a copy of this, lazy bastard
. = ..()
- if(. != 0)
+ if(. != FALSE)
return .
- switch(message_mode)
- if(MODE_HEADSET)
- if (ears)
- ears.talk_into(src, message, , spans, language)
- return ITALICS | REDUCE_RANGE
-
- if(MODE_DEPARTMENT)
- if (ears)
- ears.talk_into(src, message, message_mode, spans, language)
- return ITALICS | REDUCE_RANGE
-
- if(message_mode in GLOB.radiochannels)
+ if(message_mods[MODE_HEADSET])
if(ears)
- ears.talk_into(src, message, message_mode, spans, language)
+ ears.talk_into(src, message, , spans, language, message_mods)
+ return ITALICS | REDUCE_RANGE
+ else if(message_mods[RADIO_EXTENSION] == MODE_DEPARTMENT)
+ if(ears)
+ ears.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
+ return ITALICS | REDUCE_RANGE
+ else if(GLOB.radiochannels[message_mods[RADIO_EXTENSION]])
+ if(ears)
+ ears.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
return ITALICS | REDUCE_RANGE
return 0
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 34cef60ebce0..b836013c00c4 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -82,33 +82,26 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return new_msg
/mob/living/say(message, bubble_type,var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
- var/static/list/crit_allowed_modes = list(MODE_WHISPER = TRUE, MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE)
+ var/static/list/crit_allowed_modes = list(WHISPER_MODE = TRUE, MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE)
var/static/list/unconscious_allowed_modes = list(MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE)
- var/talk_key = get_key(message)
-
- var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE)
if(sanitize)
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
if(!message || message == "")
return
- var/datum/saymode/saymode = SSradio.saymodes[talk_key]
- var/message_mode = get_message_mode(message)
+ var/list/message_mods = list()
var/original_message = message
+ message = get_message_mods(message, message_mods)
+ var/datum/saymode/saymode = SSradio.saymodes[message_mods[RADIO_KEY]]
var/in_critical = InCritical()
- if(one_character_prefix[message_mode])
- message = copytext_char(message, 2)
- else if(message_mode || saymode)
- message = copytext_char(message, 3)
- message = trim_left(message)
- if(message_mode == MODE_ADMIN)
+ if(message_mods[RADIO_EXTENSION] == MODE_ADMIN)
if(client)
client.cmd_admin_say(message)
return
- if(message_mode == MODE_DEADMIN)
+ if(message_mods[RADIO_EXTENSION] == MODE_DEADMIN)
if(client)
client.dsay(message)
return
@@ -120,34 +113,28 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
if(check_emote(original_message, forced) || !can_speak_basic(original_message, ignore_spam))
return
- if(in_critical)
- if(!(crit_allowed_modes[message_mode]))
+ if(in_critical) //There are cheaper ways to do this, but they're less flexible, and this isn't ran all that often
+ var/end = TRUE
+ for(var/index in message_mods)
+ if(crit_allowed_modes[index])
+ end = FALSE
+ break
+ if(end)
return
else if(stat == UNCONSCIOUS)
- if(!(unconscious_allowed_modes[message_mode]))
+ var/end = TRUE
+ for(var/index in message_mods)
+ if(unconscious_allowed_modes[index])
+ end = FALSE
+ break
+ if(end)
return
- // language comma detection.
- var/datum/language/message_language = get_message_language(message)
- if(message_language)
- // No, you cannot speak in xenocommon just because you know the key
- if(can_speak_language(message_language))
- language = message_language
- message = copytext_char(message, 3)
-
- // Trim the space if they said ",0 I LOVE LANGUAGES"
- message = trim_left(message)
+ language = message_mods[LANGUAGE_EXTENSION]
if(!language)
language = get_selected_language()
- // Detection of language needs to be before inherent channels, because
- // AIs use inherent channels for the holopad. Most inherent channels
- // ignore the language argument however.
-
- if(saymode && !saymode.handle_message(src, message, language))
- return
-
if(!can_speak_vocal(message))
to_chat(src, "You find yourself unable to speak!")
return
@@ -157,13 +144,13 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/succumbed = FALSE
var/fullcrit = InFullCritical()
- if((InCritical() && !fullcrit) || message_mode == MODE_WHISPER)
+ if((InCritical() && !fullcrit) || message_mods[WHISPER_MODE] == MODE_WHISPER)
if(fullcrit)
var/alertresult = alert(src, "You will be immediately killed by this action. Proceed?",,"Accept", "Decline")
if(alertresult == "Decline" || QDELETED(src))
return FALSE
message_range = 1
- message_mode = MODE_WHISPER
+ message_mods[WHISPER_MODE] = MODE_WHISPER
src.log_talk(message, LOG_WHISPER)
if(fullcrit)
var/health_diff = round(-HEALTH_THRESHOLD_DEAD + health)
@@ -172,7 +159,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
message = copytext_char(message, 1, health_diff) + "[message_len > health_diff ? "-.." : "..."]"
message = Ellipsis(message, 10, 1)
last_words = message
- message_mode = MODE_WHISPER_CRIT
+ message_mods[WHISPER_MODE] = MODE_WHISPER_CRIT
succumbed = TRUE
else
src.log_talk(message, LOG_SAY, forced_by=forced)
@@ -190,11 +177,26 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/datum/language/L = GLOB.language_datum_instances[language]
spans |= L.spans
- var/radio_return = radio(message, message_mode, spans, language)
+ if(message_mods[MODE_SING])
+ var/randomnote = pick("\u2669", "\u266A", "\u266B")
+ message = "[randomnote] [message] [randomnote]"
+ spans |= SPAN_SINGING
+
+ //This is before anything that sends say a radio message, and after all important message type modifications, so you can scumb in alien chat or something
+ if(saymode && !saymode.handle_message(src, message, language))
+ return
+ var/radio_message = message
+ if(message_mods[WHISPER_MODE])
+ // radios don't pick up whispers very well
+ radio_message = stars(radio_message)
+ spans |= SPAN_ITALICS
+ var/radio_return = radio(radio_message, message_mods, spans, language)
if(radio_return & ITALICS)
spans |= SPAN_ITALICS
if(radio_return & REDUCE_RANGE)
message_range = 1
+ if(!message_mods[WHISPER_MODE])
+ message_mods[WHISPER_MODE] = MODE_WHISPER
if(radio_return & NOPASS)
return 1
@@ -208,15 +210,15 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
if(pressure < ONE_ATMOSPHERE*0.4) //Thin air, let's italicise the message
spans |= SPAN_ITALICS
- send_speech(message, message_range, src, bubble_type, spans, language, message_mode)
+ send_speech(message, message_range, src, bubble_type, spans, language, message_mods)
if(succumbed)
succumb(1)
- to_chat(src, compose_message(src, language, message, , spans, message_mode))
+ to_chat(src, compose_message(src, language, message, , spans, message_mods))
return 1
-/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
+/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
if(!client)
return
@@ -231,20 +233,20 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
deaf_type = 2 // Since you should be able to hear yourself without looking
// Create map text prior to modifying message for goonchat
if (client?.prefs.chat_on_map && stat != UNCONSCIOUS && (client.prefs.see_chat_non_mob || ismob(speaker)) && can_hear())
- create_chat_message(speaker, message_language, raw_message, spans, message_mode)
+ create_chat_message(speaker, message_language, raw_message, spans)
// Recompose message for AI hrefs, language incomprehension.
- message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
+ message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mods)
SEND_SIGNAL(src, COMSIG_MOVABLE_HEAR, args)
show_message(message, 2, deaf_message, deaf_type)
return message
-/mob/living/send_speech(message, message_range = 6, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language=null, message_mode)
+/mob/living/send_speech(message, message_range = 6, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language=null, list/message_mods = list())
var/static/list/eavesdropping_modes = list(MODE_WHISPER = TRUE, MODE_WHISPER_CRIT = TRUE)
var/eavesdrop_range = 0
- if(eavesdropping_modes[message_mode])
+ if(message_mods[WHISPER_MODE]) //If we're whispering
eavesdrop_range = EAVESDROP_EXTRA_RANGE
var/list/listening = get_hearers_in_view(message_range+eavesdrop_range, source)
var/list/the_dead = list()
@@ -257,7 +259,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
if(!M.client || !client) //client is so that ghosts don't have to listen to mice
continue
if(get_dist(M, src) > 7 || M.z != z) //they're out of range of normal hearing
- if(eavesdropping_modes[message_mode] && !(M.client.prefs.chat_toggles & CHAT_GHOSTWHISPER)) //they're whispering and we have hearing whispers at any range off
+ if(eavesdrop_range && !(M.client.prefs.chat_toggles & CHAT_GHOSTWHISPER)) //they're whispering and we have hearing whispers at any range off
continue
if(!(M.client.prefs.chat_toggles & CHAT_GHOSTEARS)) //they're talking normally and we have hearing at any range off
continue
@@ -268,15 +270,15 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/eavesrendered
if(eavesdrop_range)
eavesdropping = stars(message)
- eavesrendered = compose_message(src, message_language, eavesdropping, , spans, message_mode)
+ eavesrendered = compose_message(src, message_language, eavesdropping, , spans, message_mods)
- var/rendered = compose_message(src, message_language, message, , spans, message_mode)
+ var/rendered = compose_message(src, message_language, message, , spans, message_mods)
for(var/_AM in listening)
var/atom/movable/AM = _AM
if(eavesdrop_range && get_dist(source, AM) > message_range && !(the_dead[AM]))
- AM.Hear(eavesrendered, src, message_language, eavesdropping, , spans, message_mode)
+ AM.Hear(eavesrendered, src, message_language, eavesdropping, , spans, message_mods)
else
- AM.Hear(rendered, src, message_language, message, , spans, message_mode)
+ AM.Hear(rendered, src, message_language, message, , spans, message_mods)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message)
//speech bubble
@@ -293,43 +295,29 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
/mob/living/can_speak(message) //For use outside of Say()
if(can_speak_basic(message) && can_speak_vocal(message))
- return 1
+ return TRUE
/mob/living/proc/can_speak_basic(message, ignore_spam = FALSE) //Check BEFORE handling of xeno and ling channels
if(client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, "You cannot speak in IC (muted).")
- return 0
+ return FALSE
if(!ignore_spam && client.handle_spam_prevention(message,MUTE_IC))
- return 0
+ return FALSE
- return 1
+ return TRUE
/mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels
if(HAS_TRAIT(src, TRAIT_MUTE))
- return 0
+ return FALSE
if(is_muzzled())
- return 0
+ return FALSE
if(!IsVocal())
- return 0
+ return FALSE
- return 1
-
-/mob/living/proc/get_key(message)
- var/key = message[1]
- if(key in GLOB.department_radio_prefixes)
- return lowertext(message[1 + length(key)])
-
-/mob/living/proc/get_message_language(message)
- if(message[1] == ",")
- var/key = message[1 + length(message[1])]
- for(var/ld in GLOB.all_languages)
- var/datum/language/LD = ld
- if(initial(LD.key) == key)
- return LD
- return null
+ return TRUE
/mob/living/proc/treat_message(message)
if(HAS_TRAIT(src, TRAIT_UNINTELLIGIBLE_SPEECH))
@@ -351,33 +339,31 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return message
-/mob/living/proc/radio(message, message_mode, list/spans, language)
+/mob/living/proc/radio(message, list/message_mods = list(), list/spans, language)
var/obj/item/implant/radio/imp = locate() in src
if(imp && imp.radio.on)
- if(message_mode == MODE_HEADSET)
- imp.radio.talk_into(src, message, , spans, language)
+ if(message_mods[MODE_HEADSET])
+ imp.radio.talk_into(src, message, , spans, language, message_mods)
return ITALICS | REDUCE_RANGE
- if(message_mode == MODE_DEPARTMENT || (message_mode in GLOB.radiochannels))
- imp.radio.talk_into(src, message, message_mode, spans, language)
+ if(message_mods[RADIO_EXTENSION] == MODE_DEPARTMENT || (message_mods[RADIO_EXTENSION] in imp.radio.channels))
+ imp.radio.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
return ITALICS | REDUCE_RANGE
- switch(message_mode)
- if(MODE_WHISPER)
- return ITALICS
+ switch(message_mods[RADIO_EXTENSION])
if(MODE_R_HAND)
for(var/obj/item/r_hand in get_held_items_for_side("r", all = TRUE))
if (r_hand)
- return r_hand.talk_into(src, message, , spans, language)
+ return r_hand.talk_into(src, message, , spans, language, message_mods)
return ITALICS | REDUCE_RANGE
if(MODE_L_HAND)
for(var/obj/item/l_hand in get_held_items_for_side("l", all = TRUE))
if (l_hand)
- return l_hand.talk_into(src, message, , spans, language)
+ return l_hand.talk_into(src, message, , spans, language, message_mods)
return ITALICS | REDUCE_RANGE
if(MODE_INTERCOM)
for (var/obj/item/radio/intercom/I in view(1, null))
- I.talk_into(src, message, , spans, language)
+ I.talk_into(src, message, , spans, language, message_mods)
return ITALICS | REDUCE_RANGE
if(MODE_BINARY)
@@ -385,11 +371,13 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return 0
-/mob/living/say_mod(input, message_mode)
- if(message_mode == MODE_WHISPER)
+/mob/living/say_mod(input, list/message_mods = list())
+ if(message_mods[WHISPER_MODE] == MODE_WHISPER)
. = verb_whisper
- else if(message_mode == MODE_WHISPER_CRIT)
+ else if(message_mods[WHISPER_MODE] == MODE_WHISPER_CRIT)
. = "[verb_whisper] in [p_their()] last breath"
+ else if(message_mods[MODE_SING])
+ . = verb_sing
else if(stuttering)
. = "stammers"
else if(derpspeech)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 0a3056164c7c..eff1b618578b 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -822,8 +822,8 @@
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(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
- var/treated_message = lang_treat(speaker, message_language, raw_message, spans, message_mode)
+/mob/living/silicon/ai/proc/relay_speech(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
+ var/treated_message = lang_treat(speaker, message_language, raw_message, spans, message_mods)
var/start = "Relayed Speech: "
var/namepart = "[speaker.GetVoice()][speaker.get_alt_name()]"
var/hrefpart = ""
@@ -841,7 +841,7 @@
var/rendered = "[start][hrefpart][namepart] ([jobpart]) [treated_message]"
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
- create_chat_message(speaker, message_language, raw_message, spans, message_mode)
+ create_chat_message(speaker, message_language, raw_message, spans)
show_message(rendered, 2)
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index 77f1461be176..b3bd45e4b680 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -193,10 +193,10 @@
acceleration = !acceleration
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
-/mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
+/mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker))
- ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
+ ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mods)
/obj/effect/overlay/ai_detect_hud
name = ""
diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm
index e5c50fe23677..9bbe30634b0b 100644
--- a/code/modules/mob/living/silicon/ai/say.dm
+++ b/code/modules/mob/living/silicon/ai/say.dm
@@ -17,7 +17,7 @@
/mob/living/silicon/ai/IsVocal()
return !CONFIG_GET(flag/silent_ai)
-/mob/living/silicon/ai/radio(message, message_mode, list/spans, language)
+/mob/living/silicon/ai/radio(message, list/message_mods = list(), list/spans, language)
if(incapacitated())
return FALSE
if(!radio_enabled) //AI cannot speak if radio is disabled (via intellicard) or depowered.
@@ -25,13 +25,6 @@
return FALSE
..()
-/mob/living/silicon/ai/get_message_mode(message)
- var/static/regex/holopad_finder = regex(@"[:.#][hH]")
- if(holopad_finder.Find(message, 1, 1))
- return MODE_HOLOPAD
- else
- return ..()
-
//For holopads only. Usable by AI.
/mob/living/silicon/ai/proc/holopad_talk(message, language)
@@ -52,7 +45,7 @@
var/obj/effect/overlay/hologram = T.masters[src]
src.log_talk(message, LOG_SAY, tag="HOLOPAD in [padloc]")
hologram.say("[message]")
- send_speech(message, 7, T, "robot", message_language = language)
+ send_speech(message, 7, T, MODE_ROBOT, message_language = language)
to_chat(src, "Holopad transmitted, [real_name] \"[message]\"")
else
to_chat(src, "No holopad connected.")
diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm
index fbc1eb4eb969..3efc0b65a388 100644
--- a/code/modules/mob/living/silicon/say.dm
+++ b/code/modules/mob/living/silicon/say.dm
@@ -29,26 +29,19 @@
/mob/living/silicon/lingcheck()
return 0 //Borged or AI'd lings can't speak on the ling channel.
-/mob/living/silicon/radio(message, message_mode, list/spans, language)
+/mob/living/silicon/radio(message, list/message_mods = list(), list/spans, language)
. = ..()
if(. != 0)
return .
- if(message_mode == "robot")
- if (radio)
- radio.talk_into(src, message, , spans, language)
+ if(message_mods[MODE_HEADSET])
+ if(radio)
+ radio.talk_into(src, message, , spans, language, message_mods)
return REDUCE_RANGE
- else if(message_mode in GLOB.radiochannels)
+ else if(message_mods[RADIO_EXTENSION] in GLOB.radiochannels)
if(radio)
- radio.talk_into(src, message, message_mode, spans, language)
+ radio.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
return ITALICS | REDUCE_RANGE
return 0
-
-/mob/living/silicon/get_message_mode(message)
- . = ..()
- if(..() == MODE_HEADSET)
- return MODE_ROBOT
- else
- return .
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index 8e7871fd88ba..ad8660a3f00f 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -373,22 +373,19 @@
else
say(message)
-/mob/living/simple_animal/bot/radio(message, message_mode, list/spans, language)
+/mob/living/simple_animal/bot/radio(message, list/message_mods = list(), list/spans, language)
. = ..()
if(. != 0)
return
- switch(message_mode)
- if(MODE_HEADSET)
- Radio.talk_into(src, message, , spans, language)
- return REDUCE_RANGE
-
- if(MODE_DEPARTMENT)
- Radio.talk_into(src, message, message_mode, spans, language)
- return REDUCE_RANGE
-
- if(message_mode in GLOB.radiochannels)
- Radio.talk_into(src, message, message_mode, spans, language)
+ if(message_mods[MODE_HEADSET])
+ Radio.talk_into(src, message, , spans, language, message_mods)
+ return REDUCE_RANGE
+ else if(message_mods[RADIO_EXTENSION] == MODE_DEPARTMENT)
+ Radio.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
+ return REDUCE_RANGE
+ else if(message_mods[RADIO_EXTENSION] in GLOB.radiochannels)
+ Radio.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
return REDUCE_RANGE
/mob/living/simple_animal/bot/proc/drop_part(obj/item/drop_item, dropzone)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index f45e773dcda6..2ef75c4d6483 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -424,7 +424,7 @@ Difficulty: Very Hard
. += observer_desc
. += "It is activated by [activation_method]."
-/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
+/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, list/message_mods = list())
..()
if(isliving(speaker))
ActivationReaction(speaker, ACTIVATE_SPEECH)
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 0b44436747c0..b44d6a1a3775 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -143,7 +143,7 @@
. += "Held Item: [held_item]"
. += "Mode: [a_intent]"
-/mob/living/simple_animal/parrot/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode)
+/mob/living/simple_animal/parrot/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
if(speaker != src && prob(50)) //Dont imitate ourselves
if(!radio_freq || prob(10))
@@ -153,29 +153,24 @@
if(speaker == src && !client) //If a parrot squawks in the woods and no one is around to hear it, does it make a sound? This code says yes!
return message
-/mob/living/simple_animal/parrot/radio(message, message_mode, list/spans, language) //literally copied from human/radio(), but there's no other way to do this. at least it's better than it used to be.
+/mob/living/simple_animal/parrot/radio(message, list/message_mods = list(), list/spans, language) //literally copied from human/radio(), but there's no other way to do this. at least it's better than it used to be.
. = ..()
if(. != 0)
return .
-
- switch(message_mode)
- if(MODE_HEADSET)
- if (ears)
- ears.talk_into(src, message, , spans, language)
- return ITALICS | REDUCE_RANGE
-
- if(MODE_DEPARTMENT)
- if (ears)
- ears.talk_into(src, message, message_mode, spans, language)
- return ITALICS | REDUCE_RANGE
-
- if(message_mode in GLOB.radiochannels)
+ if(message_mods[MODE_HEADSET])
if(ears)
- ears.talk_into(src, message, message_mode, spans, language)
+ ears.talk_into(src, message, , spans, language, message_mods)
+ return ITALICS | REDUCE_RANGE
+ else if(message_mods[RADIO_EXTENSION] == MODE_DEPARTMENT)
+ if(ears)
+ ears.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
+ return ITALICS | REDUCE_RANGE
+ else if(message_mods[RADIO_EXTENSION] in GLOB.radiochannels)
+ if(ears)
+ ears.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
return ITALICS | REDUCE_RANGE
return 0
-
/*
* Inventory
*/
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 36c5e996eb0c..4a3c39085575 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -276,7 +276,7 @@
if(icon_gib)
new /obj/effect/temp_visual/gib_animation/animal(loc, icon_gib)
-/mob/living/simple_animal/say_mod(input, message_mode)
+/mob/living/simple_animal/say_mod(input, list/message_mods = list())
if(speak_emote && speak_emote.len)
verb_say = pick(speak_emote)
. = ..()
diff --git a/code/modules/mob/living/simple_animal/slime/say.dm b/code/modules/mob/living/simple_animal/slime/say.dm
index a2618b711e96..0b692e6d5c0d 100644
--- a/code/modules/mob/living/simple_animal/slime/say.dm
+++ b/code/modules/mob/living/simple_animal/slime/say.dm
@@ -1,4 +1,4 @@
-/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
+/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, list/message_mods = list())
. = ..()
if(speaker != src && !radio_freq && !stat)
if (speaker in Friends)
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index 569dbbfbf17f..47475e3b8c44 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -116,20 +116,50 @@
/mob/proc/lingcheck()
return LINGHIVE_NONE
+///The amount of items we are looking for in the message
+#define MESSAGE_MODS_LENGTH 6
+
/**
- * Get the mode of a message
+ * Extracts and cleans message of any extenstions at the begining of the message
+ * Inserts the info into the passed list, returns the cleaned message
*
* Result can be
+ * * SAY_MODE (Things like aliens, channels that aren't channels)
* * MODE_WHISPER (Quiet speech)
+ * * MODE_SING (Singing)
* * MODE_HEADSET (Common radio channel)
- * * A department radio (lots of values here)
+ * * RADIO_EXTENSION the extension we're using (lots of values here)
+ * * RADIO_KEY the radio key we're using, to make some things easier later (lots of values here)
+ * * LANGUAGE_EXTENSION the language we're trying to use (lots of values here)
*/
-/mob/proc/get_message_mode(message)
- var/key = message[1]
- if(key == "#")
- return MODE_WHISPER
- else if(key == ";")
- return MODE_HEADSET
- else if((length(message) > (length(key) + 1)) && (key in GLOB.department_radio_prefixes))
- var/key_symbol = lowertext(message[length(key) + 1])
- return GLOB.department_radio_keys[key_symbol]
+/mob/proc/get_message_mods(message, list/mods)
+ for(var/I in 1 to MESSAGE_MODS_LENGTH)
+ var/key = message[1]
+ var/chop_to = 2 //By default we just take off the first char
+ if(key == "#" && !mods[WHISPER_MODE])
+ mods[WHISPER_MODE] = MODE_WHISPER
+ else if(key == "%" && !mods[MODE_SING])
+ mods[MODE_SING] = TRUE
+ else if(key == ";" && !mods[MODE_HEADSET])
+ mods[MODE_HEADSET] = TRUE
+ else if((key in GLOB.department_radio_prefixes) && length(message) > length(key) + 1 && !mods[RADIO_EXTENSION])
+ mods[RADIO_KEY] = lowertext(message[1 + length(key)])
+ mods[RADIO_EXTENSION] = GLOB.department_radio_keys[mods[RADIO_KEY]]
+ chop_to = length(key) + 2
+ else if(key == "," && !mods[LANGUAGE_EXTENSION])
+ for(var/ld in GLOB.all_languages)
+ var/datum/language/LD = ld
+ if(initial(LD.key) == message[1 + length(message[1])])
+ // No, you cannot speak in xenocommon just because you know the key
+ if(!can_speak_language(LD))
+ return message
+ mods[LANGUAGE_EXTENSION] = LD
+ chop_to = length(key) + length(initial(LD.key)) + 1
+ if(!mods[LANGUAGE_EXTENSION])
+ return message
+ else
+ return message
+ message = trim_left(copytext_char(message, chop_to))
+ if(!message)
+ return
+ return message
\ No newline at end of file
diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm
index b3b8e5224bb0..ae39840bbebe 100644
--- a/interface/stylesheet.dm
+++ b/interface/stylesheet.dm
@@ -55,6 +55,7 @@ em {font-style: normal; font-weight: bold;}
.aiprivradio {color: #ff00ff;}
.redteamradio {color: #ff0000;}
.blueteamradio {color: #0000ff;}
+.singing {font-family: "Trebuchet MS", cursive, sans-serif; font-style: italic;}
.yell { font-weight: bold;}
diff --git a/strings/names/verbs.txt b/strings/names/verbs.txt
index fc90f89e4008..623cf0185f45 100644
--- a/strings/names/verbs.txt
+++ b/strings/names/verbs.txt
@@ -486,6 +486,7 @@ sigh
sign
signal
sin
+sing
sip
ski
skip