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

Ports emote keybindings #11991

Merged
merged 23 commits into from
Dec 25, 2024
Merged
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
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
Loading