Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Port] Emote Update #11617

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions beestation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -2585,6 +2585,7 @@
#include "code\modules\elevator\elevator_interface.dm"
#include "code\modules\elevator\elevator_segment.dm"
#include "code\modules\emoji\emoji_parse.dm"
#include "code\modules\emote_panel\emote_panel.dm"
#include "code\modules\error_handler\error_handler.dm"
#include "code\modules\error_handler\error_viewer.dm"
#include "code\modules\events\_event.dm"
Expand Down
18 changes: 15 additions & 3 deletions code/__DEFINES/say.dm
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,23 @@
//Used in visible_message_flags, audible_message_flags and message_mods
#define CHATMESSAGE_EMOTE "emotemessage"

/// 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 "showselfmessage"

///How far away blind people can see visible messages from
#define BLIND_TEXT_DIST 2

// Emote flags

// Bitflags for emotes, used in var/emote_type of the emote datum
/// Is the emote audible
#define EMOTE_AUDIBLE (1<<0)
#define EMOTE_ANIMATED (1<<1)
/// Is the emote visible
#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)
// Animated emote bitflag
#define EMOTE_ANIMATED (1<<4)

28 changes: 21 additions & 7 deletions code/__DEFINES/species.dm
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,16 @@
// Sounds used by species for "nasal/lungs" emotes - the DEFAULT being used mainly by humans, lizards, and ethereals becase biology idk

#define SPECIES_DEFAULT_COUGH_SOUND(user) user.gender == FEMALE ? pick(\
'sound/emotes/female/female_cough_1.ogg',\
'sound/emotes/female/female_cough_2.ogg',\
'sound/emotes/female/female_cough_3.ogg') : pick(\
'sound/emotes/male/male_cough_1.ogg',\
'sound/emotes/male/male_cough_2.ogg',\
'sound/emotes/male/male_cough_3.ogg')
'sound/emotes/female/female_cough_1.ogg',\
'sound/emotes/female/female_cough_2.ogg',\
'sound/emotes/female/female_cough_3.ogg',\
'sound/emotes/female/female_cough_4.ogg',\
'sound/emotes/female/female_cough_5.ogg',\
'sound/emotes/female/female_cough_6.ogg',\
'sound/emotes/female/female_cough_7.ogg') : pick(\
'sound/emotes/male/male_cough_1.ogg',\
'sound/emotes/male/male_cough_2.ogg',\
'sound/emotes/male/male_cough_3.ogg')
#define SPECIES_DEFAULT_GASP_SOUND(user) user.gender == FEMALE ? pick(\
'sound/emotes/female/gasp_f1.ogg',\
'sound/emotes/female/gasp_f2.ogg',\
Expand All @@ -132,5 +136,15 @@
'sound/emotes/male/gasp_m5.ogg',\
'sound/emotes/male/gasp_m6.ogg')
#define SPECIES_DEFAULT_SIGH_SOUND(user) user.gender == FEMALE ? 'sound/emotes/female/female_sigh.ogg' : 'sound/emotes/male/male_sigh.ogg'
#define SPECIES_DEFAULT_SNEEZE_SOUND(user) user.gender == FEMALE ? 'sound/emotes/female/female_sneeze.ogg' : 'sound/emotes/male/male_sneeze.ogg'
#define SPECIES_DEFAULT_SNEEZE_SOUND(user) user.gender == FEMALE ? pick(\
'sound/emotes/female/female_sneeze1.ogg',\
'sound/emotes/female/female_sneeze2.ogg') : pick(\
'sound/emotes/male/male_sneeze1.ogg',\
'sound/emotes/male/male_sneeze2.ogg')
#define SPECIES_DEFAULT_SNIFF_SOUND(user) user.gender == FEMALE ? 'sound/emotes/female/female_sniff.ogg' : 'sound/emotes/male/male_sniff.ogg'
#define SPECIES_DEFAULT_GIGGLE_SOUND(user) user.gender == FEMALE ? pick(\
'sound/emotes/female/female_giggle_1.ogg',\
'sound/emotes/female/female_giggle_2.ogg') : pick(\
'sound/emotes/male/male_giggle_1.ogg',\
'sound/emotes/male/male_giggle_2.ogg',\
'sound/emotes/male/male_giggle_3.ogg')
7 changes: 7 additions & 0 deletions code/_globalvars/bitfields.dm
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,10 @@ DEFINE_BITFIELD(mecha_flags, list(
"IS_ENCLOSED" = IS_ENCLOSED,
"HAS_LIGHTS" = HAS_LIGHTS,
))

