diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 114979e96be..7513ab3c006 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -442,3 +442,5 @@
#define FAKE_INVIS_ALPHA_THRESHOLD 127 // If something's alpha var is at or below this number, certain things will pretend it is invisible.
#define DEATHGASP_NO_MESSAGE "no message"
+
+#define RESIST_COOLDOWN 2 SECONDS
diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm
index 952e317a272..5118e90ae94 100644
--- a/code/modules/client/preference_setup/general/03_body.dm
+++ b/code/modules/client/preference_setup/general/03_body.dm
@@ -394,10 +394,6 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.body_descriptors[entry] = descriptor.default_value // Species datums have initial default value.
else
pref.body_descriptors[entry] = CLAMP(last_descriptors[entry], 1, LAZYLEN(descriptor.standalone_value_descriptors))
-
- character.update_emotes()
-
- return
/datum/category_item/player_setup_item/general/body/content(var/mob/user)
. = list()
diff --git a/code/modules/emotes/definitions/_mob.dm b/code/modules/emotes/definitions/_mob.dm
index 46a2bf94da3..8651c933b1d 100644
--- a/code/modules/emotes/definitions/_mob.dm
+++ b/code/modules/emotes/definitions/_mob.dm
@@ -24,19 +24,3 @@ var/list/_default_mob_emotes = list(
/decl/emote/audible/moan,
/decl/emote/audible/gnarl,
)
-
-/mob
- var/list/usable_emotes
- var/nextemote = 1 //VOREStation Add
-
-/mob/proc/update_emotes(var/skip_sort)
- usable_emotes = list()
- for(var/emote in get_default_emotes())
- var/decl/emote/emote_datum = decls_repository.get_decl(emote)
- if(emote_datum.check_user(src))
- usable_emotes[emote_datum.key] = emote_datum
- if(!skip_sort)
- usable_emotes = sortAssoc(usable_emotes)
-
-/mob/proc/get_default_emotes()
- return global._default_mob_emotes
diff --git a/code/modules/emotes/definitions/_species.dm b/code/modules/emotes/definitions/_species.dm
index ff15df2fae5..3fb1ccd65de 100644
--- a/code/modules/emotes/definitions/_species.dm
+++ b/code/modules/emotes/definitions/_species.dm
@@ -1,11 +1,7 @@
/datum/species
var/list/default_emotes = list()
-/mob/living/carbon/update_emotes(var/skip_sort)
- . = ..(skip_sort = TRUE)
- if(species)
- for(var/emote in species.default_emotes)
- var/decl/emote/emote_datum = decls_repository.get_decl(emote)
- if(emote_datum.check_user(src))
- usable_emotes[emote_datum.key] = emote_datum
- usable_emotes = sortAssoc(usable_emotes)
+/mob/living/carbon/get_available_emotes()
+ . = ..()
+ if(length(species?.default_emotes))
+ . |= species.default_emotes
diff --git a/code/modules/emotes/definitions/exertion.dm b/code/modules/emotes/definitions/exertion.dm
index ac0061cca32..97404cef64d 100644
--- a/code/modules/emotes/definitions/exertion.dm
+++ b/code/modules/emotes/definitions/exertion.dm
@@ -4,7 +4,7 @@
emote_message_1p = "You are sweating heavily."
emote_message_3p = "is sweating heavily."
-/decl/emote/exertion/biological/check_user(mob/living/user)
+/decl/emote/exertion/biological/mob_can_use(mob/living/user)
if(istype(user) && !user.isSynthetic())
return ..()
return FALSE
@@ -29,7 +29,7 @@
emote_message_1p = "You overstress your actuators."
emote_message_3p = "USER's actuators whine with strain."
-/decl/emote/exertion/synthetic/check_user(mob/living/user)
+/decl/emote/exertion/synthetic/mob_can_use(mob/living/user)
if(istype(user) && user.isSynthetic())
return ..()
return FALSE
diff --git a/code/modules/emotes/definitions/human.dm b/code/modules/emotes/definitions/human.dm
index 982e472c5f2..a35d4f1d67c 100644
--- a/code/modules/emotes/definitions/human.dm
+++ b/code/modules/emotes/definitions/human.dm
@@ -1,11 +1,5 @@
-/decl/emote/human
- key = "vomit"
-
-/decl/emote/human/check_user(var/mob/living/carbon/human/user)
- return (istype(user))//VOREStation Edit - What does a mouth have to do with wagging?? && user.check_has_mouth() && !user.isSynthetic())
-
-/decl/emote/human/do_emote(var/mob/living/carbon/human/user)
- user.vomit()
+/decl/emote/human/mob_can_use(var/mob/living/carbon/human/user)
+ return ..() && (istype(user))//VOREStation Edit - What does a mouth have to do with wagging?? && user.check_has_mouth() && !user.isSynthetic())
/decl/emote/human/deathgasp
key = "deathgasp"
diff --git a/code/modules/emotes/definitions/slimes.dm b/code/modules/emotes/definitions/slimes.dm
index 877422825ba..bde5b580aa4 100644
--- a/code/modules/emotes/definitions/slimes.dm
+++ b/code/modules/emotes/definitions/slimes.dm
@@ -8,8 +8,8 @@
user.mood = mood
user.update_icon()
-/decl/emote/slime/check_user(var/atom/user)
- return isslime(user)
+/decl/emote/slime/mob_can_use(var/atom/user)
+ return ..() && isslime(user)
/decl/emote/slime/pout
key = "pout"
diff --git a/code/modules/emotes/definitions/synthetics.dm b/code/modules/emotes/definitions/synthetics.dm
index 2e31a07f8fd..a4508bc51f7 100644
--- a/code/modules/emotes/definitions/synthetics.dm
+++ b/code/modules/emotes/definitions/synthetics.dm
@@ -3,7 +3,7 @@
emote_message_3p = "beeps."
emote_sound = 'sound/machines/twobeep.ogg'
-/decl/emote/audible/synth/check_user(var/mob/living/user)
+/decl/emote/audible/synth/mob_can_use(var/mob/living/user)
if(istype(user) && user.isSynthetic())
return ..()
return FALSE
@@ -34,8 +34,8 @@
emote_message_3p_target = "shows TARGET USER_THEIR legal authorization barcode."
emote_sound = 'sound/voice/biamthelaw.ogg'
-/decl/emote/audible/synth/security/check_user(var/mob/living/silicon/robot/user)
- return (istype(user) && (istype(user.module, /obj/item/weapon/robot_module/robot/security) || istype(user.module, /obj/item/weapon/robot_module/robot/knine))) //VOREStation Add - knine module
+/decl/emote/audible/synth/security/mob_can_use(var/mob/living/silicon/robot/user)
+ return ..() && (istype(user) && (istype(user.module, /obj/item/weapon/robot_module/robot/security) || istype(user.module, /obj/item/weapon/robot_module/robot/knine))) //VOREStation Add - knine module
/decl/emote/audible/synth/security/halt
key = "halt"
diff --git a/code/modules/emotes/definitions/visible.dm b/code/modules/emotes/definitions/visible.dm
index 986839fff1a..fa19ac257a3 100644
--- a/code/modules/emotes/definitions/visible.dm
+++ b/code/modules/emotes/definitions/visible.dm
@@ -237,9 +237,6 @@
emote_message_3p = "signals."
check_restraints = TRUE
-/decl/emote/visible/signal/check_user(atom/user)
- return ismob(user)
-
/decl/emote/visible/signal/get_emote_message_3p(var/mob/living/user, var/atom/target, var/extra_params)
if(istype(user) && (!user.get_active_hand() || !user.get_inactive_hand()))
var/t1 = round(text2num(extra_params))
diff --git a/code/modules/emotes/definitions/visible_animated.dm b/code/modules/emotes/definitions/visible_animated.dm
index c66fa789c17..142c3e4c0c2 100644
--- a/code/modules/emotes/definitions/visible_animated.dm
+++ b/code/modules/emotes/definitions/visible_animated.dm
@@ -2,6 +2,7 @@
key = "spin"
check_restraints = TRUE
emote_message_3p = "spins!"
+ emote_delay = 2 SECONDS
/decl/emote/visible/spin/do_extra(mob/user)
if(istype(user))
@@ -11,6 +12,7 @@
key = "sidestep"
check_restraints = TRUE
emote_message_3p = "steps rhythmically and moves side to side."
+ emote_delay = 1.2 SECONDS
/decl/emote/visible/sidestep/do_extra(mob/user)
if(istype(user))
@@ -24,6 +26,7 @@
emote_message_1p = "You do a flip!"
emote_message_3p = "does a flip!"
emote_sound = 'sound/effects/bodyfall4.ogg'
+ emote_delay = 1.2 SECONDS
/decl/emote/visible/flip/do_extra(mob/user)
. = ..()
@@ -39,6 +42,7 @@
key = "floorspin"
emote_message_1p = "You spin around on the floor!"
emote_message_3p = "spins around on the floor!"
+ emote_delay = 1.2 SECONDS
var/static/list/spin_dirs = list(
NORTH,
SOUTH,
diff --git a/code/modules/emotes/emote_define.dm b/code/modules/emotes/emote_define.dm
index 845a5202d31..6b50b09dde1 100644
--- a/code/modules/emotes/emote_define.dm
+++ b/code/modules/emotes/emote_define.dm
@@ -4,6 +4,13 @@
// gender-appropriate version of the same.
// - Impaired messages do not do any substitutions.
+var/global/list/emotes_by_key
+
+/proc/get_emote_by_key(var/key)
+ if(!global.emotes_by_key)
+ decls_repository.get_decls_of_type(/decl/emote) // emotes_by_key will be updated in emote Initialize()
+ return global.emotes_by_key[key]
+
/decl/emote
var/key // Command to use emote ie. '*[key]'
var/emote_message_1p // First person message ('You do a flip!')
@@ -28,6 +35,7 @@
var/list/emote_sound_synthetic // As above, but used when check_synthetic() is true.
var/emote_volume = 50 // Volume of sound to play.
var/emote_volume_synthetic = 50 // As above, but used when check_synthetic() is true.
+ var/emote_delay = 0 // Time in ds that this emote will block further emote use (spam prevention).
var/message_type = VISIBLE_MESSAGE // Audible/visual flag
var/check_restraints // Can this emote be used while restrained?
@@ -35,6 +43,11 @@
var/conscious = TRUE // Do we need to be awake to emote this?
var/emote_range = 0 // If >0, restricts emote visibility to viewers within range.
+/decl/emote/Initialize()
+ . = ..()
+ if(key)
+ LAZYSET(global.emotes_by_key, key, src)
+
/decl/emote/proc/get_emote_message_1p(var/atom/user, var/atom/target, var/extra_params)
if(target)
if(emote_message_synthetic_1p_target && check_synthetic(user))
@@ -162,8 +175,8 @@
if(sound_to_play)
playsound(user.loc, sound_to_play, use_sound["vol"], 0, preference = /datum/client_preference/emote_noises) //VOREStation Add - Preference
-/decl/emote/proc/check_user(var/atom/user)
- return TRUE
+/decl/emote/proc/mob_can_use(var/mob/user)
+ return istype(user) && user.stat != DEAD && (type in user.get_available_emotes())
/decl/emote/proc/can_target()
return (emote_message_1p_target || emote_message_3p_target)
diff --git a/code/modules/emotes/emote_mob.dm b/code/modules/emotes/emote_mob.dm
index 546ee4c7aec..cbc53019d86 100644
--- a/code/modules/emotes/emote_mob.dm
+++ b/code/modules/emotes/emote_mob.dm
@@ -1,11 +1,15 @@
+/mob
+ var/next_emote
+ var/next_emote_refresh
+ var/last_emote_summary
+
+/mob/proc/get_available_emotes()
+ return global._default_mob_emotes
+
/mob/proc/can_emote(var/emote_type)
- //VOREStation Add
- if(src.nextemote >= world.time)
- return FALSE
- src.nextemote = world.time + 12
- //VOREStation Add End
return (stat == CONSCIOUS)
+#define EMOTE_REFRESH_SPAM_COOLDOWN (5 SECONDS)
/mob/living/can_emote(var/emote_type)
return (..() && !(silent && emote_type == AUDIBLE_MESSAGE))
@@ -20,8 +24,20 @@
to_chat(src, "You cannot send IC messages (muted).")
return
+ if(world.time < next_emote)
+ to_chat(src, SPAN_WARNING("You cannot use another emote yet."))
+ return
+
if(act == "help")
- to_chat(src,"Usable emotes: [english_list(usable_emotes)].")
+ if(world.time >= next_emote_refresh)
+ var/list/usable_emotes = list()
+ next_emote_refresh = world.time + EMOTE_REFRESH_SPAM_COOLDOWN
+ for(var/emote in get_available_emotes())
+ var/decl/emote/emote_datum = decls_repository.get_decl(emote)
+ if(emote_datum.mob_can_use(src))
+ usable_emotes[emote_datum.key] = emote_datum
+ last_emote_summary = english_list(sortAssoc(usable_emotes))
+ to_chat(src,"Usable emotes: [last_emote_summary].")
return
if(!can_emote(m_type))
@@ -57,24 +73,30 @@
return nme(message)
//VOREStation Add End
- var/decl/emote/use_emote = usable_emotes[act]
- if(!use_emote)
+ var/decl/emote/use_emote = get_emote_by_key(act)
+ if(!istype(use_emote))
to_chat(src, SPAN_WARNING("Unknown emote '[act]'. Type say *help for a list of usable emotes."))
return
+ if(!use_emote.mob_can_use(src))
+ to_chat(src, SPAN_WARNING("You cannot use the emote '[act]'. Type say *help for a list of usable emotes."))
+ return
+
if(m_type != use_emote.message_type && use_emote.conscious && stat != CONSCIOUS)
return
if(use_emote.message_type == AUDIBLE_MESSAGE && is_muzzled())
audible_message("\The [src] [use_emote.emote_message_muffled || "makes a muffled sound."]")
return
- else
- use_emote.do_emote(src, message)
+ next_emote = world.time + use_emote.emote_delay
+ use_emote.do_emote(src, message)
for (var/obj/item/weapon/implant/I in src)
if (I.implanted)
I.trigger(act, src)
+#undef EMOTE_REFRESH_SPAM_COOLDOWN
+
/mob/proc/format_emote(var/emoter = null, var/message = null)
var/pretext
var/subtext
diff --git a/code/modules/mob/living/carbon/alien/diona/diona.dm b/code/modules/mob/living/carbon/alien/diona/diona.dm
index 739c3b09c6b..690fdb3325c 100644
--- a/code/modules/mob/living/carbon/alien/diona/diona.dm
+++ b/code/modules/mob/living/carbon/alien/diona/diona.dm
@@ -46,7 +46,7 @@ var/list/_nymph_default_emotes = list(
holder_type = /obj/item/weapon/holder/diona
var/obj/item/hat
-/mob/living/carbon/alien/diona/get_default_emotes()
+/mob/living/carbon/alien/diona/get_available_emotes()
return global._nymph_default_emotes
/mob/living/carbon/alien/diona/Initialize()
diff --git a/code/modules/mob/living/carbon/alien/emote.dm b/code/modules/mob/living/carbon/alien/emote.dm
index b0517e7a952..cb7ab9b7b0c 100644
--- a/code/modules/mob/living/carbon/alien/emote.dm
+++ b/code/modules/mob/living/carbon/alien/emote.dm
@@ -27,5 +27,5 @@ var/list/_alien_default_emotes = list(
/decl/emote/audible/chirp
)
-/mob/living/carbon/alien/get_default_emotes()
+/mob/living/carbon/alien/get_available_emotes()
. = global._alien_default_emotes
diff --git a/code/modules/mob/living/carbon/brain/emote.dm b/code/modules/mob/living/carbon/brain/emote.dm
index cb6ed6a1b7b..5fb8159b1f7 100644
--- a/code/modules/mob/living/carbon/brain/emote.dm
+++ b/code/modules/mob/living/carbon/brain/emote.dm
@@ -13,5 +13,5 @@ var/list/_brain_default_emotes = list(
/mob/living/carbon/brain/can_emote()
return (istype(container, /obj/item/device/mmi) && ..())
-/mob/living/carbon/brain/get_default_emotes()
+/mob/living/carbon/brain/get_available_emotes()
return global._brain_default_emotes
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index aba6241d652..fc424c48066 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -33,7 +33,6 @@ var/list/_human_default_emotes = list(
/decl/emote/audible/grunt,
/decl/emote/audible/slap,
/decl/emote/audible/crack,
- /decl/emote/human,
/decl/emote/human/deathgasp,
/decl/emote/audible/giggle,
/decl/emote/audible/scream,
@@ -134,8 +133,10 @@ var/list/_human_default_emotes = list(
//VOREStation Add End
)
-/mob/living/carbon/human/get_default_emotes()
- return global._human_default_emotes
+/mob/living/carbon/human/get_available_emotes()
+ . = global._human_default_emotes
+ if(length(species?.default_emotes))
+ . |= species.default_emotes
/mob/living/carbon/human/verb/pose()
set name = "Set Pose"
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 1cb3adaa28d..1e4a40eedbd 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1163,9 +1163,6 @@
//A slew of bits that may be affected by our species change
regenerate_icons()
- // Update our available emote list.
- update_emotes()
-
if(species)
//if(mind) //VOREStation Removal
//apply_traits() //VOREStation Removal
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 885de104ccf..2fd4b34acd6 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -625,8 +625,8 @@
set name = "Resist"
set category = "IC"
- if(!incapacitated(INCAPACITATION_KNOCKOUT) && checkClickCooldown())
- setClickCooldown(20)
+ if(!incapacitated(INCAPACITATION_KNOCKOUT) && (last_resist_time + RESIST_COOLDOWN < world.time))
+ last_resist_time = world.time
resist_grab()
if(!weakened)
process_resist()
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 6a2b0bdf71c..c5e7a857b84 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -80,4 +80,4 @@
var/flying = 0 // Allows flight
var/inventory_panel_type = /datum/inventory_panel
var/datum/inventory_panel/inventory_panel
-
+ var/last_resist_time = 0 // world.time of the most recent resist that wasn't on cooldown.
diff --git a/code/modules/mob/living/silicon/emote.dm b/code/modules/mob/living/silicon/emote.dm
index 6aa6ae2150f..220458c5229 100644
--- a/code/modules/mob/living/silicon/emote.dm
+++ b/code/modules/mob/living/silicon/emote.dm
@@ -9,5 +9,5 @@ var/list/_silicon_default_emotes = list(
/decl/emote/audible/synth/security/halt
)
-/mob/living/silicon/get_default_emotes()
+/mob/living/silicon/get_available_emotes()
return global._silicon_default_emotes
diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm
index 2b83568e7bf..17d6a65983c 100644
--- a/code/modules/mob/living/silicon/robot/emote.dm
+++ b/code/modules/mob/living/silicon/robot/emote.dm
@@ -29,5 +29,5 @@ var/list/_robot_default_emotes = list(
//VOREStation Add End
)
-/mob/living/silicon/robot/get_default_emotes()
+/mob/living/silicon/robot/get_available_emotes()
return global._robot_default_emotes
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm b/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm
index c48f94bf277..722ac3ffcdf 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm
@@ -57,7 +57,7 @@ var/list/_cat_default_emotes = list(
update_icon()
return ..()
-/mob/living/simple_mob/animal/passive/cat/get_default_emotes()
+/mob/living/simple_mob/animal/passive/cat/get_available_emotes()
return global._cat_default_emotes
/mob/living/simple_mob/animal/passive/cat/handle_special()
diff --git a/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm b/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
index f8d47a4b2dc..ade53adebc6 100644
--- a/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
@@ -80,7 +80,7 @@ var/list/_slime_default_emotes = list(
can_enter_vent_with = list(/obj/item/clothing/head)
-/mob/living/simple_mob/slime/get_default_emotes()
+/mob/living/simple_mob/slime/get_available_emotes()
return global._slime_default_emotes
/datum/say_list/slime
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index c41691a8575..7c6163855ee 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -42,7 +42,6 @@
lastarea = get_area(src)
hook_vr("mob_new",list(src)) //VOREStation Code
update_transform() // Some mobs may start bigger or smaller than normal.
- update_emotes()
return ..()
/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
diff --git a/code/modules/organs/subtypes/standard.dm b/code/modules/organs/subtypes/standard.dm
index 0b08d8a572c..7567aad0cab 100644
--- a/code/modules/organs/subtypes/standard.dm
+++ b/code/modules/organs/subtypes/standard.dm
@@ -38,7 +38,6 @@
if(!R)
log_error("A torso was robotize() but has no model that can be found: [model]. May affect FBPs.")
owner.synthetic = R
- owner.update_emotes()
return FALSE