diff --git a/code/__DEFINES/_flags.dm b/code/__DEFINES/_flags.dm
index 5969f81bccb..74af498376e 100644
--- a/code/__DEFINES/_flags.dm
+++ b/code/__DEFINES/_flags.dm
@@ -312,3 +312,5 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define EMOTE_VISIBLE (1<<1)
/// Is it an emote that should be shown regardless of blindness/deafness
#define EMOTE_IMPORTANT (1<<2)
+/// Emote only prints to runechat, not to the chat window
+#define EMOTE_RUNECHAT (1<<3)
diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm
index f82f4af2ddd..75366f07d48 100644
--- a/code/__DEFINES/say.dm
+++ b/code/__DEFINES/say.dm
@@ -119,5 +119,10 @@
-//Used in visible_message_flags, audible_message_flags and runechat_flags
+// Used in visible_message_flags, audible_message_flags and runechat_flags
+/// Automatically applies emote related spans/fonts/formatting to the message
#define EMOTE_MESSAGE (1<<0)
+/// By default, self_message will respect the visual / audible component of the message.
+/// Meaning that if the message is visual, and sourced from a blind mob, they will not see it.
+/// This flag skips that behavior, and will always show the self message to the mob.
+#define ALWAYS_SHOW_SELF_MESSAGE (1<<1)
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index e384aa1bcce..9f5388ce291 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -88,25 +88,19 @@
* Returns TRUE if it was able to run the emote, FALSE otherwise.
*/
/datum/emote/proc/run_emote(mob/user, params, type_override, intentional = FALSE)
- . = TRUE
if(!can_run_emote(user, TRUE, intentional))
return FALSE
if(SEND_SIGNAL(user, COMSIG_MOB_PRE_EMOTED, key, params, type_override, intentional) & COMPONENT_CANT_EMOTE)
- return // We don't return FALSE because the error output would be incorrect, provide your own if necessary.
+ return TRUE // We don't return FALSE because the error output would be incorrect, provide your own if necessary.
var/msg = select_message_type(user, message, intentional)
if(params && message_param)
msg = select_param(user, params)
msg = replace_pronoun(user, msg)
-
if(!msg)
- return
+ return TRUE
user.log_message(msg, LOG_EMOTE)
- // SKYRAT EDIT START - Better emotes - Original: var/dchatmsg = "[user] [msg]"
- var/space = should_have_space_before_emote(html_decode(msg)[1]) ? " " : ""
- var/dchatmsg = "[user][space][msg]"
- // SKYRAT EDIT END
var/tmp_sound = get_sound(user)
if(tmp_sound && should_play_sound(user, intentional) && TIMER_COOLDOWN_FINISHED(user, type))
@@ -119,23 +113,96 @@
playsound(user, tmp_sound, sound_volume, vary)
//SKYRAT EDIT CHANGE END
- var/user_turf = get_turf(user)
- if (user.client)
- for(var/mob/ghost as anything in GLOB.dead_mob_list)
- if(!ghost.client || isnewplayer(ghost))
+ var/is_important = emote_type & EMOTE_IMPORTANT
+ var/is_visual = emote_type & EMOTE_VISIBLE
+ var/is_audible = emote_type & EMOTE_AUDIBLE
+
+ // Emote doesn't get printed to chat, runechat only
+ if(emote_type & EMOTE_RUNECHAT)
+ for(var/mob/viewer as anything in viewers(user))
+ if(isnull(viewer.client))
+ continue
+ if(!is_important && viewer != user && (!is_visual || !is_audible))
+ if(is_audible && !viewer.can_hear())
+ continue
+ if(is_visual && viewer.is_blind())
+ continue
+ if(user.runechat_prefs_check(viewer, EMOTE_MESSAGE))
+ if(pref_check_emote(viewer)) // SKYRAT EDIT ADDITION - Pref checked emotes
+ viewer.create_chat_message( // SKYRAT EDIT CHANGE - Indented
+ speaker = user,
+ raw_message = msg,
+ runechat_flags = EMOTE_MESSAGE,
+ )
+ else if(is_important)
+ if(pref_check_emote(viewer)) // SKYRAT EDIT ADDITION - Pref checked emotes
+ to_chat(viewer, "[user] [msg]") // SKYRAT EDIT CHANGE - Indented
+ else if(is_audible && is_visual)
+ if(pref_check_emote(viewer)) // SKYRAT EDIT ADDITION - Pref checked emotes
+ viewer.show_message( // SKYRAT EDIT CHANGE - Indented
+ "[user] [msg]", MSG_AUDIBLE,
+ "You see how [user] [msg]", MSG_VISUAL,
+ )
+ else if(is_audible)
+ if(pref_check_emote(viewer)) // SKYRAT EDIT ADDITION - Pref checked emotes
+ viewer.show_message("[user] [msg]", MSG_AUDIBLE) // SKYRAT EDIT CHANGE - Indented
+ else if(is_visual)
+ if(pref_check_emote(viewer)) // SKYRAT EDIT ADDITION - Pref checked emotes
+ viewer.show_message("[user] [msg]", MSG_VISUAL) // SKYRAT EDIT CHANGE - Indented
+ return TRUE // Early exit so no dchat message
+
+ // The emote has some important information, and should always be shown to the user
+ else if(is_important)
+ for(var/mob/viewer as anything in viewers(user))
+ if(pref_check_emote(viewer)) // SKYRAT EDIT ADDITION - Pref checked emotes
+ to_chat(viewer, "[user] [msg]") // SKYRAT EDIT CHANGE - Indented
+ if(user.runechat_prefs_check(viewer, EMOTE_MESSAGE))
+ viewer.create_chat_message(
+ speaker = user,
+ raw_message = msg,
+ runechat_flags = EMOTE_MESSAGE,
+ )
+ // Emotes has both an audible and visible component
+ // Prioritize audible, and provide a visible message if the user is deaf
+ else if(is_visual && is_audible)
+ user.audible_message(
+ message = msg,
+ deaf_message = "You see how [user] [msg]",
+ self_message = msg,
+ audible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE,
+ pref_to_check = pref_to_check // SKYRAT EDIT ADDITION - Pref checked emotes
+ )
+ // Emote is entirely audible, no visible component
+ else if(is_audible)
+ user.audible_message(
+ message = msg,
+ self_message = msg,
+ audible_message_flags = EMOTE_MESSAGE,
+ pref_to_check = pref_to_check // SKYRAT EDIT ADDITION - Pref checked emotes
+ )
+ // Emote is entirely visible, no audible component
+ else if(is_visual)
+ user.visible_message(
+ message = msg,
+ self_message = msg,
+ visible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE,
+ pref_to_check = pref_to_check // SKYRAT EDIT ADDITION - Pref checked emotes
+ )
+ else
+ CRASH("Emote [type] has no valid emote type set!")
+
+ if(!isnull(user.client))
+ // SKYRAT EDIT START - Better emotes - Original: var/dchatmsg = "[user] [msg]"
+ var/space = should_have_space_before_emote(html_decode(msg)[1]) ? " " : ""
+ var/dchatmsg = "[user][space][msg]"
+ // SKYRAT EDIT END
+ for(var/mob/ghost as anything in GLOB.dead_mob_list - viewers(get_turf(user)))
+ if(isnull(ghost.client) || isnewplayer(ghost))
+ continue
+ if(!(get_chat_toggles(ghost.client) & CHAT_GHOSTSIGHT))
continue
- if(get_chat_toggles(ghost.client) & CHAT_GHOSTSIGHT && !(ghost in viewers(user_turf, null)))
if(pref_check_emote(ghost)) // SKYRAT EDIT ADDITION - Pref checked emotes
ghost.show_message("[FOLLOW_LINK(ghost, user)] [dchatmsg]") // SKYRAT EDIT CHANGE - Indented
- if(emote_type & (EMOTE_AUDIBLE | EMOTE_VISIBLE)) //emote is audible and visible
- user.audible_message(msg, deaf_message = "You see how [user][space][msg]", audible_message_flags = EMOTE_MESSAGE, separation = space, pref_to_check = pref_to_check) // SKYRAT EDIT - Better emotes - ORIGINAL: user.audible_message(msg, deaf_message = "You see how [user] [msg]", audible_message_flags = EMOTE_MESSAGE)
- else if(emote_type & EMOTE_VISIBLE) //emote is only visible
- user.visible_message(msg, visible_message_flags = EMOTE_MESSAGE, separation = space, pref_to_check = pref_to_check) // SKYRAT EDIT - Better emotes - ORIGINAL: user.visible_message(msg, visible_message_flags = EMOTE_MESSAGE)
- if(emote_type & EMOTE_IMPORTANT)
- for(var/mob/living/viewer in viewers())
- if(viewer.is_blind() && !viewer.can_hear())
- if(pref_check_emote(viewer)) // SKYRAT EDIT ADDITION - Pref checked emotes
- to_chat(viewer, msg) // SKYRAT EDIT CHANGE - Indented
// SKYRAT EDIT -- BEGIN -- ADDITION -- AI QOL - RELAY EMOTES OVER HOLOPADS
var/obj/effect/overlay/holo_pad_hologram/hologram = GLOB.hologram_impersonators[user]
@@ -151,6 +218,10 @@
to_chat(viewer, msg)
// SKYRAT EDIT -- END
+ return TRUE
+
+
+
/**
* For handling emote cooldown, return true to allow the emote to happen.
*
diff --git a/code/modules/mob/living/carbon/emote.dm b/code/modules/mob/living/carbon/emote.dm
index 8d1599d0e80..55453b8904d 100644
--- a/code/modules/mob/living/carbon/emote.dm
+++ b/code/modules/mob/living/carbon/emote.dm
@@ -164,7 +164,7 @@
key_third_person = "snaps"
message = "snaps their fingers."
message_param = "snaps their fingers at %t."
- emote_type = EMOTE_AUDIBLE
+ emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE
hands_use_check = TRUE
muzzle_ignore = TRUE
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 412a63c00eb..5881eceebdd 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -72,12 +72,10 @@
key_third_person = "coughs"
message = "coughs!"
message_mime = "acts out an exaggerated cough!"
- emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
+ emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE | EMOTE_RUNECHAT
/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional)
- . = ..()
- if(HAS_TRAIT(user, TRAIT_SOOTHED_THROAT))
- return FALSE
+ return !HAS_TRAIT(user, TRAIT_SOOTHED_THROAT) && ..()
/datum/emote/living/dance
key = "dance"
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 4018207b6fa..911ef49767a 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -261,10 +261,12 @@
* message is output to anyone who can see, e.g. `"The [src] does something!"`
*
* Vars:
+ * * message is the message output to anyone who can see.
* * self_message (optional) is what the src mob sees e.g. "You do something!"
* * blind_message (optional) is what blind people will hear e.g. "You hear something!"
* * vision_distance (optional) define how many tiles away the message can be seen.
- * * ignored_mob (optional) doesn't show any message to a given mob if TRUE.
+ * * ignored_mobs (optional) doesn't show any message to any mob in this list.
+ * * visible_message_flags (optional) is the type of message being sent.
*/
/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE, separation = " ", pref_to_check) // SKYRAT EDIT ADDITION - separation, pref checks
var/turf/T = get_turf(src)
@@ -328,8 +330,22 @@
///Adds the functionality to self_message.
/mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE, separation = " ", pref_to_check) // SKYRAT EDIT ADDITION - Better emotes, pref checks
. = ..()
- if(self_message)
- show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE)
+ if(!self_message)
+ return
+ var/raw_self_message = self_message
+ var/self_runechat = FALSE
+ if(visible_message_flags & EMOTE_MESSAGE)
+ self_message = "[src] [self_message]" // May make more sense as "You do x"
+
+ if(visible_message_flags & ALWAYS_SHOW_SELF_MESSAGE)
+ to_chat(src, self_message)
+ self_runechat = TRUE
+
+ else
+ self_runechat = show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE)
+
+ if(self_runechat && (visible_message_flags & EMOTE_MESSAGE) && runechat_prefs_check(src, visible_message_flags))
+ create_chat_message(src, raw_message = raw_self_message, runechat_flags = visible_message_flags)
/**
* Show a message to all mobs in earshot of this atom
@@ -340,6 +356,8 @@
* * message is the message output to anyone who can hear.
* * deaf_message (optional) is what deaf people will see.
* * hearing_distance (optional) is the range, how many tiles away the message can be heard.
+ * * self_message (optional) is what the src mob hears.
+ * * audible_message_flags (optional) is the type of message being sent.
*/
/atom/proc/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, audible_message_flags = NONE, separation = " ", pref_to_check) // SKYRAT EDIT ADDITION - Better emotes, pref checks
var/list/hearers = get_hearers_in_view(hearing_distance, src)
@@ -382,9 +400,20 @@
*/
/mob/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, audible_message_flags = NONE, separation = " ", pref_to_check) // SKYRAT EDIT ADDITION - Better emotes, pref checks
. = ..()
- if(self_message)
- show_message(self_message, MSG_AUDIBLE, deaf_message, MSG_VISUAL)
+ if(!self_message)
+ return
+ var/raw_self_message = self_message
+ var/self_runechat = FALSE
+ if(audible_message_flags & EMOTE_MESSAGE)
+ self_message = "[src] [self_message]"
+ if(audible_message_flags & ALWAYS_SHOW_SELF_MESSAGE)
+ to_chat(src, self_message)
+ self_runechat = TRUE
+ else
+ self_runechat = show_message(self_message, MSG_AUDIBLE, deaf_message, MSG_VISUAL)
+ if(self_runechat && (audible_message_flags & EMOTE_MESSAGE) && runechat_prefs_check(src, audible_message_flags))
+ create_chat_message(src, raw_message = raw_self_message, runechat_flags = audible_message_flags)
///Returns the client runechat visible messages preference according to the message type.
/atom/proc/runechat_prefs_check(mob/target, visible_message_flags = NONE)