Skip to content

Commit

Permalink
Ports emote keybindings (#11991)
Browse files Browse the repository at this point in the history
* base cooldown

tgstation/tgstation#59479

* no walls

* share between audible emotes

tgstation/tgstation#86846

* general & specific

tgstation/tgstation#87210

* audio check proc

tgstation/tgstation#62206 tgstation/tgstation#68954

* mindless, naturally

* brings emote jumps in line with f hotkey

* make it a little less punishing

* tg keybinding commit 1

tgstation/tgstation#47750

* tg keybinding commit 2

tgstation/tgstation#47868

* unit test emotes

* oops

* clean

* guhhhh

* we dont have the same crit

* integers

* implement ceilings, dehardcode limit

* bad operator

* fix integer window

* comment out testing output

* gasper
  • Loading branch information
Tsar-Salat authored Dec 25, 2024
1 parent 169c857 commit eea7fd5
Show file tree
Hide file tree
Showing 20 changed files with 295 additions and 115 deletions.
2 changes: 2 additions & 0 deletions beestation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@
#include "code\_globalvars\lists\client.dm"
#include "code\_globalvars\lists\flavor_misc.dm"
#include "code\_globalvars\lists\icons.dm"
#include "code\_globalvars\lists\keybindings.dm"
#include "code\_globalvars\lists\maintenance_loot.dm"
#include "code\_globalvars\lists\mapping.dm"
#include "code\_globalvars\lists\mobs.dm"
Expand Down Expand Up @@ -917,6 +918,7 @@
#include "code\datums\keybinding\carbon.dm"
#include "code\datums\keybinding\client.dm"
#include "code\datums\keybinding\communication.dm"
#include "code\datums\keybinding\emote.dm"
#include "code\datums\keybinding\human.dm"
#include "code\datums\keybinding\keybinding.dm"
#include "code\datums\keybinding\living.dm"
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/cooldowns.dm
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
#define COOLDOWN_MECHA_MELEE_ATTACK "mecha_melee"
#define COOLDOWN_MECHA_SMOKE "mecha_smoke"

#define COOLDOWN_EMOTE_WINDOW "emote_window"

//TIMER COOLDOWN MACROS

#define COMSIG_CD_STOP(cd_index) "cooldown_[cd_index]"
Expand Down
1 change: 1 addition & 0 deletions code/__DEFINES/keybinding.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

//General
#define COMSIG_KB_ACTIVATED (1<<0)
#define COMSIG_KB_EMOTE "keybinding_emote_down"

//Admin
#define COMSIG_KB_ADMIN_ASAY_DOWN "keybinding_admin_asay_down"
Expand Down
8 changes: 1 addition & 7 deletions code/__HELPERS/global_lists.dm
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,7 @@
GLOB.hair_gradients_list[H.name] = H

// Keybindings
for(var/KB in subtypesof(/datum/keybinding))
var/datum/keybinding/keybinding = KB
if(!initial(keybinding.keys) || !initial(keybinding.keybind_signal))
continue
var/datum/keybinding/instance = new keybinding
GLOB.keybindings_by_name[instance.name] = instance
LAZYADD(GLOB.keybindings_by_name_to_key[instance.name], LAZYCOPY(instance.keys))
init_keybindings()

init_crafting_recipes(GLOB.crafting_recipes)

Expand Down
22 changes: 22 additions & 0 deletions code/_globalvars/lists/keybindings.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/// Creates and sorts all the keybinding datums
/proc/init_keybindings()
for(var/KB in subtypesof(/datum/keybinding))
var/datum/keybinding/keybinding = KB
if(!initial(keybinding.keybind_signal) || !initial(keybinding.name))
continue
add_keybinding(new keybinding)
init_emote_keybinds()

/// Adds an instanced keybinding to the global tracker
/proc/add_keybinding(datum/keybinding/instance)
GLOB.keybindings_by_name[instance.name] = instance
LAZYADD(GLOB.keybindings_by_name_to_key[instance.name], LAZYCOPY(instance.keys))

/proc/init_emote_keybinds()
for(var/i in subtypesof(/datum/emote))
var/datum/emote/faketype = i
if(!initial(faketype.key))
continue
var/datum/keybinding/emote/emote_kb = new
emote_kb.link_to_emote(faketype)
add_keybinding(emote_kb)
2 changes: 1 addition & 1 deletion code/datums/brain_damage/split_personality.dm
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/split_personality)
return FALSE

/mob/living/split_personality/emote(act, m_type = null, message = null, intentional = FALSE)
return
return FALSE