DEFINE_BITFIELD(emote_flags, list(
"EMOTE_AUDIBLE" = EMOTE_AUDIBLE,
"EMOTE_VISIBLE" = EMOTE_VISIBLE,
"EMOTE_IMPORTANT" = EMOTE_IMPORTANT,
"EMOTE_ANIMATED" = EMOTE_ANIMATED,
))
94 changes: 79 additions & 15 deletions code/datums/emotes.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/datum/emote
var/key = "" //What calls the emote
var/key_third_person = "" //This will also call the emote
var/name = "" // Needed for more user-friendly emote names, so emotes with keys like "aflap" will show as "flap angry". Defaulted to key.
var/message = "" //Message displayed when emote is used
var/message_mime = "" //Message displayed if the user is a mime
var/message_alien = "" //Message displayed if the user is a grown alien
Expand All @@ -12,8 +13,8 @@
var/message_insect = "" //Message to display if the user is a moth, apid or flyperson
var/message_simple = "" //Message to display if the user is a simple_animal
var/message_param = "" //Message to display if a param was given
/// Emote flags (EMOTE_AUDIBLE and EMOTE_ANIMATED)
var/emote_type = 0
/// Whether the emote is visible and/or audible bitflag
var/emote_type = NONE
/// Checks if the mob can use its hands before performing the emote.
var/hands_use_check = FALSE
var/muzzle_ignore = FALSE //Will only work if the emote is EMOTE_AUDIBLE
Expand Down Expand Up @@ -57,7 +58,11 @@
mob_type_blacklist_typecache = typecacheof(mob_type_blacklist_typecache)
mob_type_ignore_stat_typecache = typecacheof(mob_type_ignore_stat_typecache)

if(!name)
name = key

/datum/emote/proc/run_emote(mob/user, params, type_override, intentional = FALSE)
Copy link
Contributor

@Tsar-Salat Tsar-Salat Nov 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I can see all of the children of this explicitly call parent except for the custom emote.

I would make the parent require calls to parent, and just exclude /datum/emote/living/custom/run_emote() with SHOULD_CALL_PARENT(FALSE)

This will prevent future screw ups by first time coders I'm sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emote/living/custom/run_emote also calls the parent proc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then the parent proc should be SHOULD_CALL_PARENT(TRUE)

SHOULD_CALL_PARENT(TRUE)
if(!can_run_emote(user, TRUE, intentional))
return FALSE

Expand Down Expand Up @@ -88,22 +93,81 @@
var/space = should_have_space_before_emote(html_decode(msg)[1]) ? " " : ""
msg = punctuate(msg)

var/dchatmsg = "<b>[user]</b>[space][msg]"
var/is_important = emote_type & EMOTE_IMPORTANT
var/is_visual = emote_type & EMOTE_VISIBLE
var/is_audible = emote_type & EMOTE_AUDIBLE

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.prefs?.read_player_preference(/datum/preference/toggle/chat_ghostsight) && !(M in viewers(T, null)))
if(user.mind || M.client.prefs?.read_player_preference(/datum/preference/toggle/chat_followghostmindless))
M.show_message("[FOLLOW_LINK(M, user)] [dchatmsg]")
else
M.show_message("[dchatmsg]")
// 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, CHATMESSAGE_EMOTE))
create_chat_message(
speaker = user,
raw_message = msg,
message_mods = list(CHATMESSAGE_EMOTE = TRUE),
)
else if(is_important)
to_chat(viewer, "<span class='emote'><b>[user]</b> [msg]</span>")
else if(is_audible && is_visual)
viewer.show_message(
"<span class='emote'><b>[user]</b> [msg]</span>", MSG_AUDIBLE,
"<span class='emote'>You see how <b>[user]</b> [msg]</span>", MSG_VISUAL,
)
else if(is_audible)
viewer.show_message("<span class='emote'><b>[user]</b> [msg]</span>", MSG_AUDIBLE)
else if(is_visual)
viewer.show_message("<span class='emote'><b>[user]</b> [msg]</span>", MSG_VISUAL)
return TRUE // Early exit so no dchat message

