Files
Bubberstation/code/modules/mob/living/emote.dm
Fikou fc4de530ce reorganizes the human sprite folder and replaces the human_basic sprite with an updated one (#77323)
instead of mob/species/human the icon folders are now mob/human/species,
this makes much more sense imo than having human stuff like hair or
bodyparts (which are a GENERAL thing, not human species only) be behind
a folder while you see shit like podperson hair and golem in the main
folder
the icon for human is replaced by the new sprites instead of the old
yellow guy with green eyes
2023-08-05 14:12:05 +00:00

713 lines
22 KiB
Plaintext

/* EMOTE DATUMS */
/datum/emote/living
mob_type_allowed_typecache = /mob/living
mob_type_blacklist_typecache = list(/mob/living/brain)
/datum/emote/living/blush
key = "blush"
key_third_person = "blushes"
message = "blushes."
/datum/emote/living/blush/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(!ishuman(user))
return
var/mob/living/carbon/human/human_user = user
QDEL_IN(human_user.give_emote_overlay(/datum/bodypart_overlay/simple/emote/blush), 5.2 SECONDS)
/datum/emote/living/sing_tune
key = "tunesing"
key_third_person = "sings a tune"
message = "sings a tune."
/datum/emote/living/bow
key = "bow"
key_third_person = "bows"
message = "bows."
message_param = "bows to %t."
hands_use_check = TRUE
/datum/emote/living/burp
key = "burp"
key_third_person = "burps"
message = "burps."
message_mime = "acts out a burp."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/choke
key = "choke"
key_third_person = "chokes"
message = "chokes!"
message_mime = "chokes silently!"
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/cross
key = "cross"
key_third_person = "crosses"
message = "crosses their arms."
hands_use_check = TRUE
/datum/emote/living/chuckle
key = "chuckle"
key_third_person = "chuckles"
message = "chuckles."
message_mime = "acts out chuckling."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/collapse
key = "collapse"
key_third_person = "collapses"
message = "collapses!"
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/collapse/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(. && isliving(user))
var/mob/living/L = user
L.Unconscious(40)
/datum/emote/living/cough
key = "cough"
key_third_person = "coughs"
message = "coughs!"
message_mime = "acts out an exaggerated cough!"
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional)
. = ..()
if(HAS_TRAIT(user, TRAIT_SOOTHED_THROAT))
return FALSE
/datum/emote/living/dance
key = "dance"
key_third_person = "dances"
message = "dances around happily."
hands_use_check = TRUE
/datum/emote/living/deathgasp
key = "deathgasp"
key_third_person = "deathgasps"
message = "seizes up and falls limp, their eyes dead and lifeless..."
message_robot = "shudders violently for a moment before falling still, its eyes slowly darkening."
message_AI = "screeches, its screen flickering as its systems slowly halt."
message_alien = "lets out a waning guttural screech, and collapses onto the floor..."
message_larva = "lets out a sickly hiss of air and falls limply to the floor..."
message_monkey = "lets out a faint chimper as it collapses and stops moving..."
message_animal_or_basic = "stops moving..."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE | EMOTE_IMPORTANT
cooldown = (15 SECONDS)
stat_allowed = HARD_CRIT
/datum/emote/living/deathgasp/run_emote(mob/living/user, params, type_override, intentional)
if(!is_type_in_typecache(user, mob_type_allowed_typecache))
return
var/custom_message = user.death_message
if(custom_message)
message_animal_or_basic = custom_message
. = ..()
message_animal_or_basic = initial(message_animal_or_basic)
if(. && user.death_sound)
if(!user.can_speak() || user.oxyloss >= 50)
return //stop the sound if oxyloss too high/cant speak
playsound(user, user.death_sound, 200, TRUE, TRUE)
/datum/emote/living/drool
key = "drool"
key_third_person = "drools"
message = "drools."
/datum/emote/living/faint
key = "faint"
key_third_person = "faints"
message = "faints."
/datum/emote/living/faint/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(. && isliving(user))
var/mob/living/L = user
L.SetSleeping(200)
/datum/emote/living/flap
key = "flap"
key_third_person = "flaps"
message = "flaps their wings."
hands_use_check = TRUE
var/wing_time = 20
/datum/emote/living/flap/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(. && ishuman(user))
var/mob/living/carbon/human/H = user
var/open = FALSE
var/obj/item/organ/external/wings/functional/wings = H.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS)
if(istype(wings))
if(wings.wings_open)
open = TRUE
wings.close_wings()
else
wings.open_wings()
addtimer(CALLBACK(wings, open ? TYPE_PROC_REF(/obj/item/organ/external/wings/functional, open_wings) : TYPE_PROC_REF(/obj/item/organ/external/wings/functional, close_wings)), wing_time)
/datum/emote/living/flap/aflap
key = "aflap"
key_third_person = "aflaps"
message = "flaps their wings ANGRILY!"
hands_use_check = TRUE
wing_time = 10
/datum/emote/living/frown
key = "frown"
key_third_person = "frowns"
message = "frowns."
/datum/emote/living/gag
key = "gag"
key_third_person = "gags"
message = "gags."
message_mime = "gags silently."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/gasp
key = "gasp"
key_third_person = "gasps"
message = "gasps!"
message_mime = "gasps silently!"
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
stat_allowed = HARD_CRIT
/datum/emote/living/gasp_shock
key = "gaspshock"
key_third_person = "gaspsshock"
message = "gasps in shock!"
message_mime = "gasps in silent shock!"
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
stat_allowed = SOFT_CRIT
/datum/emote/living/gasp_shock/get_sound(mob/living/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/human_user = user
if(human_user.dna.species.id == SPECIES_HUMAN && !HAS_MIND_TRAIT(human_user, TRAIT_MIMING))
if(human_user.gender == FEMALE)
return pick('sound/voice/human/gasp_female1.ogg', 'sound/voice/human/gasp_female2.ogg', 'sound/voice/human/gasp_female3.ogg')
else
return pick('sound/voice/human/gasp_male1.ogg', 'sound/voice/human/gasp_male2.ogg')
/datum/emote/living/giggle
key = "giggle"
key_third_person = "giggles"
message = "giggles."
message_mime = "giggles silently!"
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/glare
key = "glare"
key_third_person = "glares"
message = "glares."
message_param = "glares at %t."
/datum/emote/living/grin
key = "grin"
key_third_person = "grins"
message = "grins."
/datum/emote/living/groan
key = "groan"
key_third_person = "groans"
message = "groans!"
message_mime = "appears to groan!"
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/grimace
key = "grimace"
key_third_person = "grimaces"
message = "grimaces."
/datum/emote/living/jump
key = "jump"
key_third_person = "jumps"
message = "jumps!"
hands_use_check = TRUE
/datum/emote/living/jump/run_emote(mob/living/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
animate(user, pixel_y = user.pixel_y + 4, time = 0.1 SECONDS)
animate(pixel_y = user.pixel_y - 4, time = 0.1 SECONDS)
/datum/emote/living/jump/get_sound(mob/living/user)
return 'sound/weapons/thudswoosh.ogg'
/datum/emote/living/kiss
key = "kiss"
key_third_person = "kisses"
cooldown = 3 SECONDS
/datum/emote/living/kiss/run_emote(mob/living/user, params, type_override, intentional)
. = ..()
if(!.)
return
var/kiss_type = /obj/item/hand_item/kisser
if(HAS_TRAIT(user, TRAIT_KISS_OF_DEATH))
kiss_type = /obj/item/hand_item/kisser/death
var/obj/item/kiss_blower = new kiss_type(user)
if(user.put_in_hands(kiss_blower))
to_chat(user, span_notice("You ready your kiss-blowing hand."))
else
qdel(kiss_blower)
to_chat(user, span_warning("You're incapable of blowing a kiss in your current state."))
/datum/emote/living/laugh
key = "laugh"
key_third_person = "laughs"
message = "laughs."
message_mime = "laughs silently!"
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
audio_cooldown = 5 SECONDS
vary = TRUE
/datum/emote/living/laugh/can_run_emote(mob/living/user, status_check = TRUE , intentional)
return ..() && user.can_speak(allow_mimes = TRUE)
/datum/emote/living/laugh/get_sound(mob/living/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/human_user = user
if(human_user.dna.species.id == SPECIES_HUMAN && !HAS_MIND_TRAIT(human_user, TRAIT_MIMING))
if(human_user.gender == FEMALE)
return 'sound/voice/human/womanlaugh.ogg'
else
return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg')
/datum/emote/living/look
key = "look"
key_third_person = "looks"
message = "looks."
message_param = "looks at %t."
/datum/emote/living/nod
key = "nod"
key_third_person = "nods"
message = "nods."
message_param = "nods at %t."
/datum/emote/living/point
key = "point"
key_third_person = "points"
message = "points."
message_param = "points at %t."
hands_use_check = TRUE
/datum/emote/living/point/run_emote(mob/user, params, type_override, intentional)
message_param = initial(message_param) // reset
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.usable_hands == 0)
if(H.usable_legs != 0)
message_param = "tries to point at %t with a leg, [span_userdanger("falling down")] in the process!"
H.Paralyze(20)
else
message_param = "[span_userdanger("bumps [user.p_their()] head on the ground")] trying to motion towards %t."
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5)
return ..()
/datum/emote/living/pout
key = "pout"
key_third_person = "pouts"
message = "pouts."
message_mime = "pouts silently."
/datum/emote/living/scream
key = "scream"
key_third_person = "screams"
message = "screams!"
message_mime = "acts out a scream!"
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
mob_type_blacklist_typecache = list(/mob/living/carbon/human) //Humans get specialized scream.
/datum/emote/living/scream/select_message_type(mob/user, message, intentional)
. = ..()
if(!intentional && isanimal_or_basicmob(user))
return "makes a loud and pained whimper."
/datum/emote/living/scowl
key = "scowl"
key_third_person = "scowls"
message = "scowls."
/datum/emote/living/shake
key = "shake"
key_third_person = "shakes"
message = "shakes their head."
/datum/emote/living/shiver
key = "shiver"
key_third_person = "shiver"
message = "shivers."
#define SHIVER_LOOP_DURATION (1 SECONDS)
/datum/emote/living/shiver/run_emote(mob/living/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
animate(user, pixel_x = user.pixel_x + 1, time = 0.1 SECONDS)
for(var/i in 1 to SHIVER_LOOP_DURATION / (0.2 SECONDS)) //desired total duration divided by the iteration duration to give the necessary iteration count
animate(pixel_x = user.pixel_x - 1, time = 0.1 SECONDS)
animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS)
animate(pixel_x = user.pixel_x - 1, time = 0.1 SECONDS)
#undef SHIVER_LOOP_DURATION
/datum/emote/living/sigh
key = "sigh"
key_third_person = "sighs"
message = "sighs."
message_mime = "acts out an exaggerated silent sigh."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/sigh/run_emote(mob/living/user, params, type_override, intentional)
. = ..()
if(!ishuman(user))
return
var/image/emote_animation = image('icons/mob/human/emote_visuals.dmi', user, "sigh")
flick_overlay_global(emote_animation, GLOB.clients, 2.0 SECONDS)
/datum/emote/living/sit
key = "sit"
key_third_person = "sits"
message = "sits down."
/datum/emote/living/smile
key = "smile"
key_third_person = "smiles"
message = "smiles."
/datum/emote/living/sneeze
key = "sneeze"
key_third_person = "sneezes"
message = "sneezes."
message_mime = "acts out an exaggerated silent sneeze."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/smug
key = "smug"
key_third_person = "smugs"
message = "grins smugly."
/datum/emote/living/sniff
key = "sniff"
key_third_person = "sniffs"
message = "sniffs."
message_mime = "sniffs silently."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/snore
key = "snore"
key_third_person = "snores"
message = "snores."
message_mime = "sleeps soundly."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
stat_allowed = UNCONSCIOUS
/datum/emote/living/stare
key = "stare"
key_third_person = "stares"
message = "stares."
message_param = "stares at %t."
/datum/emote/living/strech
key = "stretch"
key_third_person = "stretches"
message = "stretches their arms."
/datum/emote/living/sulk
key = "sulk"
key_third_person = "sulks"
message = "sulks down sadly."
/datum/emote/living/surrender
key = "surrender"
key_third_person = "surrenders"
message = "puts their hands on their head and falls to the ground, they surrender%s!"
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/surrender/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(. && isliving(user))
var/mob/living/L = user
L.Paralyze(200)
L.remove_status_effect(/datum/status_effect/grouped/surrender)
/datum/emote/living/sway
key = "sway"
key_third_person = "sways"
message = "sways around dizzily."
/datum/emote/living/sway/run_emote(mob/living/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
animate(user, pixel_x = user.pixel_x + 2, time = 0.5 SECONDS)
for(var/i in 1 to 2)
animate(pixel_x = user.pixel_x - 4, time = 1.0 SECONDS)
animate(pixel_x = user.pixel_x + 4, time = 1.0 SECONDS)
animate(pixel_x = user.pixel_x - 2, time = 0.5 SECONDS)
/datum/emote/living/tilt
key = "tilt"
key_third_person = "tilts"
message = "tilts their head to the side."
/datum/emote/living/tremble
key = "tremble"
key_third_person = "trembles"
message = "trembles in fear!"
#define TREMBLE_LOOP_DURATION (4.4 SECONDS)
/datum/emote/living/tremble/run_emote(mob/living/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
animate(user, pixel_x = user.pixel_x + 2, time = 0.2 SECONDS)
for(var/i in 1 to TREMBLE_LOOP_DURATION / (0.4 SECONDS)) //desired total duration divided by the iteration duration to give the necessary iteration count
animate(pixel_x = user.pixel_x - 2, time = 0.2 SECONDS)
animate(pixel_x = user.pixel_x + 2, time = 0.2 SECONDS)
animate(pixel_x = user.pixel_x - 2, time = 0.2 SECONDS)
#undef TREMBLE_LOOP_DURATION
/datum/emote/living/twitch
key = "twitch"
key_third_person = "twitches"
message = "twitches violently."
/datum/emote/living/twitch/run_emote(mob/living/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
animate(user, pixel_x = user.pixel_x - 1, time = 0.1 SECONDS)
animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS)
animate(time = 0.1 SECONDS)
animate(pixel_x = user.pixel_x - 1, time = 0.1 SECONDS)
animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS)
/datum/emote/living/twitch_s
key = "twitch_s"
message = "twitches."
/datum/emote/living/twitch_s/run_emote(mob/living/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
animate(user, pixel_x = user.pixel_x - 1, time = 0.1 SECONDS)
animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS)
/datum/emote/living/wave
key = "wave"
key_third_person = "waves"
message = "waves."
/datum/emote/living/whimper
key = "whimper"
key_third_person = "whimpers"
message = "whimpers."
message_mime = "appears hurt."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/wsmile
key = "wsmile"
key_third_person = "wsmiles"
message = "smiles weakly."
/// The base chance for your yawn to propagate to someone else if they're on the same tile as you
#define YAWN_PROPAGATE_CHANCE_BASE 40
/// The base chance for your yawn to propagate to someone else if they're on the same tile as you
#define YAWN_PROPAGATE_CHANCE_DECAY 8
/datum/emote/living/yawn
key = "yawn"
key_third_person = "yawns"
message = "yawns."
message_mime = "acts out an exaggerated silent yawn."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
cooldown = 5 SECONDS
/datum/emote/living/yawn/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(!isliving(user))
return
if(!TIMER_COOLDOWN_CHECK(user, COOLDOWN_YAWN_PROPAGATION))
TIMER_COOLDOWN_START(user, COOLDOWN_YAWN_PROPAGATION, cooldown * 3)
var/mob/living/carbon/carbon_user = user
if(istype(carbon_user) && ((carbon_user.wear_mask?.flags_inv & HIDEFACE) || carbon_user.head?.flags_inv & HIDEFACE))
return // if your face is obscured, skip propagation
var/propagation_distance = user.client ? 5 : 2 // mindless mobs are less able to spread yawns
for(var/mob/living/iter_living in view(user, propagation_distance))
if(IS_DEAD_OR_INCAP(iter_living) || TIMER_COOLDOWN_CHECK(iter_living, COOLDOWN_YAWN_PROPAGATION))
continue
var/dist_between = get_dist(user, iter_living)
var/recently_examined = FALSE // if you yawn just after someone looks at you, it forces them to yawn as well. Tradecraft!
if(iter_living.client)
var/examine_time = LAZYACCESS(iter_living.client?.recent_examines, user)
if(examine_time && (world.time - examine_time < YAWN_PROPAGATION_EXAMINE_WINDOW))
recently_examined = TRUE
if(!recently_examined && !prob(YAWN_PROPAGATE_CHANCE_BASE - (YAWN_PROPAGATE_CHANCE_DECAY * dist_between)))
continue
var/yawn_delay = rand(0.2 SECONDS, 0.7 SECONDS) * dist_between
addtimer(CALLBACK(src, PROC_REF(propagate_yawn), iter_living), yawn_delay)
/// This yawn has been triggered by someone else yawning specifically, likely after a delay. Check again if they don't have the yawned recently trait
/datum/emote/living/yawn/proc/propagate_yawn(mob/user)
if(!istype(user) || TIMER_COOLDOWN_CHECK(user, COOLDOWN_YAWN_PROPAGATION))
return
user.emote("yawn")
#undef YAWN_PROPAGATE_CHANCE_BASE
#undef YAWN_PROPAGATE_CHANCE_DECAY
/datum/emote/living/gurgle
key = "gurgle"
key_third_person = "gurgles"
message = "makes an uncomfortable gurgle."
message_mime = "gurgles silently and uncomfortably."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/custom
key = "me"
key_third_person = "custom"
message = null
/datum/emote/living/custom/can_run_emote(mob/user, status_check, intentional)
. = ..() && intentional
/datum/emote/living/custom/proc/emote_is_valid(mob/user, input)
// We're assuming clientless mobs custom emoting is something codebase-driven and not player-driven.
// If players ever get the ability to force clientless mobs to emote, we'd need to reconsider this.
if(!user.client)
return TRUE
if(CAN_BYPASS_FILTER(user))
return TRUE
var/static/regex/stop_bad_mime = regex(@"says|exclaims|yells|asks")
if(stop_bad_mime.Find(input, 1, 1))
to_chat(user, span_danger("Invalid emote."))
return FALSE
var/list/filter_result = is_ic_filtered(input)
if(filter_result)
to_chat(user, span_warning("That emote contained a word prohibited in IC emotes! Consider reviewing the server rules."))
to_chat(user, span_warning("\"[input]\""))
REPORT_CHAT_FILTER_TO_USER(user, filter_result)
log_filter("IC Emote", input, filter_result)
SSblackbox.record_feedback("tally", "ic_blocked_words", 1, lowertext(config.ic_filter_regex.match))
return FALSE
filter_result = is_soft_ic_filtered(input)
if(filter_result)
if(tgui_alert(user,"Your emote contains \"[filter_result[CHAT_FILTER_INDEX_WORD]]\". \"[filter_result[CHAT_FILTER_INDEX_REASON]]\", Are you sure you want to emote it?", "Soft Blocked Word", list("Yes", "No")) != "Yes")
SSblackbox.record_feedback("tally", "soft_ic_blocked_words", 1, lowertext(config.soft_ic_filter_regex.match))
log_filter("Soft IC Emote", input, filter_result)
return FALSE
message_admins("[ADMIN_LOOKUPFLW(user)] has passed the soft filter for emote \"[filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Emote: \"[input]\"")
log_admin_private("[key_name(user)] has passed the soft filter for emote \"[filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Emote: \"[input]\"")
SSblackbox.record_feedback("tally", "passed_soft_ic_blocked_words", 1, lowertext(config.soft_ic_filter_regex.match))
log_filter("Soft IC Emote (Passed)", input, filter_result)
return TRUE
/datum/emote/living/custom/proc/get_custom_emote_from_user()
return copytext(sanitize(input("Choose an emote to display.") as text|null), 1, MAX_MESSAGE_LEN)
/datum/emote/living/custom/proc/get_custom_emote_type_from_user()
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
switch(type)
if("Visible")
return EMOTE_VISIBLE
if("Hearable")
return EMOTE_AUDIBLE
else
tgui_alert(usr,"Unable to use this emote, must be either hearable or visible.")
return FALSE
/datum/emote/living/custom/run_emote(mob/user, params, type_override = null, intentional = FALSE)
if(!can_run_emote(user, TRUE, intentional))
return FALSE
if(is_banned_from(user.ckey, "Emote"))
to_chat(user, span_boldwarning("You cannot send custom emotes (banned)."))
return FALSE
if(QDELETED(user))
return FALSE
if(user.client && user.client.prefs.muted & MUTE_IC)
to_chat(user, span_boldwarning("You cannot send IC messages (muted)."))
return FALSE
message = params ? params : get_custom_emote_from_user()
if(!emote_is_valid(user, message))
message = null
return FALSE
if(!params)
var/user_emote_type = get_custom_emote_type_from_user()
if(!user_emote_type)
return FALSE
emote_type = user_emote_type
else if(type_override)
emote_type = type_override
. = ..()
message = null
emote_type = EMOTE_VISIBLE
/datum/emote/living/custom/replace_pronoun(mob/user, message)
return message
/datum/emote/living/beep
key = "beep"
key_third_person = "beeps"
message = "beeps."
message_param = "beeps at %t."
sound = 'sound/machines/twobeep.ogg'
mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon)
emote_type = EMOTE_AUDIBLE
/datum/emote/living/inhale
key = "inhale"
key_third_person = "inhales"
message = "breathes in."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/exhale
key = "exhale"
key_third_person = "exhales"
message = "breathes out."
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
/datum/emote/living/swear
key = "swear"
key_third_person = "swears"
message = "says a swear word!"
message_mime = "makes a rude gesture!"
emote_type = EMOTE_AUDIBLE