///////////////BRAINWASHING////////////////////

Expand Down
115 changes: 107 additions & 8 deletions code/datums/emotes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,21 @@
var/sound
/// Volume to play the sound at
var/sound_volume = 50
/// Whether to vary the pitch of the sound played
/// Do we vary the pitch of the sound played
var/vary = FALSE
var/only_forced_audio = FALSE //can only code call this event instead of the player.
/// The cooldown between the uses of the emote.
var/cooldown = 0.5 SECONDS
/// How long is the shared emote cooldown triggered by this emote?
var/general_emote_audio_cooldown = 7 SECONDS
/// How long is the specific emote cooldown triggered by this emote?
var/specific_emote_audio_cooldown = 10 SECONDS
/// Every time a emote is made, it increases this counter by one. When the integer equals cooldown_integer_ceiling, the mob is forced into a cooldown period
var/cooldown_integer = 0
/// Maximum amount of emotes that can be made
var/cooldown_integer_ceiling = 3
/// Does this emote's sound ignore walls?
var/sound_wall_ignore = FALSE

// Animated emote stuff
// ~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -61,18 +73,27 @@
if(!name)
name = key

/**
* Handles the modifications and execution of emotes.
*
* Arguments:
* * user - Person that is trying to send the emote.
* * params - Parameters added after the emote.
* * type_override - Override to the current emote_type.
* * intentional - Bool that says whether the emote was forced (FALSE) or not (TRUE).
*
*/
/datum/emote/proc/run_emote(mob/user, params, type_override, intentional = FALSE)
SHOULD_CALL_PARENT(TRUE)
if(!can_run_emote(user, TRUE, intentional))
return FALSE

if((emote_type & EMOTE_ANIMATED) && emote_length > 0)
var/image/I = image(overlay_icon, user, overlay_icon_state, ABOVE_MOB_LAYER, 0, overlay_x_offset, overlay_y_offset)
flick_overlay_view(I, user, emote_length)

var/tmp_sound = get_sound(user)
if(tmp_sound && (!only_forced_audio || !intentional))
playsound(user, tmp_sound, sound_volume, vary)
if(tmp_sound && should_play_sound(user, intentional) && !TIMER_COOLDOWN_CHECK(user, "audible_emote_cooldown") && !TIMER_COOLDOWN_CHECK(user, type))
run_cooldown_integer(user)
playsound(source = user, soundin = tmp_sound, vol = sound_volume, vary = vary, ignore_walls = sound_wall_ignore)

var/msg = select_message_type(user, intentional)
if(params && message_param)
Expand All @@ -86,7 +107,7 @@
I.trigger(key, L)

if(!msg)
return TRUE
return

user.log_message(msg, LOG_EMOTE)

Expand Down Expand Up @@ -124,7 +145,7 @@
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
return // Early exit so no dchat message

// The emote has some important information, and should always be shown to the user
else if(is_important)
Expand Down Expand Up @@ -168,6 +189,51 @@
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

/datum/emote/proc/run_cooldown_integer(mob/user)
//If we do one audible emote, then do nothing, we eventually should purge our list
cooldown_integer_window(user)
cooldown_integer += 1
//debug
//user.balloon_alert(user, "[cooldown_integer]")
check_cooldown_integer(user)

/datum/emote/proc/check_cooldown_integer(mob/user)
if(cooldown_integer >= cooldown_integer_ceiling)
to_chat(user, "<span class='warning'>[name] emote limit reached</span>")
TIMER_COOLDOWN_START(user, type, specific_emote_audio_cooldown)
TIMER_COOLDOWN_START(user, "general_emote_audio_cooldown", general_emote_audio_cooldown)
//We used up all our usable emotes, now we set the integer back to zero and wait the long wait
cooldown_integer = initial(cooldown_integer)

/datum/emote/proc/cooldown_integer_window(mob/user)
if(TIMER_COOLDOWN_CHECK(user, COOLDOWN_EMOTE_WINDOW))
TIMER_COOLDOWN_START(user, COOLDOWN_EMOTE_WINDOW, 4 SECONDS)
else
//We did a few emotes, but didnt use them all up, reset our integer
cooldown_integer = initial(cooldown_integer)

/**
* For handling emote cooldown, return true to allow the emote to happen.
*
* Arguments:
* * user - Person that is trying to send the emote.
* * intentional - Bool that says whether the emote was forced (FALSE) or not (TRUE).
*
* Returns FALSE if the cooldown is not over, TRUE if the cooldown is over.
*/
/datum/emote/proc/check_cooldown(mob/user, intentional)
if(!intentional)
return TRUE

