diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm
index 7a78e1d001..73d3e69ac4 100644
--- a/code/datums/chatmessage.dm
+++ b/code/datums/chatmessage.dm
@@ -114,7 +114,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)
diff --git a/code/game/say.dm b/code/game/say.dm
index 187994f432..35a1b1d072 100644
--- a/code/game/say.dm
+++ b/code/game/say.dm
@@ -59,7 +59,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
var/endspanpart = ""
//Message
- var/messagepart = " [lang_treat(speaker, message_language, raw_message, spans, message_mode)]"
+ var/messagepart = " [say_emphasis(lang_treat(speaker, message_language, raw_message, spans, message_mode))]"
var/languageicon = ""
var/datum/language/D = GLOB.language_datum_instances[message_language]
@@ -96,6 +96,18 @@ GLOBAL_LIST_INIT(freqtospan, list(
return "[say_mod(input, message_mode)][spanned ? ", \"[spanned]\"" : ""]"
// Citadel edit [spanned ? ", \"[spanned]\"" : ""]"
+#define ENCODE_HTML_EPHASIS(input, char, html, varname) \
+ var/static/regex/##varname = regex("[char]{2}(.+?)[char]{2}", "g");\
+ input = varname.Replace_char(input, "<[html]>$1[html]>")
+
+/atom/movable/proc/say_emphasis(input)
+ ENCODE_HTML_EPHASIS(input, "\\|", "i", italics)
+ ENCODE_HTML_EPHASIS(input, "\\+", "b", bold)
+ ENCODE_HTML_EPHASIS(input, "_", "u", underline)
+ return input
+
+#undef ENCODE_HTML_EPHASIS
+
/// Quirky citadel proc for our custom sayverbs to strip the verb out. Snowflakey as hell, say rewrite 3.0 when?
/atom/movable/proc/quoteless_say_quote(input, list/spans = list(speech_span), message_mode)
var/pos = findtext(input, "*")
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 111054c383..7d0a701e8f 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -457,6 +457,7 @@
message = params
if(type_override)
emote_type = type_override
+ message = user.say_emphasis(message)
. = ..()
message = null
emote_type = EMOTE_VISIBLE
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index e2b3aee35d..a403845ee2 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -113,7 +113,7 @@
if(name != real_name)
alt_name = " (died as [real_name])"
- var/spanned = say_quote(message)
+ var/spanned = say_quote(say_emphasis(message))
message = emoji_parse(message)
var/rendered = "DEAD: [name][alt_name] [emoji_parse(spanned)]"
log_talk(message, LOG_SAY, tag="DEAD")
diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm
index 44dc3e2a05..5ed24af726 100644
--- a/code/modules/mob/say_vr.dm
+++ b/code/modules/mob/say_vr.dm
@@ -60,7 +60,7 @@ proc/get_top_level_mob(var/mob/S)
return FALSE
user.log_message(message, LOG_EMOTE)
- message = "[user] " + "[message]"
+ message = "[user] " + "[user.say_emphasis(message)]"
for(var/mob/M in GLOB.dead_mob_list)
if(!M.client || isnewplayer(M))
@@ -121,7 +121,7 @@ proc/get_top_level_mob(var/mob/S)
return FALSE
user.log_message(message, LOG_SUBTLER)
- message = "[user] " + "[message]"
+ message = "[user] " + "[user.say_emphasis(message)]"
if(emote_type == EMOTE_AUDIBLE)
user.audible_message(message=message,hearing_distance=1, ignored_mobs = GLOB.dead_mob_list)