if(emote_type & EMOTE_AUDIBLE)
user.audible_message(msg, audible_message_flags = list(CHATMESSAGE_EMOTE = TRUE), separation = space)
// 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))
to_chat(viewer, "<span class='emote'><b>[user]</b> [msg]</span>")
if(user.runechat_prefs_check(viewer, list(CHATMESSAGE_EMOTE = TRUE)))
create_chat_message(user, null, list(viewer), msg, null, list(CHATMESSAGE_EMOTE = TRUE))
// 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 = "<span class='emote'>You see how <b>[user]</b> [msg]</span>",
self_message = msg,
audible_message_flags = list(CHATMESSAGE_EMOTE = TRUE, ALWAYS_SHOW_SELF_MESSAGE = TRUE),
separation = space
)
// Emote is entirely audible, no visible component
else if(is_audible)
user.audible_message(
message = msg,
self_message = msg,
audible_message_flags = list(CHATMESSAGE_EMOTE = TRUE),
separation = space
)
// Emote is entirely visible, no audible component
else if(is_visual)
user.visible_message(
message = msg,
self_message = msg,
visible_message_flags = list(CHATMESSAGE_EMOTE = TRUE, ALWAYS_SHOW_SELF_MESSAGE = TRUE),
)
else
user.visible_message(msg, visible_message_flags = list(CHATMESSAGE_EMOTE = TRUE), separation = space)
CRASH("Emote [type] has no valid emote type set!")

if(!isnull(user.client))
var/dchatmsg = "<b>[user]</b> [msg]"
for(var/mob/ghost as anything in GLOB.dead_mob_list - viewers(get_turf(user)))
if(isnull(ghost.client) || isnewplayer(ghost))
continue
if(!ghost?.client.prefs?.read_player_preference(/datum/preference/toggle/chat_ghostsight))
continue
to_chat(ghost, "<span class='emote'>[FOLLOW_LINK(ghost, user)] [dchatmsg]</span>")
return TRUE

/datum/emote/proc/get_sound(mob/living/user)
Expand Down
40 changes: 34 additions & 6 deletions code/modules/asset_cache/asset_list.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
/// Whether or not this asset can be cached across rounds of the same commit under the `CACHE_ASSETS` config.
/// This is not a *guarantee* the asset will be cached. Not all asset subtypes respect this field, and the
/// config can, of course, be disabled.
/// Disable this if your asset can change between rounds on the same exact version of the code.
var/cross_round_cachable = FALSE

/// Whether or not this asset should be loaded in the "early assets" SS
Expand Down Expand Up @@ -146,6 +147,7 @@ GLOBAL_LIST_EMPTY(asset_datums)

/datum/asset/spritesheet
_abstract = /datum/asset/spritesheet
cross_round_cachable = TRUE
var/name
/// List of arguments to pass into queuedInsert
/// Exists so we can queue icon insertion, mostly for stuff like preferences
Expand All @@ -158,6 +160,9 @@ GLOBAL_LIST_EMPTY(asset_datums)
/// If this asset should be fully loaded on new
/// Defaults to false so we can process this stuff nicely
var/load_immediately = FALSE
VAR_PRIVATE
// Kept in state so that the result is the same, even when the files are created, for this run
should_refresh = null

/datum/asset/spritesheet/proc/should_load_immediately()
#ifdef DO_NOT_DEFER_ASSETS
Expand All @@ -170,12 +175,9 @@ GLOBAL_LIST_EMPTY(asset_datums)
if (..())
return TRUE

// Static so that the result is the same, even when the files are created, for this run
var/static/should_refresh = null

