diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm
index 9502db55f..49010f957 100644
--- a/code/__DEFINES/say.dm
+++ b/code/__DEFINES/say.dm
@@ -61,9 +61,9 @@
#define SPAN_SMALL "small"
//bitflag #defines for return value of the radio() proc.
-#define ITALICS 1
-#define REDUCE_RANGE 2
-#define NOPASS 4
+#define ITALICS (1<<0)
+#define REDUCE_RANGE (1<<1)
+#define NOPASS (1<<2)
//Eavesdropping
#define EAVESDROP_EXTRA_RANGE 1 //how much past the specified message_range does the message get starred, whispering only
@@ -88,3 +88,7 @@
// Audio/Visual Flags. Used to determine what sense are required to notice a message.
#define MSG_VISUAL (1<<0)
#define MSG_AUDIBLE (1<<1)
+
+
+//Used in visible_message_flags, audible_message_flags and runechat_flags
+#define EMOTE_MESSAGE (1<<0)
\ No newline at end of file
diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm
index 8cac8b435..4c773a7e1 100644
--- a/code/datums/chatmessage.dm
+++ b/code/datums/chatmessage.dm
@@ -55,15 +55,6 @@
message = null
return ..()
-/**
- * Calls qdel on the chatmessage when its parent is deleted, used to register qdel signal
- */
-/datum/chatmessage/proc/on_parent_qdel()
- UnregisterSignal(src, COMSIG_PARENT_QDELETING)
- qdel(src)
-
-
-
/**
* Generates a chat message image representation
*
@@ -107,10 +98,10 @@
// Append radio icon if from a virtual speaker
if (extra_classes.Find("virtual-speaker"))
var/image/r_icon = image('icons/UI_Icons/chat/chat_icons.dmi', icon_state = "radio")
- text = "\icon[r_icon] " + text
+ text = "\icon[r_icon] [text]"
else if (extra_classes.Find("emote"))
- var/image/r_icon = image('icons/ui_icons/chat/chat_icons.dmi', icon_state = "emote")
- text = "\icon[r_icon] " + text
+ var/image/r_icon = image('icons/UI_Icons/chat/chat_icons.dmi', icon_state = "emote")
+ text = "\icon[r_icon] [text]"
// We dim italicized text to make it more distinguishable from regular text
var/tgt_color = extra_classes.Find("italics") ? target.chat_color_darkened : target.chat_color
@@ -120,7 +111,7 @@
// BYOND Bug #2563917
// Construct text
var/static/regex/html_metachars = new(@"&[A-Za-z]{1,7};", "g")
- var/complete_text = ""
+ var/complete_text = ""
var/mheight = WXH_TO_HEIGHT(owned_by.MeasureText(replacetext(complete_text, html_metachars, "m"), null, CHAT_MESSAGE_WIDTH))
approx_lines = max(1, mheight / CHAT_MESSAGE_APPROX_LHEIGHT)
@@ -176,7 +167,7 @@
* * 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, message_mode)
+/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
spans = spans ? spans.Copy() : list()
@@ -192,7 +183,10 @@
return
// Display visual above source
- new /datum/chatmessage(lang_treat(speaker, message_language, raw_message, spans, null, TRUE), speaker, src, spans)
+ if(runechat_flags & EMOTE_MESSAGE)
+ new /datum/chatmessage(raw_message, speaker, src, list("emote", "italics"))
+ else
+ new /datum/chatmessage(lang_treat(speaker, message_language, raw_message, spans, null, TRUE), speaker, src, spans)
// Tweak these defines to change the available color ranges
@@ -246,3 +240,11 @@
return "#[num2hex(x, 2)][num2hex(m, 2)][num2hex(c, 2)]"
if(5)
return "#[num2hex(c, 2)][num2hex(m, 2)][num2hex(x, 2)]"
+
+
+/**
+ * Calls qdel on the chatmessage when its parent is deleted, used to register qdel signal
+ */
+/datum/chatmessage/proc/on_parent_qdel()
+ qdel(src)
+
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index fe3456f2c..02c964045 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -58,19 +58,19 @@
return
user.log_message(msg, LOG_EMOTE)
- msg = "[user] " + msg
+ var/dchatmsg = "[user] [msg]"
for(var/mob/M in GLOB.dead_mob_list)
if(!M.client || isnewplayer(M))
continue
var/T = get_turf(user)
if(M.stat == DEAD && M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT) && !(M in viewers(T, null)) && (user.client)) //SKYRAT CHANGE - only user controlled mobs show their emotes to all-seeing ghosts, to reduce chat spam
- M.show_message(msg)
+ M.show_message("[FOLLOW_LINK(M, user)] [dchatmsg]")
if(emote_type == EMOTE_AUDIBLE)
- user.audible_message(msg)
+ user.audible_message(msg, audible_message_flags = EMOTE_MESSAGE)
else
- user.visible_message(msg)
+ user.visible_message(msg, visible_message_flags = EMOTE_MESSAGE)
/datum/emote/proc/replace_pronoun(mob/user, message)
if(findtext(message, "their"))
diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm
index 1ae020554..410eda7d0 100644
--- a/code/modules/antagonists/disease/disease_mob.dm
+++ b/code/modules/antagonists/disease/disease_mob.dm
@@ -129,6 +129,11 @@ the new instance inside the host to be updated to the template's stats.
link = FOLLOW_LINK(src, to_follow)
else
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)
+
// Recompose the message, because it's scrambled by default
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
to_chat(src, "[link] [message]")
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index d50fdc5f0..4917cbaa5 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -50,6 +50,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/radiosounds = TRUE
var/max_chat_length = CHAT_MESSAGE_MAX_LENGTH
var/see_chat_non_mob = TRUE
+ var/see_rc_emotes = TRUE
var/tgui_fancy = TRUE
var/tgui_lock = TRUE
var/windowflashing = TRUE
@@ -1041,6 +1042,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Chat Bubbles: [chat_on_map ? "Enabled" : "Disabled"]
"
dat += "Chat Bubbles message char limit: [max_chat_length]
"
dat += "Chat Bubbles for non-mobs: [see_chat_non_mob ? "Enabled" : "Disabled"]
"
+ dat += "Chat Bubbles emotes: [see_rc_emotes ? "Enabled" : "Disabled"]
"
dat += "
"
dat += "Autocorrect: [(autocorrect) ? "On" : "Off"]
"
dat += "Radio Sounds: [radiosounds ? "Enabled" : "Disabled"]
"
@@ -2835,6 +2837,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
radiosounds = !radiosounds
if("see_chat_non_mob")
see_chat_non_mob = !see_chat_non_mob
+ if("see_rc_emotes")
+ see_rc_emotes = !see_rc_emotes
if("tgui_fancy")
tgui_fancy = !tgui_fancy
if("tgui_lock")
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 47afd6d98..190a6c2f8 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -116,6 +116,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["radiosounds"] >> radiosounds
S["max_chat_length"] >> max_chat_length
S["see_chat_non_mob"] >> see_chat_non_mob
+ S["see_rc_emotes"] >> see_rc_emotes
S["parallax"] >> parallax
@@ -224,6 +225,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["radiosounds"], radiosounds)
WRITE_FILE(S["max_chat_length"], max_chat_length)
WRITE_FILE(S["see_chat_non_mob"], see_chat_non_mob)
+ WRITE_FILE(S["see_rc_emotes"], see_rc_emotes)
WRITE_FILE(S["tgui_fancy"], tgui_fancy)
WRITE_FILE(S["tgui_lock"], tgui_lock)
WRITE_FILE(S["buttons_locked"], buttons_locked)
diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index e5aa0c3d0..4119dfbbc 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -703,7 +703,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
var/image/speech_overlay = image('icons/mob/talk.dmi', person, "default0", layer = ABOVE_MOB_LAYER)
INVOKE_ASYNC(GLOBAL_PROC, /proc/flick_overlay, speech_overlay, list(target.client), 30)
if (target.client?.prefs.chat_on_map)
- target.create_chat_message(person, understood_language, chosen, spans, 0)
+ target.create_chat_message(person, understood_language, chosen, spans)
to_chat(target, message)
qdel(src)
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index c4032177e..df278390d 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -249,6 +249,10 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
deaf_message = "You can't hear yourself!"
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)
+
if (client?.prefs.radiosounds && stat != UNCONSCIOUS && can_hear() && radio_freq)
playsound_local(src,'sound/voice/radio.ogg', 30, 0)
@@ -304,7 +308,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
//speech bubble
var/list/speech_bubble_recipients = list()
for(var/mob/M in listening)
- speech_bubble_recipients.Add(M.client)
+ if(M.client && !M.client.prefs.chat_on_map)
+ speech_bubble_recipients.Add(M.client)
var/image/I = image('icons/mob/talk.dmi', src, "[bubble_type][say_test(message)]", FLY_LAYER)
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, speech_bubble_recipients, 30)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
index 1da1c8326..46c4858b4 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -80,7 +80,7 @@ Difficulty: Medium
return FALSE
return ..()
-/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs)
+/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE)
if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit
return
return ..()
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index f3ca2844d..0dda0ed3e 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -127,7 +127,7 @@
* * vision_distance (optional) define how many tiles away the message can be seen.
* * ignored_mobs (optional) doesn't show any message to any given mob in the list.
*/
-/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs)
+/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE)
var/turf/T = get_turf(src)
if(!T)
return
@@ -139,6 +139,11 @@
hearers -= ignored_mobs
if(self_message)
hearers -= src
+
+ var/raw_msg = message
+ if(visible_message_flags & EMOTE_MESSAGE)
+ message = "[src] [message]"
+
for(var/mob/M in hearers)
if(!M.client)
continue
@@ -152,10 +157,14 @@
if(!msg)
continue
+
+ if(visible_message_flags & EMOTE_MESSAGE && runechat_prefs_check(M, visible_message_flags))
+ M.create_chat_message(src, raw_message = raw_msg, runechat_flags = visible_message_flags)
+
M.show_message(msg, MSG_VISUAL,blind_message, MSG_AUDIBLE)
///Adds the functionality to self_message.
-mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs)
+/mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE)
. = ..()
if(self_message)
show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE)
@@ -171,7 +180,7 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
* * hearing_distance (optional) is the range, how many tiles away the message can be heard.
* * ignored_mobs (optional) doesn't show any message to any given mob in the list.
*/
-/atom/proc/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, list/ignored_mobs)
+/atom/proc/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, list/ignored_mobs, visible_message_flags = NONE, audible_message_flags = NONE)
var/turf/T = get_turf(src)
if(!T)
return
@@ -183,7 +192,15 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
hearers -= ignored_mobs
if(self_message)
hearers -= src
+
+ var/raw_msg = message
+ if(audible_message_flags & EMOTE_MESSAGE)
+ message = "[src] [message]"
+
for(var/mob/M in hearers)
+ if(audible_message_flags & EMOTE_MESSAGE && runechat_prefs_check(M, audible_message_flags))
+ M.create_chat_message(src, raw_message = raw_msg, runechat_flags = audible_message_flags)
+
M.show_message(message, MSG_AUDIBLE, deaf_message, MSG_VISUAL)
/**
@@ -198,11 +215,27 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
* * hearing_distance (optional) is the range, how many tiles away the message can be heard.
* * ignored_mobs (optional) doesn't show any message to any given mob in the list.
*/
-/mob/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, list/ignored_mobs)
+/mob/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, list/ignored_mobs, audible_message_flags = NONE)
. = ..()
if(self_message)
show_message(self_message, MSG_AUDIBLE, deaf_message, MSG_VISUAL)
+
+///Returns the client runechat visible messages preference according to the message type.
+/atom/proc/runechat_prefs_check(mob/target, visible_message_flags = NONE)
+ if(!target.client?.prefs.chat_on_map || !target.client.prefs.see_chat_non_mob)
+ return FALSE
+ if(visible_message_flags & EMOTE_MESSAGE && !target.client.prefs.see_rc_emotes)
+ return FALSE
+ return TRUE
+
+/mob/runechat_prefs_check(mob/target, message, visible_message_flags = NONE)
+ if(!target.client?.prefs.chat_on_map)
+ return FALSE
+ if(visible_message_flags & EMOTE_MESSAGE && !target.client.prefs.see_rc_emotes)
+ return FALSE
+ return TRUE
+
/mob/proc/Life()
set waitfor = FALSE