mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-13 17:14:47 +01:00
00ccf0c6b5
# Conflicts: # .github/CODEOWNERS # .github/workflows/compile_changelogs.yml # .github/workflows/stale.yml # SQL/database_changelog.md # _maps/map_files/CatwalkStation/CatwalkStation_2023.dmm # code/__DEFINES/atom_hud.dm # code/__DEFINES/inventory.dm # code/__DEFINES/mobs.dm # code/__DEFINES/species_clothing_paths.dm # code/__DEFINES/subsystems.dm # code/__DEFINES/surgery.dm # code/__HELPERS/global_lists.dm # code/_globalvars/lists/maintenance_loot.dm # code/_globalvars/traits/_traits.dm # code/controllers/subsystem/minor_mapping.dm # code/controllers/subsystem/processing/quirks.dm # code/controllers/subsystem/shuttle.dm # code/datums/components/palette.dm # code/datums/components/surgery_initiator.dm # code/datums/diseases/advance/advance.dm # code/datums/hud.dm # code/datums/mood.dm # code/datums/mutations/chameleon.dm # code/datums/quirks/negative_quirks/nyctophobia.dm # code/datums/status_effects/debuffs/debuffs.dm # code/datums/status_effects/debuffs/drunk.dm # code/datums/status_effects/debuffs/slime/slime_leech.dm # code/datums/weather/weather.dm # code/game/data_huds.dm # code/game/objects/items.dm # code/game/objects/items/devices/scanners/health_analyzer.dm # code/game/objects/items/frog_statue.dm # code/game/objects/items/rcd/RLD.dm # code/game/objects/items/robot/items/hypo.dm # code/game/objects/items/stacks/medical.dm # code/game/objects/items/stacks/wrap.dm # code/game/objects/items/storage/garment.dm # code/game/objects/items/tools/medical/defib.dm # code/game/objects/items/weaponry.dm # code/game/objects/items/weaponry/melee/misc.dm # code/game/objects/structures/crates_lockers/closets/secure/security.dm # code/game/objects/structures/curtains.dm # code/game/objects/structures/dresser.dm # code/game/objects/structures/girders.dm # code/game/objects/structures/maintenance.dm # code/game/objects/structures/mirror.dm # code/modules/admin/greyscale_modify_menu.dm # code/modules/admin/verbs/light_debug.dm # code/modules/antagonists/ashwalker/ashwalker.dm # code/modules/antagonists/heretic/knowledge/starting_lore.dm # code/modules/antagonists/ninja/ninjaDrainAct.dm # code/modules/art/paintings.dm # code/modules/client/preferences.dm # code/modules/client/verbs/ooc.dm # code/modules/clothing/head/wig.dm # code/modules/events/disease_outbreak.dm # code/modules/holodeck/holo_effect.dm # code/modules/jobs/job_types/head_of_security.dm # code/modules/jobs/job_types/security_officer.dm # code/modules/library/skill_learning/generic_skillchips/point.dm # code/modules/mining/lavaland/ash_flora.dm # code/modules/mining/lavaland/mining_loot/megafauna/ash_drake.dm # code/modules/mob/dead/new_player/new_player.dm # code/modules/mob/living/basic/guardian/guardian.dm # code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm # code/modules/mob/living/carbon/carbon.dm # code/modules/mob/living/carbon/human/human.dm # code/modules/mob/living/carbon/human/human_defines.dm # code/modules/mob/living/carbon/life.dm # code/modules/mob/living/living.dm # code/modules/mob/living/living_defines.dm # code/modules/mob/mob.dm # code/modules/mob_spawn/ghost_roles/mining_roles.dm # code/modules/mod/mod_control.dm # code/modules/mod/modules/modules_general.dm # code/modules/modular_computers/computers/item/computer_ui.dm # code/modules/paperwork/paper.dm # code/modules/paperwork/paperbin.dm # code/modules/power/lighting/light.dm # code/modules/projectiles/guns/energy/kinetic_accelerator.dm # code/modules/projectiles/projectile.dm # code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm # code/modules/reagents/chemistry/reagents/food_reagents.dm # code/modules/reagents/chemistry/reagents/other_reagents.dm # code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm # code/modules/research/xenobiology/crossbreeding/_clothing.dm # code/modules/research/xenobiology/crossbreeding/prismatic.dm # code/modules/surgery/advanced/brainwashing.dm # code/modules/surgery/advanced/lobotomy.dm # code/modules/surgery/amputation.dm # code/modules/surgery/blood_filter.dm # code/modules/surgery/bodyparts/_bodyparts.dm # code/modules/surgery/brain_surgery.dm # code/modules/surgery/cavity_implant.dm # code/modules/surgery/coronary_bypass.dm # code/modules/surgery/gastrectomy.dm # code/modules/surgery/healing.dm # code/modules/surgery/limb_augmentation.dm # code/modules/surgery/organ_manipulation.dm # code/modules/surgery/revival.dm # code/modules/surgery/sleeper_protocol.dm # code/modules/surgery/surgery_helpers.dm # code/modules/surgery/surgery_step.dm # code/modules/unit_tests/_unit_tests.dm # code/modules/unit_tests/designs.dm # code/modules/unit_tests/icon_state_worn.dm # code/modules/unit_tests/screenshots/screenshot_antag_icons_cultist.png # code/modules/unit_tests/screenshots/screenshot_antag_icons_headrevolutionary.png # code/modules/unit_tests/screenshots/screenshot_antag_icons_provocateur.png # code/modules/unit_tests/screenshots/screenshot_husk_body.png # code/modules/unit_tests/screenshots/screenshot_husk_body_missing_limbs.png # icons/map_icons/clothing/head/_head.dmi # icons/map_icons/clothing/shoes.dmi # icons/map_icons/items/_item.dmi # icons/mob/huds/hud.dmi # icons/mob/inhands/64x64_lefthand.dmi # icons/mob/inhands/64x64_righthand.dmi # icons/obj/machines/computer.dmi # tgui/packages/tgui/interfaces/OperatingComputer.jsx # tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx # tgui/packages/tgui/interfaces/PreferencesMenu/types.ts # tgui/packages/tgui/interfaces/SurgeryInitiator.tsx # tools/icon_cutter/check.py
841 lines
27 KiB
Plaintext
841 lines
27 KiB
Plaintext
|
|
/* EMOTE DATUMS */
|
|
/datum/emote/living
|
|
abstract_type = /datum/emote/living
|
|
mob_type_allowed_typecache = /mob/living
|
|
mob_type_blacklist_typecache = list(/mob/living/brain)
|
|
|
|
/datum/emote/living/taunt
|
|
key = "taunt"
|
|
key_third_person = "taunts"
|
|
message = "taunts!"
|
|
cooldown = 1.6 SECONDS //note when changing this- this is used by the matrix taunt to block projectiles.
|
|
|
|
/datum/emote/living/taunt/run_emote(mob/living/user, params, type_override, intentional)
|
|
. = ..()
|
|
user.spin(TAUNT_EMOTE_DURATION, 0.1 SECONDS)
|
|
|
|
/datum/emote/living/tongue
|
|
key = "tongue"
|
|
key_third_person = "tongues"
|
|
message = "sticks their tongue out."
|
|
|
|
/datum/emote/living/tongue/run_emote(mob/user, params, type_override, intentional)
|
|
var/mob/living/carbon/human/human_user = user
|
|
if(istype(human_user) && !human_user.get_organ_slot(ORGAN_SLOT_TONGUE))
|
|
to_chat(human_user, span_warning("You don't have a tongue!"))
|
|
return
|
|
. = ..()
|
|
QDEL_IN(human_user.give_emote_overlay(/datum/bodypart_overlay/simple/emote/tongue), 5.2 SECONDS)
|
|
|
|
/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/living = user
|
|
living.Unconscious(4 SECONDS)
|
|
|
|
/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.can_speak() || user.get_oxy_loss() >= 50)
|
|
return //stop the sound if oxyloss too high/cant speak
|
|
var/mob/living/carbon/carbon_user = user
|
|
// For masks that give unique death sounds
|
|
if(istype(carbon_user) && isclothing(carbon_user.wear_mask) && carbon_user.wear_mask.unique_death)
|
|
playsound(carbon_user, carbon_user.wear_mask.unique_death, 200, TRUE, TRUE)
|
|
return
|
|
if(user.death_sound)
|
|
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/living = user
|
|
living.SetSleeping(20 SECONDS)
|
|
|
|
/datum/emote/living/flap
|
|
key = "flap"
|
|
key_third_person = "flaps"
|
|
message = "flaps their wings."
|
|
hands_use_check = TRUE
|
|
var/wing_time = 0.35 SECONDS
|
|
|
|
/datum/emote/living/flap/run_emote(mob/user, params, type_override, intentional)
|
|
. = ..()
|
|
if(!ishuman(user))
|
|
return
|
|
var/mob/living/carbon/human/human_user = user
|
|
var/obj/item/organ/wings/wings = human_user.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS)
|
|
|
|
// play a flapping noise if the wing has this implemented
|
|
if(!istype(wings))
|
|
return
|
|
wings.make_flap_sound(human_user)
|
|
|
|
// open/close functional wings
|
|
var/obj/item/organ/wings/functional/wings_functional = wings
|
|
if(!istype(wings_functional))
|
|
return
|
|
var/open = FALSE
|
|
if(wings_functional.wings_open)
|
|
open = TRUE
|
|
wings_functional.close_wings()
|
|
else
|
|
wings_functional.open_wings()
|
|
addtimer(CALLBACK(wings_functional, open ? TYPE_PROC_REF(/obj/item/organ/wings/functional, open_wings) : TYPE_PROC_REF(/obj/item/organ/wings/functional, close_wings)), wing_time)
|
|
|
|
/datum/emote/living/flap/aflap
|
|
key = "aflap"
|
|
key_third_person = "aflaps"
|
|
name = "flap (Angry)"
|
|
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/get_sound(mob/living/user)
|
|
if(HAS_MIND_TRAIT(user, TRAIT_MIMING))
|
|
return
|
|
if(!ishuman(user))
|
|
return
|
|
|
|
var/mob/living/carbon/human/human_user = user
|
|
if(human_user.physique == FEMALE)
|
|
return pick(
|
|
'sound/mobs/humanoids/human/gasp/gasp_female1.ogg',
|
|
'sound/mobs/humanoids/human/gasp/gasp_female2.ogg',
|
|
'sound/mobs/humanoids/human/gasp/gasp_female3.ogg',
|
|
)
|
|
return pick(
|
|
'sound/mobs/humanoids/human/gasp/gasp_male1.ogg',
|
|
'sound/mobs/humanoids/human/gasp/gasp_male2.ogg',
|
|
)
|
|
|
|
/datum/emote/living/gasp/shock
|
|
key = "gaspshock"
|
|
key_third_person = "gaspsshock"
|
|
name = "gasp (Shock)"
|
|
message = "gasps in shock!"
|
|
message_mime = "gasps in silent shock!"
|
|
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
|
|
stat_allowed = SOFT_CRIT
|
|
|
|
/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/kiss
|
|
key = "kiss"
|
|
key_third_person = "kisses"
|
|
cooldown = 3 SECONDS
|
|
|
|
/datum/emote/living/kiss/run_emote(mob/living/user, params, type_override, intentional)
|
|
. = ..()
|
|
var/kiss_type = /obj/item/hand_item/kisser
|
|
|
|
if(HAS_TRAIT(user, TRAIT_GARLIC_BREATH))
|
|
kiss_type = /obj/item/hand_item/kisser/french
|
|
|
|
if(HAS_TRAIT(user, TRAIT_CHEF_KISS))
|
|
kiss_type = /obj/item/hand_item/kisser/chef
|
|
|
|
if(HAS_TRAIT(user, TRAIT_SYNDIE_KISS))
|
|
kiss_type = /obj/item/hand_item/kisser/syndie
|
|
|
|
if(HAS_TRAIT(user, TRAIT_KISS_OF_DEATH))
|
|
kiss_type = /obj/item/hand_item/kisser/death
|
|
|
|
var/datum/action/cooldown/ink_spit/ink_action = locate() in user.actions
|
|
if(ink_action?.IsAvailable())
|
|
kiss_type = /obj/item/hand_item/kisser/ink
|
|
else
|
|
ink_action = null
|
|
|
|
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."))
|
|
ink_action?.StartCooldown()
|
|
return
|
|
|
|
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
|
|
specific_emote_audio_cooldown = 8 SECONDS
|
|
vary = TRUE
|
|
|
|
/datum/emote/living/laugh/can_run_emote(mob/living/user, status_check = TRUE , intentional, params)
|
|
return ..() && user.can_speak(allow_mimes = TRUE)
|
|
|
|
/datum/emote/living/laugh/get_sound(mob/living/carbon/human/user)
|
|
if(!istype(user))
|
|
return
|
|
return user.dna.species.get_laugh_sound(user)
|
|
|
|
/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."
|
|
cooldown = 1 SECONDS
|
|
// don't put hands use check here, everything is handled in run_emote
|
|
|
|
/datum/emote/living/point/run_emote(mob/user, params, type_override, intentional)
|
|
message_param = initial(message_param) // reset
|
|
if(iscarbon(user))
|
|
var/mob/living/carbon/our_carbon = user
|
|
if(our_carbon.usable_hands <= 0 || user.incapacitated & INCAPABLE_RESTRAINTS || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED))
|
|
if(our_carbon.usable_legs > 0)
|
|
var/one_leg = FALSE
|
|
var/has_shoes = our_carbon.get_item_by_slot(ITEM_SLOT_FEET)
|
|
if(our_carbon.usable_legs == 1)
|
|
one_leg = TRUE
|
|
var/success_prob = 65
|
|
if(HAS_TRAIT(our_carbon, TRAIT_FREERUNNING))
|
|
success_prob += 35
|
|
if(one_leg)
|
|
success_prob -= 40
|
|
if(prob(success_prob))
|
|
message_param = "[one_leg ? "jumps into the air and " : ""]points at %t with their [has_shoes ? "leg" : "toes"]!"
|
|
else
|
|
message_param = "[one_leg ? "jumps into the air and " : ""]tries to point at %t with their [has_shoes ? "leg" : "toes"], falling down in the process!"
|
|
our_carbon.Paralyze(2 SECONDS)
|
|
TIMER_COOLDOWN_START(user, "point_verb_emote_cooldown", 1 SECONDS)
|
|
else
|
|
if(our_carbon.get_organ_slot(ORGAN_SLOT_EYES))
|
|
message_param = "gives a meaningful glance at %t!"
|
|
TIMER_COOLDOWN_START(src, "point_verb_emote_cooldown", 1.5 SECONDS)
|
|
else
|
|
if(our_carbon.get_organ_slot(ORGAN_SLOT_TONGUE))
|
|
message_param = "motions their tongue towards %t!"
|
|
TIMER_COOLDOWN_START(src, "point_verb_emote_cooldown", 2 SECONDS)
|
|
else
|
|
message_param = "[span_userdanger("bumps [user.p_their()] head on the ground")] trying to motion towards %t."
|
|
our_carbon.adjust_organ_loss(ORGAN_SLOT_BRAIN, 5)
|
|
playsound(user, 'sound/effects/glass/glassbash.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
|
TIMER_COOLDOWN_START(src, "point_verb_emote_cooldown", 2.5 SECONDS)
|
|
return ..()
|
|
|
|
/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
|
|
vary = TRUE
|
|
|
|
/datum/emote/living/sneeze/get_sound(mob/living/carbon/human/user)
|
|
if(!istype(user))
|
|
return
|
|
return user.dna.species.get_sneeze_sound(user)
|
|
|
|
/datum/emote/living/cough
|
|
key = "cough"
|
|
key_third_person = "coughs"
|
|
message = "coughs!"
|
|
message_mime = "acts out an exaggerated cough!"
|
|
vary = TRUE
|
|
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE | EMOTE_RUNECHAT
|
|
|
|
/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional, params)
|
|
return !HAS_TRAIT(user, TRAIT_SOOTHED_THROAT) && ..()
|
|
|
|
/datum/emote/living/cough/get_sound(mob/living/carbon/human/user)
|
|
if(!istype(user))
|
|
return
|
|
return user.dna.species.get_cough_sound(user)
|
|
|
|
/datum/emote/living/wheeze
|
|
key = "wheeze"
|
|
key_third_person = "wheezes"
|
|
message = "wheezes!"
|
|
emote_type = EMOTE_AUDIBLE
|
|
|
|
/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/brain)
|
|
sound_wall_ignore = TRUE
|
|
specific_emote_audio_cooldown = 10 SECONDS
|
|
vary = TRUE
|
|
|
|
/datum/emote/living/scream/run_emote(mob/user, params, type_override, intentional = FALSE)
|
|
if(!intentional && HAS_TRAIT(user, TRAIT_ANALGESIA))
|
|
return
|
|
return ..()
|
|
|
|
/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/scream/get_sound(mob/living/user)
|
|
if(!ishuman(user))
|
|
return
|
|
var/mob/living/carbon/human/humie = user
|
|
return humie.dna.species.get_scream_sound(user)
|
|
|
|
/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)
|
|
. = ..()
|
|
|
|
animate(user, pixel_w = 1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
|
|
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_w = -2, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE)
|
|
animate(pixel_w = 2, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE)
|
|
animate(pixel_w = -1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE)
|
|
#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
|
|
vary = TRUE
|
|
|
|
/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/sigh/get_sound(mob/living/carbon/human/user)
|
|
if(!istype(user))
|
|
return
|
|
return user.dna.species.get_sigh_sound(user)
|
|
|
|
/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/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
|
|
vary = TRUE
|
|
|
|
/datum/emote/living/sniff/get_sound(mob/living/carbon/human/user)
|
|
if(!istype(user))
|
|
return
|
|
return user.dna.species.get_sniff_sound(user)
|
|
|
|
/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
|
|
|
|
// eventually we want to give species their own "snoring" sounds
|
|
/datum/emote/living/snore/get_sound(mob/living/carbon/human/user)
|
|
if(!istype(user))
|
|
return
|
|
return user.dna.species.get_snore_sound(user)
|
|
|
|
/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/living = user
|
|
living.Paralyze(20 SECONDS)
|
|
living.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)
|
|
. = ..()
|
|
|
|
animate(user, pixel_w = 2, time = 0.5 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
|
|
for(var/i in 1 to 2)
|
|
animate(pixel_w = -6, time = 1.0 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE)
|
|
animate(pixel_w = 6, time = 1.0 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE)
|
|
animate(pixel_w = -2, time = 0.5 SECONDS, flags = ANIMATION_RELATIVE)
|
|
|
|
/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!"
|
|
|
|
#define TREMBLE_LOOP_DURATION (4.4 SECONDS)
|
|
/datum/emote/living/tremble/run_emote(mob/living/user, params, type_override, intentional)
|
|
. = ..()
|
|
|
|
animate(user, pixel_w = 2, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
|
|
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_w = -4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE)
|
|
animate(pixel_w = 4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE)
|
|
animate(pixel_w = -2, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE)
|
|
#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)
|
|
. = ..()
|
|
|
|
animate(user, pixel_w = 1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
|
|
animate(pixel_w = -2, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE)
|
|
animate(time = 0.1 SECONDS)
|
|
animate(pixel_w = 2, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE)
|
|
animate(pixel_w = -1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE)
|
|
|
|
/datum/emote/living/twitch_s
|
|
key = "twitch_s"
|
|
name = "twitch (Slight)"
|
|
message = "twitches."
|
|
|
|
/datum/emote/living/twitch_s/run_emote(mob/living/user, params, type_override, intentional)
|
|
. = ..()
|
|
|
|
animate(user, pixel_w = -1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
|
|
animate(pixel_w = 1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE)
|
|
|
|
/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"
|
|
name = "smile (Weak)"
|
|
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 20
|
|
/// The amount the base chance to propagate yawns falls for each tile of distance
|
|
#define YAWN_PROPAGATE_CHANCE_DECAY 4
|
|
|
|
/datum/emote/living/yawn
|
|
key = "yawn"
|
|
key_third_person = "yawns"
|
|
message = "yawns."
|
|
message_mime = "acts out an exaggerated silent yawn."
|
|
message_robot = "symphathetically yawns."
|
|
message_AI = "symphathetically yawns."
|
|
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_FINISHED(user, COOLDOWN_YAWN_PROPAGATION))
|
|
TIMER_COOLDOWN_START(user, COOLDOWN_YAWN_PROPAGATION, cooldown * 3)
|
|
|
|
var/mob/living/carbon/carbon_user = user
|
|
if(carbon_user.obscured_slots & 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_RUNNING(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_RUNNING(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"
|
|
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
|
|
message = null
|
|
|
|
/datum/emote/living/custom/can_run_emote(mob/user, status_check, intentional, params)
|
|
. = ..()
|
|
if(!. || !intentional)
|
|
return FALSE
|
|
|
|
if(!isnull(user.ckey) && 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
|
|
|
|
/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, LOWER_TEXT(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, LOWER_TEXT(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: \"[html_encode(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, LOWER_TEXT(config.soft_ic_filter_regex.match))
|
|
log_filter("Soft IC Emote (Passed)", input, filter_result)
|
|
|
|
return TRUE
|
|
|
|
/datum/emote/living/custom/get_message_flags(intentional)
|
|
. = ..()
|
|
return .|WITH_EMPHASIS_MESSAGE
|
|
|
|
/datum/emote/living/custom/proc/get_custom_emote_from_user()
|
|
return stripped_multiline_input(usr, "Choose an emote to display.", "Me" , null, MAX_MESSAGE_LEN) // SKYRAT EDIT CHANGE - ORIGINAL : 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", "Both")
|
|
|
|
switch(type)
|
|
if("Visible")
|
|
return EMOTE_VISIBLE
|
|
if("Hearable")
|
|
return EMOTE_AUDIBLE
|
|
if("Both")
|
|
return EMOTE_VISIBLE | 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)
|
|
var/our_message = params ? params : get_custom_emote_from_user()
|
|
|
|
if(!emote_is_valid(user, our_message))
|
|
return FALSE
|
|
|
|
if(!params)
|
|
var/user_emote_type = get_custom_emote_type_from_user()
|
|
|
|
if(!user_emote_type)
|
|
return FALSE
|
|
|
|
type_override = user_emote_type
|
|
|
|
. = ..(user = user, params = our_message, type_override = type_override, intentional = intentional)
|
|
|
|
/datum/emote/living/custom/replace_pronoun(mob/user, message)
|
|
return message
|
|
|
|
/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
|
|
|
|
/datum/emote/living/carbon/whistle
|
|
key = "whistle"
|
|
key_third_person = "whistles"
|
|
message = "whistles."
|
|
message_mime = "whistles silently!"
|
|
vary = TRUE
|
|
emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE
|
|
|
|
/datum/emote/living/carbon/whistle/get_sound(mob/living/user)
|
|
return 'sound/mobs/humanoids/human/whistle/whistle1.ogg'
|
|
|
|
/datum/emote/living/gulp
|
|
key = "gulp"
|
|
key_third_person = "gulps"
|
|
message = "gulps nervously."
|
|
message_mime = "gulps silently!"
|
|
vary = TRUE
|
|
emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE
|
|
|
|
/datum/emote/living/gulp/get_sound(mob/living/user)
|
|
return pick('sound/mobs/humanoids/human/gulp/gulp1.ogg',
|
|
'sound/mobs/humanoids/human/gulp/gulp2.ogg')
|