if (isnull(should_refresh))
// `fexists` seems to always fail on static-time
should_refresh = !fexists("[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].css")
should_refresh = !fexists(css_cache_filename()) || !fexists(data_cache_filename())

return should_refresh

Expand Down Expand Up @@ -329,8 +331,17 @@ GLOBAL_LIST_EMPTY(asset_datums)

return out.Join("\n")

/datum/asset/spritesheet/proc/css_cache_filename()
return "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].css"

/datum/asset/spritesheet/proc/data_cache_filename()
return "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].json"

/datum/asset/spritesheet/proc/read_from_cache()
var/replaced_css = rustg_file_read("[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].css")
return read_css_from_cache() && read_data_from_cache()

/datum/asset/spritesheet/proc/read_css_from_cache()
var/replaced_css = file2text(css_cache_filename())

var/regex/find_background_urls = regex(@"background:url\('%(.+?)%'\)", "g")
while (find_background_urls.Find(replaced_css))
Expand All @@ -352,6 +363,14 @@ GLOBAL_LIST_EMPTY(asset_datums)

return TRUE

/datum/asset/spritesheet/proc/read_data_from_cache()
var/json = json_decode(file2text(data_cache_filename()))

if (islist(json["sprites"]))
sprites = json["sprites"]

return TRUE

/datum/asset/spritesheet/proc/send_from_cache(client/client)
if (isnull(cached_spritesheets_needed))
stack_trace("cached_spritesheets_needed was null when sending assets from [type] from cache")
Expand All @@ -367,6 +386,10 @@ GLOBAL_LIST_EMPTY(asset_datums)
return SSassets.transport.get_asset_url(asset)

/datum/asset/spritesheet/proc/write_to_cache()
write_css_to_cache()
write_data_to_cache()

/datum/asset/spritesheet/proc/write_css_to_cache()
for (var/size_id in sizes)
var/datum/asset_cache_item/temp = SSassets.cache["[name]_[size_id].png"]
fcopy(temp.resource, "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name]_[size_id].png")
Expand All @@ -375,7 +398,12 @@ GLOBAL_LIST_EMPTY(asset_datums)
var/mock_css = generate_css()
generating_cache = FALSE

rustg_file_write(mock_css, "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].css")
rustg_file_write(mock_css, css_cache_filename())

/datum/asset/spritesheet/proc/write_data_to_cache()
rustg_file_write(json_encode(list(
"sprites" = sprites,
)), data_cache_filename())

/datum/asset/spritesheet/proc/get_cached_url_mappings()
var/list/mappings = list()
Expand Down
1 change: 0 additions & 1 deletion code/modules/client/preferences/middleware/antags.dm
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@
/datum/asset/spritesheet/antagonists
name = "antagonists"
early = TRUE
cross_round_cachable = TRUE

/datum/asset/spritesheet/antagonists/create_spritesheets()
var/list/generated_icons = list()
Expand Down
1 change: 0 additions & 1 deletion code/modules/client/preferences/middleware/species.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
/datum/asset/spritesheet/species
name = "species"
early = TRUE
cross_round_cachable = TRUE

/datum/asset/spritesheet/species/create_spritesheets()
var/list/to_insert = list()
Expand Down
1 change: 1 addition & 0 deletions code/modules/clothing/masks/_masks.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
var/adjusted_flags = null
var/voice_change = FALSE //Used to mask/change the user's voice, only specific masks can set this to TRUE
var/obj/item/organ/tongue/chosen_tongue = null
var/unique_death /// The unique sound effect of dying while wearing this

/obj/item/clothing/mask/attack_self(mob/user)
if(CHECK_BITFIELD(clothing_flags, VOICEBOX_TOGGLABLE))
Expand Down
1 change: 1 addition & 0 deletions code/modules/clothing/masks/hailer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
visor_flags_inv = HIDEFACE | HIDESNOUT
flags_cover = MASKCOVERSMOUTH | MASKCOVERSEYES
visor_flags_cover = MASKCOVERSMOUTH | MASKCOVERSEYES
unique_death = 'sound/voice/sec_death.ogg'
var/aggressiveness = 2
var/cooldown_special
var/recent_uses = 0
Expand Down
Loading
Loading