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)