if(user.emotes_used && user.emotes_used[src] + cooldown > world.time)
return FALSE

if(!user.emotes_used)
user.emotes_used = list()

user.emotes_used[src] = world.time
return TRUE

/datum/emote/proc/get_sound(mob/living/user)
Expand Down Expand Up @@ -208,7 +274,7 @@
/datum/emote/proc/select_param(mob/user, params)
return replacetext(message_param, "%t", params)

/datum/emote/proc/can_run_emote(mob/user, status_check = TRUE, intentional = FALSE)
/datum/emote/proc/can_run_emote(mob/user, status_check = TRUE, intentional = FALSE, params)
. = TRUE
if(!is_type_in_typecache(user, mob_type_allowed_typecache))
return FALSE
Expand Down Expand Up @@ -237,6 +303,39 @@
if(HAS_TRAIT(L, TRAIT_EMOTEMUTE))
return FALSE

/**
* Check to see if the user should play a sound when performing the emote.
*
* Arguments:
* * user - Person that is doing the emote.
* * intentional - Bool that says whether the emote was forced (FALSE) or not (TRUE).
*
* Returns a bool about whether or not the user should play a sound when performing the emote.
*/
/datum/emote/proc/should_play_sound(mob/user, intentional = FALSE)
if(emote_type & EMOTE_AUDIBLE && !hands_use_check)
if(HAS_TRAIT(user, TRAIT_MUTE))
return FALSE
if(ishuman(user))
var/mob/living/carbon/human/loud_mouth = user
if(loud_mouth.mind?.miming) // vow of silence prevents outloud noises
return FALSE
if(!loud_mouth.getorganslot(ORGAN_SLOT_TONGUE))
return FALSE

if(only_forced_audio && intentional)
return FALSE
return TRUE

/**
* Allows the intrepid coder to send a basic emote
* Takes text as input, sends it out to those who need to know after some light parsing
* If you need something more complex, make it into a datum emote
* Arguments:
* * text - The text to send out
*
* Returns TRUE if it was able to run the emote, FALSE otherwise.
*/
/mob/proc/manual_emote(text) //Just override the song and dance
. = TRUE
if(stat != CONSCIOUS)
Expand Down
14 changes: 8 additions & 6 deletions code/datums/keybinding/_defines.dm
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#define CATEGORY_CLIENT "CLIENT"
#define CATEGORY_EMOTE "EMOTE"
#define CATEGORY_ADMIN "ADMIN"
#define CATEGORY_CARBON "CARBON"
#define CATEGORY_HUMAN "HUMAN"
Expand All @@ -8,11 +9,12 @@
#define CATEGORY_COMMUNICATION "COMMUNICATION"

#define WEIGHT_HIGHEST 0
#define WEIGHT_CLIENT 10
#define WEIGHT_ADMIN 20
#define WEIGHT_MOB 30
#define WEIGHT_LIVING 40
#define WEIGHT_DEAD 50
#define WEIGHT_ROBOT 60
#define WEIGHT_ADMIN 10
#define WEIGHT_CLIENT 20
#define WEIGHT_ROBOT 30
#define WEIGHT_MOB 40
#define WEIGHT_LIVING 50
#define WEIGHT_DEAD 60
#define WEIGHT_EMOTE 70
#define WEIGHT_AI 80
#define WEIGHT_LOWEST 999
17 changes: 17 additions & 0 deletions code/datums/keybinding/emote.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/datum/keybinding/emote
category = CATEGORY_EMOTE
weight = WEIGHT_EMOTE
keybind_signal = COMSIG_KB_EMOTE
var/emote_key

/datum/keybinding/emote/proc/link_to_emote(datum/emote/faketype)
keys = list("Unbound")
emote_key = initial(faketype.key)
name = initial(faketype.key)
full_name = capitalize(initial(faketype.key))

/datum/keybinding/emote/down(client/user)
. = ..()
if(.)
return
return user.mob.emote(emote_key, intentional=TRUE)
2 changes: 1 addition & 1 deletion code/modules/mob/camera/camera.dm
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
return FALSE

/mob/camera/emote(act, m_type=1, message = null, intentional = FALSE)
return
return FALSE

// Cameras can't fall
/mob/camera/has_gravity(turf/T)
Expand Down
Loading

0 comments on commit eea7fd5

Please sign in to comment.