mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-24 12:37:26 +01:00
Datumized Emotes (#17544)
* Add raw tg emote datums * Some more initial implementation * First (big) commit * More reworks, most emotes seem to work but cooldowns are weird * Add the remaining emote species * Add simple mobs * Update defines, add more comments * Remove unnecessary intentional calls * Fix some bugs, add more functionality - Silicon mobs/bots can't use all the living emotes - Sound volume can now be specified for emotes - Added a define for emotes to not go thru runechat - Reorganized some emotes - Some human emotes that need breath will gasp - IPCs can beep boop - Restore power warn for robits - Sneezing and coughing have sound effects * Fixes emote species separation not working in *help * Reorganize emotes based on what's available on paradise * mouthful mode * Update implants to use emote signals * Update species whitelist to use a typecache * Cleanups * More small changes - Remove old extraneous typecache - Reconfigure drask emotes - Make all mime emotes visible (since they're silent) * Remove old emote functions * Update emote sounds, volume * Rework more emotes into EMOTE_VISIBLE * *rumble* * More slight testing and cleanup - Drop audio emote cooldown from 10 to 5 seconds - Change clapping behaivor slightly, putting it into run_emote - Update some emote flags here and there - Fix up johnny, though remind me why this one exists? * Fix indentation, missing typecast * fix some returns * More review * Rename emote files * Add'l review * Even more emote fixes! - Move defines out into an emote define file - Integrate audio and general emote cooldowns - change some 1 and 2 into visible/audible - Try to fix monkey screech * Add ability for admins to mute users' emotes. * Rename cooldowns, add general mob emote cooldown. * Fix flip not always geting the right message * Add some emote target handling, docs * Fix admin rights, indentation * Update emote.dm set default mode to ANY * General implant fixes - The way implant triggers are handled is now improved, with separate checks for death and emotes instead of just checking deathgasp. - Implants can choose to be triggered for the first death or for every death. - Voice of God play dead now activates sad trombone read: voice of god can now no longer lowtiergod nukies * Bunch of other changes and bugfixes - Adds number flag for behavior - Reworks how muzzling/vocalizing emotes works - Breaks out sound effects - Drops cooldown to 1.5s * Fix people being able to snore/nightmare while awake. * Bump paralysis on living emotes * First review pass * Clean up implants (while we're here) and fix compile errors * in living error * More outstanding review fixes * use more isx() checks * Add pre-emote signal, try_run_emote() * Prevent silicons from playing their deathgasp multiple times * Add emote postfix behavior for adding parameters to non-message params. Also adds a signal to intercept emote actions. * Fix linter complaints * Remove new player checks on GLOB.dead_mob_list * Fix species emotes not being distinguished, remove weird legacy code * monkey ball * better docs == better code * Fix audio cooldown, silicon emotes * Fix ghost emotes (don't worry they're staying) * Restore spin to 2 seconds * oh johnny boy * Make fainting last two seconds instead of .2 seconds * Remove extra highfive message * Tick friendly emotes * Fix up friendly emotes, ghost emotes * Add some emote message safeguards, prevent flip from showing twice * Fix ghost vision message format * Fix hands_use_check on non-carbon mobs * Bring emotes in line with say re. oxyloss * Add option for death implants to not trigger on gib * Try adding some unit testing * Include emote unit tests * More attempts at unit testing * More attempts at unit testing? * forget it this is fine * Housekeeping * Little bit more * Remove extra bolding from ghostsight emotes * More sanity checks, fix snore * Remove stack trace when unintentional emote fails * Update code/modules/mob/living/silicon/silicon_emote.dm oops Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> * More implant cleanups * Oh I missed this * Silence wagging, more review fixes * Oops 2 * ensure everything can swear * High-five fixes and status effect stuff - Adds new on_timeout() function that gets triggered when a status effect expires - Fixes up passing arguments to status effects - Ensures high-five explosions don't kill the wizards * More review stuff - Add a stat to text to make things easier - Make it harder to delete emotes - BIG DANGER - pose can no longer be set while unconscious * Remove extra high five logic, godmode changes * forgor * Fix gasp not working * Update docs for good measure * Some review and custom emote fixes * Fixes death alarms being broken * Better handle stat_allowed, more review comments. * ..() conventions * This is why unit tests are nice * Remove drone snowflake emote stuff * Linting * No more flipping on the ground * Snap doesn't require hands free * Does it make complete sense? no, but it's Fun * Apply suggestions from code review Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> * Fix revenant messages, power warning * epic webedit fail, laugh at this user Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
#define MUTE_PRAY 4
|
||||
#define MUTE_ADMINHELP 8
|
||||
#define MUTE_DEADCHAT 16
|
||||
#define MUTE_ALL 31
|
||||
#define MUTE_EMOTE 32
|
||||
#define MUTE_ALL 63
|
||||
|
||||
//Number of identical messages required to get the spam-prevention automute thing to trigger warnings and automutes
|
||||
#define SPAM_TRIGGER_WARNING 5
|
||||
|
||||
@@ -335,12 +335,31 @@
|
||||
///from /mob/say_dead(): (mob/speaker, message)
|
||||
#define COMSIG_MOB_DEADSAY "mob_deadsay"
|
||||
#define MOB_DEADSAY_SIGNAL_INTERCEPT (1<<0)
|
||||
///from /mob/living/emote(): ()
|
||||
|
||||
/// Signal fired when an emote is used but before it's executed.
|
||||
///from /datum/emote/proc/try_run_emote(): (key, intentional)
|
||||
#define COMSIG_MOB_PREEMOTE "mob_preemote"
|
||||
// Use these to block execution of emotes from components.
|
||||
/// Return this to block an emote and let the user know the emote is unusable.
|
||||
#define COMPONENT_BLOCK_EMOTE_UNUSABLE (1<<0)
|
||||
/// Return this to block an emote silently.
|
||||
#define COMPONENT_BLOCK_EMOTE_SILENT (1<<1)
|
||||
/// General signal fired when a mob does any old emote
|
||||
///from /datum/emote/proc/run_emote(): (key, intentional)
|
||||
#define COMSIG_MOB_EMOTE "mob_emote"
|
||||
/// Specific signal used to track when a specific emote is used.
|
||||
/// From /datum/emote/run_emote(): (P, key, m_type, message, intentional)
|
||||
#define COMSIG_MOB_EMOTED(emote_key) "mob_emoted_[emote_key]"
|
||||
/// From /datum/emote/select_param(): (target, key, intentional)
|
||||
#define COMSIG_MOB_EMOTE_AT "mob_emote_at"
|
||||
#define COMPONENT_BLOCK_EMOTE_ACTION (1<<2)
|
||||
|
||||
///from base of mob/swap_hand(): (obj/item)
|
||||
#define COMSIG_MOB_SWAP_HANDS "mob_swap_hands"
|
||||
#define COMPONENT_BLOCK_SWAP (1<<0)
|
||||
|
||||
|
||||
|
||||
// /mob/living signals
|
||||
|
||||
///from base of mob/living/resist() (/mob/living)
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* General defines used for emotes
|
||||
*/
|
||||
|
||||
// Emote types.
|
||||
// These determine how the emote is treated when not directly visible (or audible).
|
||||
// These are also used in some cases for visible/audible messages.
|
||||
|
||||
/// Emote is visible. These emotes will be runechatted.
|
||||
#define EMOTE_VISIBLE (1<<0)
|
||||
/// Emote is audible (in character).
|
||||
#define EMOTE_AUDIBLE (1<<1)
|
||||
/// Emote makes a sound. These emotes will specifically not be runechatted.
|
||||
#define EMOTE_SOUND (1<<2)
|
||||
/// Regardless of its existing flags, an emote with this flag will not be sent to runechat.
|
||||
#define EMOTE_FORCE_NO_RUNECHAT (1<<3)
|
||||
/// This emote uses the mouth, and so should be blocked if the user is muzzled or can't breathe (for humans).
|
||||
#define EMOTE_MOUTH (1<<4)
|
||||
|
||||
// User audio cooldown system.
|
||||
// This is a value stored on the user and represents their current ability to perform audio emotes.
|
||||
|
||||
/// The user is not on emote cooldown, and is ready to emote whenever.
|
||||
#define EMOTE_READY 0
|
||||
/// The user can spam emotes to their heart's content.
|
||||
#define EMOTE_INFINITE 1
|
||||
/// The user cannot emote as they have been blocked by an admin.
|
||||
#define EMOTE_ADMIN_BLOCKED 2
|
||||
/// The user cannot emote until their cooldown expires.
|
||||
#define EMOTE_ON_COOLDOWN 3
|
||||
|
||||
/// Marker to separate an emote key from its parameters in user input.
|
||||
#define EMOTE_PARAM_SEPARATOR "-"
|
||||
|
||||
/// Default cooldown for normal (non-audio) emotes.
|
||||
#define DEFAULT_EMOTE_COOLDOWN (1.5 SECONDS)
|
||||
|
||||
// Each mob can only play an emote with audio every AUDIO_EMOTE_COOLDOWN seconds, unless a given emote overrides its own audio cooldown.
|
||||
|
||||
/// Default cooldown for audio that comes from emotes.
|
||||
#define AUDIO_EMOTE_COOLDOWN (5 SECONDS)
|
||||
|
||||
// Emote parameter types
|
||||
// If nothing is passed in for a target, this can determine the possible target.
|
||||
|
||||
// Our emote code will search around the user to find a matching target to use, based on the second set of defines.
|
||||
// This first set of defines denotes the behavior if a match can't be found.
|
||||
|
||||
/// If this is set and a valid target is not found, the emote will not execute.
|
||||
#define EMOTE_TARGET_BHVR_MUST_MATCH 1
|
||||
/// If this is set and a valid target is not found, the emote will just ignore the parameter entirely.
|
||||
#define EMOTE_TARGET_BHVR_DEFAULT_TO_BASE 2
|
||||
/// If this is set and a valid target is not found, the emote will work with the params that it has.
|
||||
#define EMOTE_TARGET_BHVR_USE_PARAMS_ANYWAY 3
|
||||
/// No matching/processing will be performed, and the target will be purely what's passed in.
|
||||
#define EMOTE_TARGET_BHVR_RAW 4
|
||||
/// The emote target should be just a number. Anything else will be rejected.
|
||||
#define EMOTE_TARGET_BHVR_NUM 5
|
||||
|
||||
// This set determines the type of target that we want to check for.
|
||||
|
||||
/// The target will check all nearby living mobs.
|
||||
#define EMOTE_TARGET_MOB (1<<0)
|
||||
/// The target will check all objects nearby.
|
||||
#define EMOTE_TARGET_OBJ (1<<1)
|
||||
/// The target will check nearby mobs and objects.
|
||||
#define EMOTE_TARGET_ANY (EMOTE_TARGET_MOB | EMOTE_TARGET_OBJ)
|
||||
|
||||
/// If passed as message_param, will default to using the message's postfix.
|
||||
#define EMOTE_PARAM_USE_POSTFIX 1
|
||||
|
||||
/// If returned from act_on_target(), emote execution will stop.
|
||||
#define EMOTE_ACT_STOP_EXECUTION 1
|
||||
@@ -191,9 +191,6 @@
|
||||
#define TINT_BLIND 3 //Threshold of tint level to obscure vision fully
|
||||
#define EYE_SHINE_THRESHOLD 6 //dark_view threshold past which a humanoid's eyes will 'shine' in the dark.
|
||||
|
||||
#define EMOTE_VISUAL 1 //A mob emote is visual
|
||||
#define EMOTE_SOUND 2 //A mob emote is sound
|
||||
|
||||
#define STATUS_UPDATE_HEALTH 1
|
||||
#define STATUS_UPDATE_STAT 2
|
||||
#define STATUS_UPDATE_STAMINA 8
|
||||
|
||||
@@ -164,6 +164,8 @@
|
||||
|
||||
GLOB.karma_packages[KP.database_id] = KP
|
||||
|
||||
GLOB.emote_list = init_emote_list()
|
||||
|
||||
|
||||
/* // Uncomment to debug chemical reaction list.
|
||||
/client/verb/debug_chemical_list()
|
||||
@@ -197,3 +199,22 @@
|
||||
if(assoc) //value gotten
|
||||
L["[assoc]"] = D //put in association
|
||||
return L
|
||||
|
||||
|
||||
/proc/init_emote_list()
|
||||
. = list()
|
||||
for(var/path in subtypesof(/datum/emote))
|
||||
var/datum/emote/E = new path()
|
||||
if(E.key)
|
||||
if(!.[E.key])
|
||||
.[E.key] = list(E)
|
||||
else
|
||||
.[E.key] += E
|
||||
else if(E.message) //Assuming all non-base emotes have this
|
||||
stack_trace("Keyless emote: [E.type]")
|
||||
|
||||
if(E.key_third_person) //This one is optional
|
||||
if(!.[E.key_third_person])
|
||||
.[E.key_third_person] = list(E)
|
||||
else
|
||||
.[E.key_third_person] |= E
|
||||
|
||||
@@ -167,6 +167,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
#define TRAIT_MESON_VISION "meson_vision"
|
||||
#define TRAIT_FLASH_PROTECTION "flash_protection"
|
||||
#define TRAIT_NIGHT_VISION "night_vision"
|
||||
#define TRAIT_EMOTE_MUTE "emote_mute"
|
||||
|
||||
#define TRAIT_NO_BONES "no_bones"
|
||||
#define TRAIT_STURDY_LIMBS "sturdy_limbs"
|
||||
|
||||
@@ -33,3 +33,5 @@ GLOBAL_LIST_EMPTY(sec_hud_users)
|
||||
GLOBAL_LIST_EMPTY(antag_hud_users)
|
||||
GLOBAL_LIST_EMPTY(surgeries_list)
|
||||
GLOBAL_LIST_EMPTY(hear_radio_list) //Mobs that hear the radio even if there's no client
|
||||
|
||||
GLOBAL_LIST_EMPTY(emote_list)
|
||||
|
||||
@@ -65,6 +65,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_NOEXAMINE" = TRAIT_NOEXAMINE,
|
||||
"TRAIT_NOPAIN" = TRAIT_NOPAIN,
|
||||
"TRAIT_FORCE_DOORS" = TRAIT_FORCE_DOORS,
|
||||
"TRAIT_EMOTE_MUTE" = TRAIT_EMOTE_MUTE,
|
||||
),
|
||||
/obj/item = list(
|
||||
"TRAIT_SHOW_WIRE_INFO" = TRAIT_SHOW_WIRE_INFO,
|
||||
|
||||
@@ -0,0 +1,620 @@
|
||||
|
||||
// Defines are in code\__DEFINES\emotes.dm
|
||||
|
||||
/// Sentinel for emote stats.
|
||||
/// If this is set for max stat, then its value will be ignored.
|
||||
#define DEFAULT_MAX_STAT_ALLOWED "defaultstat"
|
||||
|
||||
/**
|
||||
* # Emote
|
||||
*
|
||||
* Most of the text that's not someone talking is based off of this.
|
||||
*
|
||||
*/
|
||||
/datum/emote
|
||||
/// What calls the emote.
|
||||
var/key = ""
|
||||
/// This will also call the emote.
|
||||
var/key_third_person = ""
|
||||
/// Message displayed when emote is used.
|
||||
var/message = ""
|
||||
/// Message displayed if the user is a mime.
|
||||
var/message_mime = ""
|
||||
/// Message displayed if the user is a grown alien.
|
||||
var/message_alien = ""
|
||||
/// Message displayed if the user is an alien larva.
|
||||
var/message_larva = ""
|
||||
/// Message displayed if the user is a robot.
|
||||
var/message_robot = ""
|
||||
/// Message displayed if the user is an AI.
|
||||
var/message_AI = ""
|
||||
/// Message displayed if the user is a monkey.
|
||||
var/message_monkey = ""
|
||||
/// Message to display if the user is a simple_animal.
|
||||
var/message_simple = ""
|
||||
/// Message to display if the user is a spooky observer ghost.
|
||||
var/message_observer = ""
|
||||
/// Sounds emitted when the user is muzzled. Generally used like "[user] makes a pick(muzzled_noises) noise!"
|
||||
var/muzzled_noises = list("strong", "weak")
|
||||
/// Message with %t at the end to allow adding params to the message, like for mobs doing an emote relatively to something else.
|
||||
/// Set this to EMOTE_PARAM_USE_POSTFIX to just use the postfix.
|
||||
var/message_param = ""
|
||||
/// Message postfix with %t used when we don't want to use message_param for our targeting. Used for things like message_monkey or message_mime.
|
||||
/// Punctuation from the message will be stripped when this is applied, so make sure it's punctuated as well.
|
||||
var/message_postfix = ""
|
||||
/// Description appended to the emote name describing what the target should be, like for help commands.
|
||||
var/param_desc = "target"
|
||||
/// Whether the emote is visible or audible.
|
||||
var/emote_type = EMOTE_VISIBLE
|
||||
/// Checks if the mob can use its hands before performing the emote.
|
||||
var/hands_use_check = FALSE
|
||||
/// If the emote type is EMOTE_MOUTH but should still bypass a muzzle.
|
||||
var/muzzle_ignore = FALSE
|
||||
/// Types that are allowed to use that emote.
|
||||
var/list/mob_type_allowed_typecache = /mob
|
||||
/// Types that are NOT allowed to use that emote.
|
||||
var/list/mob_type_blacklist_typecache
|
||||
/// Types that can use this emote regardless of their state.
|
||||
var/list/mob_type_ignore_stat_typecache
|
||||
/// Species types which the emote will be exclusively available to. Should be subclasses of /datum/species
|
||||
var/species_type_whitelist_typecache
|
||||
/// If we get a target, how do we want to treat it?
|
||||
var/target_behavior = EMOTE_TARGET_BHVR_USE_PARAMS_ANYWAY
|
||||
/// If our target behavior isn't to ignore, what should we look for with targets?
|
||||
var/emote_target_type = EMOTE_TARGET_ANY
|
||||
|
||||
// Stat_allowed is the "lower threshold" for stat, and basically represents how alive you have to be to use it.
|
||||
// on the other hand, max_stat_allowed is the "upper threshold" representing how 'dead' you can be while still using the emote.
|
||||
// see stat.dm for the stats that you can actually use here.
|
||||
|
||||
// Typical use case might be setting unintentional_stat_allowed to UNCONSCIOUS to allow a mob to gasp whether or not they're conscious.
|
||||
// A use case for max_stat alone would be in case you'd want someone to be able to do something while unconscious or dead. Unlikely, but the option will still be there.
|
||||
// A use case for both at once would be fixing it somewhere in the middle, like only allowing mobs to snore while they're unconscious.
|
||||
|
||||
// (worth noting: this is flexible on purpose in case we ever increase the amount of life stats).
|
||||
|
||||
/// How conscious do you need to be to use this emote intentionally?
|
||||
var/stat_allowed = CONSCIOUS
|
||||
/// How unconscious/dead can you be while still being able to use this emote intentionally?
|
||||
/// If this is set to DEFAULT_STAT_ALLOWED, it'll behave as if it isn't set.
|
||||
var/max_stat_allowed = DEFAULT_MAX_STAT_ALLOWED
|
||||
/// How conscious do you need to be to have this emote forced out of you?
|
||||
var/unintentional_stat_allowed = CONSCIOUS
|
||||
/// Same as above, how unconscious/dead do you need to be to have this emote forced out of you?
|
||||
/// If this is set to DEFAULT_STAT_ALLOWED, it'll behave as if it isn't set.
|
||||
var/max_unintentional_stat_allowed = DEFAULT_MAX_STAT_ALLOWED
|
||||
/// Sound to play when emote is called. If you want to adjust this dynamically, see get_sound().
|
||||
var/sound
|
||||
/// Whether or not to vary the sound of the emote.
|
||||
var/vary = FALSE
|
||||
/// Whether or not to adjust the frequency of the emote sound based on age.
|
||||
var/age_based = FALSE
|
||||
/// If true, this emote will only make a sound effect when called unintentionally.
|
||||
var/only_forced_audio = FALSE
|
||||
/// Whether or not the emote can even be called at all if it's not intentional
|
||||
var/only_unintentional = FALSE
|
||||
/// The cooldown between the uses of the emote.
|
||||
var/cooldown = DEFAULT_EMOTE_COOLDOWN
|
||||
/// How long is the cooldown on the audio of the emote, if it has one?
|
||||
var/audio_cooldown = AUDIO_EMOTE_COOLDOWN
|
||||
/// How loud is the audio emote?
|
||||
var/volume = 50
|
||||
|
||||
/datum/emote/New()
|
||||
if(message_param && !param_desc)
|
||||
CRASH("emote [src] was given a message parameter without a description.")
|
||||
if(ispath(mob_type_allowed_typecache))
|
||||
switch(mob_type_allowed_typecache)
|
||||
if(/mob)
|
||||
mob_type_allowed_typecache = GLOB.typecache_mob
|
||||
if(/mob/living)
|
||||
mob_type_allowed_typecache = GLOB.typecache_living
|
||||
else
|
||||
mob_type_allowed_typecache = typecacheof(mob_type_allowed_typecache)
|
||||
else
|
||||
mob_type_allowed_typecache = typecacheof(mob_type_allowed_typecache)
|
||||
mob_type_blacklist_typecache = typecacheof(mob_type_blacklist_typecache)
|
||||
mob_type_ignore_stat_typecache = typecacheof(mob_type_ignore_stat_typecache)
|
||||
species_type_whitelist_typecache = typecacheof(species_type_whitelist_typecache)
|
||||
|
||||
/datum/emote/Destroy(force)
|
||||
if(force)
|
||||
return ..()
|
||||
else
|
||||
// if you're deleting an emote something has gone wrong
|
||||
return QDEL_HINT_LETMELIVE
|
||||
|
||||
/**
|
||||
* Handles the modifications and execution of emotes.
|
||||
*
|
||||
* In general, what this does:
|
||||
* - Checks if the user can run the emote at all
|
||||
* - Checks and applies the message parameter, if it exists
|
||||
* - Replaces pronouns with a mob's specific pronouns
|
||||
* - Checks for and plays sound if the emote supports it
|
||||
* - Sends the emote to users
|
||||
* - Runechats the emote
|
||||
*
|
||||
* You most likely want to use try_run_emote() anywhere you would otherwise call this directly,
|
||||
* as that will incorporate can_run_emote() checking as well.
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* Returns TRUE if it was able to run the emote, FALSE otherwise.
|
||||
*/
|
||||
/datum/emote/proc/run_emote(mob/user, params, type_override, intentional = FALSE)
|
||||
. = TRUE
|
||||
var/msg = select_message_type(user, message, intentional)
|
||||
if(params && message_param)
|
||||
// In this case, we did make some changes to the message that will be used, and we want to add the postfix on with the new parameters.
|
||||
// This is applicable to things like mimes, who this lets have a target on their canned emote responses.
|
||||
// Note that we only do this if we would otherwise have a message param, meaning there should be some target by default.
|
||||
// If we're using EMOTE_PARAM_USE_POSTFIX, we don't want to bother specifying a message_param and just want to use the postfix for everything.
|
||||
if(message_param == EMOTE_PARAM_USE_POSTFIX || (msg != message && message_postfix))
|
||||
if(!message_postfix)
|
||||
CRASH("Emote was specified to use postfix but message_postfix is empty.")
|
||||
msg = select_param(user, params, "[remove_ending_punctuation(msg)] [message_postfix]", msg)
|
||||
else if(msg == message)
|
||||
// In this case, we're not making any substitutions in select_message_type, but we do have some params we want to sub in.
|
||||
msg = select_param(user, params, message_param, message)
|
||||
|
||||
// If this got propogated up, jump out.
|
||||
if(msg == EMOTE_ACT_STOP_EXECUTION)
|
||||
return TRUE
|
||||
|
||||
if(isnull(msg))
|
||||
to_chat(user, "<span class='warning'>'[params]' isn't a valid parameter for [key].</span>")
|
||||
return TRUE
|
||||
|
||||
msg = replace_pronoun(user, msg)
|
||||
|
||||
var/suppressed = FALSE
|
||||
|
||||
// Keep em quiet if they can't speak
|
||||
if(!can_vocalize_emotes(user) && (emote_type & (EMOTE_MOUTH | EMOTE_AUDIBLE) || emote_type & (EMOTE_MOUTH | EMOTE_SOUND)))
|
||||
var/noise_emitted = pick(muzzled_noises)
|
||||
suppressed = TRUE
|
||||
msg = "makes \a [noise_emitted] noise."
|
||||
|
||||
var/tmp_sound = get_sound(user)
|
||||
var/sound_volume = get_volume(user)
|
||||
// If our sound emote is forced by code, don't worry about cooldowns at all.
|
||||
if(tmp_sound && should_play_sound(user, intentional) && sound_volume > 0)
|
||||
if(!intentional || user.start_audio_emote_cooldown(audio_cooldown))
|
||||
play_sound_effect(user, intentional, tmp_sound, sound_volume)
|
||||
|
||||
if(msg)
|
||||
if(isobserver(user))
|
||||
log_ghostemote(msg, user)
|
||||
else
|
||||
log_emote(msg, user)
|
||||
|
||||
var/displayed_msg = "<b>[user]</b> [msg]"
|
||||
|
||||
var/user_turf = get_turf(user)
|
||||
if(user.client && !isobserver(user))
|
||||
for(var/mob/ghost as anything in GLOB.dead_mob_list)
|
||||
if(!ghost.client)
|
||||
continue
|
||||
if((ghost.client.prefs.toggles & PREFTOGGLE_CHAT_GHOSTSIGHT) && !(ghost in viewers(user_turf, null)))
|
||||
ghost.show_message("<span class='emote'>[user] ([ghost_follow_link(user, ghost)]) [msg]</span>")
|
||||
|
||||
if(isobserver(user))
|
||||
for(var/mob/dead/observer/ghost in viewers(user))
|
||||
ghost.show_message("<span class=deadsay>[displayed_msg]</span>", EMOTE_VISIBLE)
|
||||
|
||||
else if(emote_type & EMOTE_VISIBLE || user.mind?.miming)
|
||||
user.audible_message(displayed_msg, deaf_message = "<span class='emote'>You see how <b>[user]</b> [msg]</span>")
|
||||
else
|
||||
user.visible_message(displayed_msg, blind_message = "<span class='emote'>You hear how <b>[user]</b> [msg]</span>")
|
||||
|
||||
if(!(emote_type & (EMOTE_FORCE_NO_RUNECHAT | EMOTE_SOUND) || suppressed) && !isobserver(user))
|
||||
runechat_emote(user, msg)
|
||||
|
||||
SEND_SIGNAL(user, COMSIG_MOB_EMOTED(key), src, key, emote_type, message, intentional)
|
||||
SEND_SIGNAL(user, COMSIG_MOB_EMOTE, key, intentional)
|
||||
|
||||
/**
|
||||
* Try to run an emote, checking can_run_emote once before executing the emote itself.
|
||||
*
|
||||
* * user - User of the emote
|
||||
* * params - Params of the emote to be passed to run_emote
|
||||
* * type_override - emote type to override the existing one with, if given.
|
||||
* * intentional - Whether or not the emote was triggered intentionally (if false, the emote was forced by code).
|
||||
*
|
||||
* Returns TRUE if the emote was able to be run (or failed successfully), or FALSE if the emote is unusable.
|
||||
*/
|
||||
/datum/emote/proc/try_run_emote(mob/user, params, type_override, intentional = FALSE)
|
||||
if(!can_run_emote(user, intentional = intentional))
|
||||
return FALSE
|
||||
|
||||
// You can use this signal to block execution of emotes from components/other sources.
|
||||
var/sig_res = SEND_SIGNAL(user, COMSIG_MOB_PREEMOTE, key, intentional)
|
||||
switch(sig_res)
|
||||
if(COMPONENT_BLOCK_EMOTE_UNUSABLE)
|
||||
return FALSE
|
||||
if(COMPONENT_BLOCK_EMOTE_SILENT)
|
||||
return TRUE
|
||||
|
||||
. = run_emote(user, params, type_override, intentional)
|
||||
|
||||
// safeguard in case these get modified
|
||||
message = initial(message)
|
||||
message_param = initial(message_param)
|
||||
|
||||
/**
|
||||
* Play the sound effect in an emote.
|
||||
* If you want to change the way the playsound call works, override this.
|
||||
* * user - The user of the emote.
|
||||
* * intentional - Whether or not the emote was triggered intentionally.
|
||||
* * sound_path - Filesystem path to the audio clip to play.
|
||||
* * sound_volume - Volume at which to play the audio clip.
|
||||
*/
|
||||
/datum/emote/proc/play_sound_effect(mob/user, intentional, sound_path, sound_volume)
|
||||
if(age_based && ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
playsound(user.loc, sound_path, sound_volume, vary, frequency = H.get_age_pitch())
|
||||
else
|
||||
playsound(user.loc, sound_path, sound_volume, vary)
|
||||
|
||||
/**
|
||||
* Send an emote to runechat for all (listening) users in the vicinity.
|
||||
*
|
||||
* * user - The user of the emote.
|
||||
* * text - The text of the emote.
|
||||
*/
|
||||
/datum/emote/proc/runechat_emote(mob/user, text)
|
||||
var/runechat_text = text
|
||||
if(length(text) > 100)
|
||||
runechat_text = "[copytext(text, 1, 101)]..."
|
||||
var/list/can_see = get_mobs_in_view(1, user) //Allows silicon & mmi mobs carried around to see the emotes of the person carrying them around.
|
||||
can_see |= viewers(user, null)
|
||||
for(var/mob/O in can_see)
|
||||
if(O.status_flags & PASSEMOTES)
|
||||
for(var/obj/item/holder/H in O.contents)
|
||||
H.show_message(text, EMOTE_VISIBLE)
|
||||
|
||||
for(var/mob/living/M in O.contents)
|
||||
M.show_message(text, EMOTE_VISIBLE)
|
||||
|
||||
if(O.client?.prefs.toggles2 & PREFTOGGLE_2_RUNECHAT)
|
||||
O.create_chat_message(user, runechat_text, symbol = RUNECHAT_SYMBOL_EMOTE)
|
||||
|
||||
/**
|
||||
* Check whether or not an emote can be used due to a cooldown.
|
||||
* This applies to per-emote cooldowns, preventing individual emotes from being used (intentionally) too frequently.
|
||||
* This also checks audio cooldowns, so that intentional uses of audio emotes across the mob are time-constrained.
|
||||
*
|
||||
* 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 our emote would play sound but another audio emote is on cooldown, prevent this emote from being used.
|
||||
// Note that this only applies to intentional emotes
|
||||
if(get_sound(user) && should_play_sound(user, intentional) && !user.can_use_audio_emote())
|
||||
return FALSE
|
||||
var/cooldown_in_use
|
||||
if(!isnull(user.emote_cooldown_override))
|
||||
// if the user has a a cooldown override in place, apply that instead.
|
||||
cooldown_in_use = user.emote_cooldown_override
|
||||
else
|
||||
cooldown_in_use = cooldown
|
||||
// Check cooldown on a per-emote basis.
|
||||
if(user.emotes_used && user.emotes_used[src] + cooldown_in_use > world.time)
|
||||
return FALSE
|
||||
if(!user.emotes_used)
|
||||
user.emotes_used = list()
|
||||
user.emotes_used[src] = world.time
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* To get the sound that the emote plays, for special sound interactions depending on the mob.
|
||||
*
|
||||
* Arguments:
|
||||
* * user - Person that is trying to send the emote.
|
||||
*
|
||||
* Returns the sound that will be made while sending the emote.
|
||||
*/
|
||||
/datum/emote/proc/get_sound(mob/living/user)
|
||||
return sound //by default just return this var.
|
||||
|
||||
/**
|
||||
* Get the volume of the audio emote to play.
|
||||
*
|
||||
* Override this if you want to dynamically change the volume of an emote.
|
||||
*
|
||||
* Arguments:
|
||||
* * user - Person that is trying to send the emote.
|
||||
*
|
||||
* Returns the volume level for an emote's audio component.
|
||||
*/
|
||||
/datum/emote/proc/get_volume(mob/living/user)
|
||||
return volume
|
||||
|
||||
/**
|
||||
* Replace pronouns in the inputed string with the user's proper pronouns.
|
||||
*
|
||||
* Specifically replaces they/them/their pronouns with the user's pronouns, as well as %s (like theirs)
|
||||
*
|
||||
* Arguments:
|
||||
* * user - Person that is trying to send the emote.
|
||||
* * msg - The string to modify.
|
||||
*
|
||||
* Returns the modified msg string.
|
||||
*/
|
||||
/datum/emote/proc/replace_pronoun(mob/user, msg)
|
||||
if(findtext(msg, "their"))
|
||||
msg = replacetext(msg, "their", user.p_their())
|
||||
if(findtext(msg, "them"))
|
||||
msg = replacetext(msg, "them", user.p_them())
|
||||
if(findtext(msg, "they"))
|
||||
msg = replacetext(msg, "they", user.p_they())
|
||||
if(findtext(msg, "%s"))
|
||||
msg = replacetext(msg, "%s", user.p_s())
|
||||
return msg
|
||||
|
||||
/**
|
||||
* Selects the message type to override the message with.
|
||||
*
|
||||
* Arguments:
|
||||
* * user - Person that is trying to send the emote.
|
||||
* * msg - The string to modify.
|
||||
* * intentional - Bool that says whether the emote was forced (FALSE) or not (TRUE).
|
||||
*
|
||||
* Returns the new message, or msg directly, if no change was needed.
|
||||
*/
|
||||
/datum/emote/proc/select_message_type(mob/user, msg, intentional)
|
||||
. = msg
|
||||
if(user.mind && user.mind.miming && message_mime)
|
||||
. = message_mime
|
||||
if(isalienadult(user) && message_alien)
|
||||
. = message_alien
|
||||
else if(islarva(user) && message_larva)
|
||||
. = message_larva
|
||||
else if(issilicon(user) && message_robot)
|
||||
. = message_robot
|
||||
else if(isAI(user) && message_AI)
|
||||
. = message_AI
|
||||
else if(ismonkeybasic(user) && message_monkey)
|
||||
. = message_monkey
|
||||
else if(isanimal(user) && message_simple)
|
||||
. = message_simple
|
||||
else if(isobserver(user) && message_observer)
|
||||
. = message_observer
|
||||
|
||||
/**
|
||||
* Replaces the %t in the message in message_param by params.
|
||||
*
|
||||
* The behavior of this proc is particularly dependent on `target_behavior` and `emote_target_type`.
|
||||
* If target_behavior is EMOTE_TARGET_BHVR_RAW, we ignore any sort of target searching.
|
||||
* Otherwise, we try to find a target in view to call this emote on based on emote_target_type.
|
||||
*
|
||||
*
|
||||
* If you want to call something on the target object itself while it's still in scope, override act_on_target().
|
||||
*
|
||||
*
|
||||
* Arguments:
|
||||
* * user - Person that is trying to send the emote.
|
||||
* * params - Parameters added after the emote.
|
||||
* * substitution_str - String to substitute the target into.
|
||||
* * base_message - If passed, the original message before any sort of modification occurred. Useful when dealing with non-standard message types.
|
||||
*
|
||||
* Returns the modified string, or null if the given parameter is invalid. May also return EMOTE_ACT_STOP_EXECUTION if acting on the target should stop emote execution.
|
||||
*/
|
||||
/datum/emote/proc/select_param(mob/user, params, substitution, base_message)
|
||||
|
||||
if(target_behavior == EMOTE_TARGET_BHVR_RAW)
|
||||
return replacetext(substitution, "%t", params)
|
||||
|
||||
if(target_behavior == EMOTE_TARGET_BHVR_NUM)
|
||||
if(!isnum(text2num(params)))
|
||||
return null
|
||||
act_on_target(user, text2num(params))
|
||||
return replacetext(substitution, "%t", params)
|
||||
|
||||
var/full_target = find_target(user, params, emote_target_type)
|
||||
if(full_target)
|
||||
// If we find an actual target obj/item/whatever, see if we'd want to perform some action on it and jump out
|
||||
// Fire off a signal first to see if our interaction should be stopped for some reason
|
||||
if(!(SEND_SIGNAL(user, COMSIG_MOB_EMOTE_AT, full_target, key) & COMPONENT_BLOCK_EMOTE_ACTION))
|
||||
if(act_on_target(user, full_target) == EMOTE_ACT_STOP_EXECUTION)
|
||||
return EMOTE_ACT_STOP_EXECUTION
|
||||
return replacetext(substitution, "%t", full_target)
|
||||
|
||||
// no target found, contingency plans
|
||||
switch(target_behavior)
|
||||
if(EMOTE_TARGET_BHVR_MUST_MATCH)
|
||||
return null
|
||||
if(EMOTE_TARGET_BHVR_DEFAULT_TO_BASE)
|
||||
return base_message
|
||||
if(EMOTE_TARGET_BHVR_USE_PARAMS_ANYWAY)
|
||||
return replacetext(substitution, "%t", params)
|
||||
|
||||
CRASH("Emote tried to select_param with invalid target behavior.")
|
||||
|
||||
/**
|
||||
* Perform an action on the target of an emote, if one was found.
|
||||
*
|
||||
* This gets called in select_param if a valid object target was found, and should let you interact with the
|
||||
* object being targeted while it's still in scope.
|
||||
*
|
||||
* * user - Person who is triggering the emote.
|
||||
* * Target - The target of the emote itself.
|
||||
*/
|
||||
/datum/emote/proc/act_on_target(mob/user, target)
|
||||
return
|
||||
|
||||
/**
|
||||
* Check to see if the user is allowed to run the emote.
|
||||
*
|
||||
*
|
||||
* Arguments:
|
||||
* * user - Person that is trying to send the emote.
|
||||
* * status_check - Bool that says whether we should check their stat or not.
|
||||
* * intentional - Bool that says whether the emote was forced (FALSE) or not (TRUE).
|
||||
*
|
||||
* Returns a bool about whether or not the user can run the emote.
|
||||
*/
|
||||
/datum/emote/proc/can_run_emote(mob/user, status_check = TRUE, intentional = FALSE)
|
||||
. = TRUE
|
||||
if(!is_type_in_typecache(user, mob_type_allowed_typecache))
|
||||
return FALSE
|
||||
if(is_type_in_typecache(user, mob_type_blacklist_typecache))
|
||||
return FALSE
|
||||
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(species_type_whitelist_typecache && H.dna && !is_type_in_typecache(H.dna.species, species_type_whitelist_typecache))
|
||||
return FALSE
|
||||
|
||||
if(intentional && only_unintentional)
|
||||
return FALSE
|
||||
|
||||
if(check_mute(user.client?.ckey, MUTE_EMOTE))
|
||||
to_chat(src, "<span class='warning'>You cannot send emotes (muted).</span>")
|
||||
return FALSE
|
||||
|
||||
if(status_check && !is_type_in_typecache(user, mob_type_ignore_stat_typecache))
|
||||
var/intentional_stat_check = (intentional && (user.stat <= stat_allowed && (max_stat_allowed == DEFAULT_MAX_STAT_ALLOWED || user.stat >= max_stat_allowed)))
|
||||
var/unintentional_stat_check = (!intentional && (user.stat <= unintentional_stat_allowed && (max_unintentional_stat_allowed == DEFAULT_MAX_STAT_ALLOWED || user.stat >= max_unintentional_stat_allowed)))
|
||||
if(!intentional_stat_check && !unintentional_stat_check)
|
||||
var/stat = stat_to_text(user.stat)
|
||||
if(!intentional)
|
||||
return FALSE
|
||||
|
||||
if(stat)
|
||||
to_chat(user, "<span class='warning'>You cannot [key] while [stat]!</span>")
|
||||
return FALSE
|
||||
if(HAS_TRAIT(src, TRAIT_FAKEDEATH))
|
||||
// Don't let people blow their cover by mistake
|
||||
return FALSE
|
||||
if(hands_use_check && !user.can_use_hands() && (iscarbon(user)))
|
||||
if(!intentional)
|
||||
return FALSE
|
||||
to_chat(user, "<span class='warning'>You cannot use your hands to [key] right now!</span>")
|
||||
return FALSE
|
||||
|
||||
if(isliving(user))
|
||||
var/mob/living/sender = user
|
||||
if(HAS_TRAIT(sender, TRAIT_EMOTE_MUTE) && intentional)
|
||||
return FALSE
|
||||
else
|
||||
// deadchat handling
|
||||
if(check_mute(user.client?.ckey, MUTE_DEADCHAT))
|
||||
to_chat(src, "<span class='warning'>You cannot send deadchat emotes (muted).</span>")
|
||||
return FALSE
|
||||
if(!(user.client?.prefs.toggles & PREFTOGGLE_CHAT_DEAD))
|
||||
to_chat(src, "<span class='warning'>You have deadchat muted.</span>")
|
||||
return FALSE
|
||||
if(!check_rights(R_ADMIN, FALSE, user))
|
||||
if(!GLOB.dsay_enabled)
|
||||
to_chat(src, "<span class='warning'>Deadchat is globally muted</span>")
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Find a target for the emote based on the message parameter fragment passed in.
|
||||
*
|
||||
* * user - The user looking for a target.
|
||||
* * fragment - The mesage parameter or fragment of text they're using to try to find a target.
|
||||
* * emote_target_type - Define denoting the type of target to use when searching.
|
||||
*
|
||||
* Returns a matched target, or null if a specific match couldn't be made.
|
||||
*/
|
||||
/datum/emote/proc/find_target(mob/user, fragment, emote_target_type)
|
||||
var/target = null
|
||||
|
||||
fragment = lowertext(fragment)
|
||||
|
||||
if(emote_target_type & EMOTE_TARGET_MOB)
|
||||
for(var/mob/living/M in view(user.client))
|
||||
if(findtext(lowertext(M.name), fragment))
|
||||
target = M
|
||||
break
|
||||
|
||||
if(!target && emote_target_type & EMOTE_TARGET_OBJ)
|
||||
for(var/obj/thing in view(user.client))
|
||||
if(findtext(lowertext(thing.name), fragment))
|
||||
target = thing
|
||||
break
|
||||
|
||||
return target
|
||||
|
||||
/**
|
||||
* Return whether a user should be able to vocalize emotes or not, due to a mask or inability to speak.
|
||||
* If this returns false, any mouth emotes will be replaced with muzzled noises.
|
||||
*/
|
||||
/datum/emote/proc/can_vocalize_emotes(mob/user)
|
||||
if(user.mind?.miming)
|
||||
// mimes get special treatment; though they can't really "vocalize" we don't want to replace their message.
|
||||
return TRUE
|
||||
if(!muzzle_ignore && !user.can_speak())
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
/**
|
||||
* 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(only_forced_audio && intentional)
|
||||
return FALSE
|
||||
if((emote_type & EMOTE_MOUTH) && !can_vocalize_emotes(user))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/emote/proc/remove_ending_punctuation(msg)
|
||||
var/static/list/end_punctuation = list(".", "?", "!")
|
||||
if(copytext(msg, -1) in end_punctuation)
|
||||
msg = copytext(msg, 1, -1)
|
||||
return msg
|
||||
|
||||
/**
|
||||
* 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)
|
||||
return FALSE
|
||||
|
||||
if(!text)
|
||||
CRASH("Someone passed nothing to manual_emote(), fix it")
|
||||
|
||||
|
||||
log_emote(text, src)
|
||||
|
||||
var/ghost_text = "<b>[src]</b> [text]"
|
||||
|
||||
var/origin_turf = get_turf(src)
|
||||
if(client)
|
||||
for(var/mob/ghost as anything in GLOB.dead_mob_list)
|
||||
if(!ghost.client)
|
||||
continue
|
||||
if(ghost.client.prefs.toggles & PREFTOGGLE_CHAT_GHOSTSIGHT && !(ghost in viewers(origin_turf, null)))
|
||||
ghost.show_message("[ghost_follow_link(src, ghost)] [ghost_text]")
|
||||
|
||||
visible_message(text)
|
||||
|
||||
|
||||
#undef DEFAULT_MAX_STAT_ALLOWED
|
||||
@@ -206,7 +206,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
switch(invocation_type)
|
||||
if("shout")
|
||||
if(!user.IsVocal())
|
||||
user.custom_emote(1, "makes frantic gestures!")
|
||||
user.custom_emote(EMOTE_VISIBLE, "makes frantic gestures!")
|
||||
else
|
||||
if(prob(50))//Auto-mute? Fuck that noise
|
||||
user.say(invocation)
|
||||
|
||||
@@ -40,11 +40,25 @@
|
||||
|
||||
/datum/status_effect/high_five
|
||||
id = "high_five"
|
||||
duration = 40
|
||||
duration = 5 SECONDS
|
||||
alert_type = null
|
||||
|
||||
/datum/status_effect/high_five/on_remove()
|
||||
owner.visible_message("[owner] was left hanging....")
|
||||
/datum/status_effect/high_five/proc/get_missed_message()
|
||||
var/list/missed_highfive_messages = list(
|
||||
"it looks like [owner.p_they()] [owner.p_were()] left hanging...",
|
||||
"seeming to wave at nobody in particular.",
|
||||
"moving [owner.p_their()] hand directly to [owner.p_their()] forehead in shame.",
|
||||
"fully committing and high-fiving empty space.",
|
||||
"high-fiving [owner.p_their()] other hand shamefully before wiping away a tear.",
|
||||
"going for a handshake, then a fistbump, before pulling [owner.p_their()] hand back...? What [owner.p_are()] [owner.p_they()] doing?"
|
||||
)
|
||||
|
||||
return pick(missed_highfive_messages)
|
||||
|
||||
/datum/status_effect/high_five/on_timeout()
|
||||
// show some emotionally damaging failure messages
|
||||
// high risk, high reward
|
||||
owner.visible_message("[owner] awkwardly lowers [owner.p_their()] hand, [get_missed_message()]")
|
||||
|
||||
/datum/status_effect/charging
|
||||
id = "charging"
|
||||
|
||||
@@ -55,12 +55,14 @@
|
||||
tick()
|
||||
tick_interval = world.time + initial(tick_interval)
|
||||
if(duration != -1 && duration < world.time)
|
||||
on_timeout()
|
||||
qdel(src)
|
||||
|
||||
/datum/status_effect/proc/on_apply() //Called whenever the buff is applied; returning FALSE will cause it to autoremove itself.
|
||||
return TRUE
|
||||
/datum/status_effect/proc/tick() //Called every tick.
|
||||
/datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed; do note that at the point this is called, it is out of the owner's status_effects but owner is not yet null
|
||||
/datum/status_effect/proc/on_timeout() // Called specifically whenever the status effect expires.
|
||||
/datum/status_effect/proc/be_replaced() //Called instead of on_remove when a status effect is replaced by itself or when a status effect with on_remove_on_mob_delete = FALSE has its mob deleted
|
||||
owner.clear_alert(id)
|
||||
LAZYREMOVE(owner.status_effects, src)
|
||||
@@ -127,7 +129,7 @@
|
||||
if(status_effects)
|
||||
var/datum/status_effect/S1 = effect
|
||||
for(var/datum/status_effect/S in status_effects)
|
||||
if(initial(S1.id) == S.id && S.before_remove(arguments))
|
||||
if(initial(S1.id) == S.id && S.before_remove(arglist(arguments)))
|
||||
qdel(S)
|
||||
. = TRUE
|
||||
|
||||
|
||||
@@ -101,9 +101,6 @@
|
||||
if(isovermind(M) || isobserver(M) || istype((M), /mob/living/simple_animal/hostile/blob/blobbernaut))
|
||||
M.show_message(rendered, 2)
|
||||
|
||||
/mob/camera/blob/emote(act, m_type = 1, message = null, force)
|
||||
return
|
||||
|
||||
/mob/camera/blob/blob_act(obj/structure/blob/B)
|
||||
return
|
||||
|
||||
|
||||
@@ -32,9 +32,6 @@
|
||||
return FALSE
|
||||
return B.host.say_understands(other, speaking)
|
||||
|
||||
/mob/living/captive_brain/emote(act, m_type = 1, message = null, force)
|
||||
return
|
||||
|
||||
/mob/living/captive_brain/resist()
|
||||
var/mob/living/simple_animal/borer/B = loc
|
||||
|
||||
|
||||
@@ -115,11 +115,14 @@
|
||||
if(!message)
|
||||
return
|
||||
log_say(message, src)
|
||||
if(copytext(message, 1, 2) == "*")
|
||||
return emote(copytext(message, 2), intentional = TRUE)
|
||||
|
||||
var/rendered
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
var/rendered = "<span class='revennotice'><b>[src]</b> [(isobserver(M) ? ("([ghost_follow_link(src, ghost=M)])") : "")] says, \"[message]\"</span>"
|
||||
rendered = "<span class='revennotice'><b>[src]</b> [(isobserver(M) ? ("([ghost_follow_link(src, ghost=M)])") : "")] says, \"[message]\"</span>"
|
||||
if(istype(M, /mob/living/simple_animal/revenant) || isobserver(M))
|
||||
to_chat(M, rendered)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/revenant/Stat()
|
||||
..()
|
||||
|
||||
@@ -540,7 +540,7 @@
|
||||
/obj/mecha/attack_animal(mob/living/simple_animal/user)
|
||||
log_message("Attack by simple animal. Attacker - [user].")
|
||||
if(!user.melee_damage_upper && !user.obj_damage)
|
||||
user.custom_emote(1, "[user.friendly] [src].")
|
||||
user.custom_emote(EMOTE_VISIBLE, "[user.friendly] [src].")
|
||||
return FALSE
|
||||
else
|
||||
var/play_soundeffect = 1
|
||||
|
||||
@@ -1,3 +1,28 @@
|
||||
/// If used, an implant will trigger when an emote is intentionally used.
|
||||
#define IMPLANT_EMOTE_TRIGGER_INTENTIONAL (1<<0)
|
||||
/// If used, an implant will trigger when an emote is forced/unintentionally used.
|
||||
#define IMPLANT_EMOTE_TRIGGER_UNINTENTIONAL (1<<1)
|
||||
/// If used, an implant will always trigger when the user makes an emote.
|
||||
#define IMPLANT_EMOTE_TRIGGER_ALWAYS (IMPLANT_EMOTE_TRIGGER_UNINTENTIONAL | IMPLANT_EMOTE_TRIGGER_INTENTIONAL)
|
||||
/// If used, an implant will trigger on the user's first death.
|
||||
#define IMPLANT_TRIGGER_DEATH_ONCE (1<<2)
|
||||
/// If used, an implant will trigger any time a user dies.
|
||||
#define IMPLANT_TRIGGER_DEATH_ANY (1<<3)
|
||||
/// If used, an implant will NOT trigger on death when a user is gibbed.
|
||||
#define IMPLANT_TRIGGER_NOT_WHEN_GIBBED (1<<4)
|
||||
|
||||
// Defines related to the way that the implant is activated. This is the value for implant.activated
|
||||
/// The implant is passively active (like a mindshield)
|
||||
#define IMPLANT_ACTIVATED_PASSIVE 0
|
||||
/// The implant is activated manually by a trigger
|
||||
#define IMPLANT_ACTIVATED_ACTIVE 1
|
||||
|
||||
/**
|
||||
* # Implants
|
||||
*
|
||||
* Code for implants that can be inserted into a person and have some sort of passive or triggered action.
|
||||
*
|
||||
*/
|
||||
/obj/item/implant
|
||||
name = "implant"
|
||||
icon = 'icons/obj/implants.dmi'
|
||||
@@ -5,31 +30,121 @@
|
||||
origin_tech = "materials=2;biotech=3;programming=2"
|
||||
|
||||
actions_types = list(/datum/action/item_action/hands_free/activate)
|
||||
var/activated = 1 //1 for implant types that can be activated, 0 for ones that are "always on" like mindshield implants
|
||||
/// How the implant is activated.
|
||||
var/activated = IMPLANT_ACTIVATED_ACTIVE
|
||||
/// Whether the implant is implanted. Null if it's never been inserted, TRUE if it's currently inside someone, or FALSE if it's been removed.
|
||||
var/implanted = null
|
||||
/// Who the implant is inside of.
|
||||
var/mob/living/imp_in = null
|
||||
item_color = "b"
|
||||
var/allow_multiple = 0
|
||||
/// Whether multiple implants of this same type can be inserted into someone.
|
||||
var/allow_multiple = FALSE
|
||||
/// Amount of times that the implant can be triggered by the user. If the implant can't be used, it can't be inserted.
|
||||
var/uses = -1
|
||||
flags = DROPDEL
|
||||
flags = DROPDEL // By default, don't let implants be harvestable.
|
||||
|
||||
/// List of emote keys that activate this implant when used.
|
||||
var/list/trigger_emotes
|
||||
/// What type of action will trigger this emote. Bitfield of IMPLANT_EMOTE_* defines.
|
||||
var/trigger_causes
|
||||
/// Whether this implant has already triggered on death or not, to prevent it firing multiple times.
|
||||
var/has_triggered_on_death = FALSE
|
||||
|
||||
/obj/item/implant/proc/trigger(emote, mob/source, force)
|
||||
/obj/item/implant/proc/unregister_emotes()
|
||||
if(imp_in && LAZYLEN(trigger_emotes))
|
||||
for(var/emote in trigger_emotes)
|
||||
UnregisterSignal(imp_in, COMSIG_MOB_EMOTED(emote))
|
||||
|
||||
/**
|
||||
* Set the emote that will trigger the implant.
|
||||
* * user - User who is trying to associate the implant to themselves.
|
||||
* * emote_key - Key of the emote that should trigger the implant.
|
||||
* * on_implant - Whether this proc is being called during the implantation of the implant.
|
||||
* * silent - If true, the user won't get any to_chat messages if an implantation fails.
|
||||
*/
|
||||
/obj/item/implant/proc/set_trigger(mob/user, emote_key, on_implant = FALSE, silent = TRUE)
|
||||
if(imp_in != user)
|
||||
return FALSE
|
||||
|
||||
if(!emote_key)
|
||||
return FALSE
|
||||
|
||||
if(LAZYIN(trigger_emotes, emote_key) && !on_implant)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'> You've already registered [emote_key]!")
|
||||
return FALSE
|
||||
|
||||
if(emote_key == "me" || emote_key == "custom")
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'> You can't trigger [src] with a custom emote.")
|
||||
return FALSE
|
||||
|
||||
if(!(emote_key in user.usable_emote_keys(trigger_causes & IMPLANT_EMOTE_TRIGGER_INTENTIONAL)))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'> You can't trigger [src] with that emote! Try *help to see emotes you can use.</span>")
|
||||
return FALSE
|
||||
|
||||
if(!(emote_key in user.usable_emote_keys(trigger_causes & IMPLANT_EMOTE_TRIGGER_UNINTENTIONAL)))
|
||||
CRASH("User was given an implant for an unintentional emote that they can't use.")
|
||||
|
||||
LAZYADD(trigger_emotes, emote_key)
|
||||
RegisterSignal(user, COMSIG_MOB_EMOTED(emote_key), .proc/on_emote)
|
||||
|
||||
/obj/item/implant/proc/on_emote(mob/living/user, datum/emote/fired_emote, key, emote_type, message, intentional)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!implanted || !imp_in)
|
||||
return
|
||||
|
||||
if(!(intentional && (trigger_causes & IMPLANT_EMOTE_TRIGGER_INTENTIONAL)) && !(!intentional && (trigger_causes & IMPLANT_EMOTE_TRIGGER_UNINTENTIONAL)))
|
||||
return
|
||||
|
||||
add_attack_logs(user, user, "[intentional ? "intentionally" : "unintentionally"] [src] was [intentional ? "intentionally" : "unintentionally"] triggered with the emote [fired_emote].")
|
||||
emote_trigger(key, user, intentional)
|
||||
|
||||
/obj/item/implant/proc/on_death(mob/source, gibbed)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!implanted || !imp_in)
|
||||
return
|
||||
|
||||
if(gibbed && (trigger_causes & IMPLANT_TRIGGER_NOT_WHEN_GIBBED))
|
||||
return
|
||||
|
||||
// This should help avoid infinite recursion for things like dust that call death()
|
||||
if(has_triggered_on_death && (trigger_causes & IMPLANT_TRIGGER_DEATH_ONCE))
|
||||
return
|
||||
|
||||
has_triggered_on_death = TRUE
|
||||
|
||||
add_attack_logs(source, source, "had their [src] implant triggered on [gibbed ? "gib" : "death"].")
|
||||
death_trigger(source, gibbed)
|
||||
|
||||
/obj/item/implant/proc/emote_trigger(emote, mob/source, force)
|
||||
return
|
||||
|
||||
/obj/item/implant/proc/activate()
|
||||
/obj/item/implant/proc/death_trigger(mob/source, gibbed)
|
||||
return
|
||||
|
||||
/obj/item/implant/proc/activate(cause)
|
||||
return
|
||||
|
||||
/obj/item/implant/ui_action_click()
|
||||
activate("action_button")
|
||||
|
||||
|
||||
//What does the implant do upon injection?
|
||||
//return 1 if the implant injects
|
||||
//return -1 if the implant fails to inject
|
||||
//return 0 if there is no room for implant
|
||||
/**
|
||||
* Try to implant ourselves into a mob.
|
||||
*
|
||||
* * source - The person the implant is being administered to.
|
||||
* * user - The person who is doing the implanting.
|
||||
*
|
||||
* Returns
|
||||
* 1 if the implant injects successfully
|
||||
* -1 if the implant fails to inject
|
||||
* 0 if there's no room for the implant.
|
||||
*/
|
||||
/obj/item/implant/proc/implant(mob/source, mob/user)
|
||||
var/obj/item/implant/imp_e = locate(src.type) in source
|
||||
var/obj/item/implant/imp_e = locate(type) in source
|
||||
if(!allow_multiple && imp_e && imp_e != src)
|
||||
if(imp_e.uses < initial(imp_e.uses)*2)
|
||||
if(uses == -1)
|
||||
@@ -42,13 +157,23 @@
|
||||
return 0
|
||||
|
||||
|
||||
src.loc = source
|
||||
loc = source
|
||||
imp_in = source
|
||||
implanted = 1
|
||||
implanted = TRUE
|
||||
if(trigger_emotes)
|
||||
if(!(trigger_causes & IMPLANT_EMOTE_TRIGGER_INTENTIONAL | IMPLANT_EMOTE_TRIGGER_UNINTENTIONAL))
|
||||
CRASH("Implant [src] has trigger emotes defined but no trigger cause with which to use them!")
|
||||
if(!activated && (trigger_causes & IMPLANT_EMOTE_TRIGGER_INTENTIONAL))
|
||||
CRASH("Implant [src] has intentional emote triggers on a passive implant")
|
||||
// If you can't activate the implant manually, you shouldn't be able to deliberately activate it with an emote
|
||||
for(var/emote in trigger_emotes)
|
||||
set_trigger(source, emote, TRUE, TRUE)
|
||||
if(activated)
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.Grant(source)
|
||||
if(trigger_causes & (IMPLANT_TRIGGER_DEATH_ONCE | IMPLANT_TRIGGER_DEATH_ANY))
|
||||
RegisterSignal(source, COMSIG_MOB_DEATH, .proc/on_death)
|
||||
if(ishuman(source))
|
||||
var/mob/living/carbon/human/H = source
|
||||
H.sec_hud_set_implants()
|
||||
@@ -58,10 +183,14 @@
|
||||
|
||||
return 1
|
||||
|
||||
/**
|
||||
* Clean up when an implant is removed.
|
||||
* * source - the user who the implant was removed from.
|
||||
*/
|
||||
/obj/item/implant/proc/removed(mob/source)
|
||||
src.loc = null
|
||||
loc = null
|
||||
imp_in = null
|
||||
implanted = 0
|
||||
implanted = FALSE
|
||||
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
@@ -71,7 +200,12 @@
|
||||
var/mob/living/carbon/human/H = source
|
||||
H.sec_hud_set_implants()
|
||||
|
||||
return 1
|
||||
if(trigger_causes & (IMPLANT_TRIGGER_DEATH_ONCE | IMPLANT_TRIGGER_DEATH_ANY))
|
||||
UnregisterSignal(source, COMSIG_MOB_DEATH)
|
||||
|
||||
unregister_emotes()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/implant/Destroy()
|
||||
if(imp_in)
|
||||
@@ -83,5 +217,5 @@
|
||||
return "No information available"
|
||||
|
||||
/obj/item/implant/dropped(mob/user)
|
||||
. = 1
|
||||
. = TRUE
|
||||
..()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
desc = "Returns you to the mothership."
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "implant"
|
||||
activated = 1
|
||||
activated = IMPLANT_ACTIVATED_ACTIVE
|
||||
origin_tech = "materials=2;biotech=7;magnets=4;bluespace=4;abductor=5"
|
||||
var/obj/machinery/abductor/pad/home
|
||||
var/cooldown = 30
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
icon_state = "reagents"
|
||||
origin_tech = "materials=3;biotech=4"
|
||||
container_type = OPENCONTAINER
|
||||
trigger_causes = IMPLANT_TRIGGER_DEATH_ANY
|
||||
|
||||
/obj/item/implant/chem/get_data()
|
||||
var/dat = {"<b>Implant Specifications:</b><BR>
|
||||
@@ -30,12 +31,8 @@
|
||||
GLOB.tracked_implants -= src
|
||||
return ..()
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/item/implant/chem/trigger(emote, mob/source, force)
|
||||
if(force && emote == "deathgasp")
|
||||
activate(reagents.total_volume)
|
||||
/obj/item/implant/chem/death_trigger(mob/victim, gibbed)
|
||||
activate(reagents.total_volume)
|
||||
|
||||
/obj/item/implant/chem/activate(cause)
|
||||
if(!cause || !imp_in) return 0
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/obj/item/implant/sad_trombone
|
||||
name = "sad trombone implant"
|
||||
activated = FALSE
|
||||
trigger_emotes = list("deathgasp")
|
||||
// If something forces the clown to fake death, it's pretty funny to still see the sad trombone played
|
||||
trigger_causes = IMPLANT_EMOTE_TRIGGER_UNINTENTIONAL | IMPLANT_TRIGGER_DEATH_ANY
|
||||
|
||||
/obj/item/implant/sad_trombone/get_data()
|
||||
var/dat = {"<b>Implant Specifications:</b><BR>
|
||||
@@ -9,9 +12,15 @@
|
||||
"}
|
||||
return dat
|
||||
|
||||
/obj/item/implant/sad_trombone/trigger(emote, mob/source, force)
|
||||
if(force && emote == "deathgasp")
|
||||
playsound(loc, 'sound/misc/sadtrombone.ogg', 50, FALSE)
|
||||
/obj/item/implant/sad_trombone/emote_trigger(emote, mob/source, force)
|
||||
activate(emote)
|
||||
|
||||
/obj/item/implant/sad_trombone/death_trigger(mob/user, gibbed)
|
||||
activate(gibbed)
|
||||
|
||||
|
||||
/obj/item/implant/sad_trombone/activate()
|
||||
playsound(loc, 'sound/misc/sadtrombone.ogg', 50, FALSE)
|
||||
|
||||
/obj/item/implanter/sad_trombone
|
||||
name = "implanter (sad trombone)"
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
name = "death alarm implant"
|
||||
desc = "An alarm which monitors host vital signs and transmits a radio message upon death."
|
||||
var/mobname = "Will Robinson"
|
||||
activated = 0
|
||||
activated = IMPLANT_ACTIVATED_PASSIVE
|
||||
var/static/list/stealth_areas = typecacheof(list(/area/syndicate_mothership, /area/shuttle/syndicate_elite))
|
||||
trigger_causes = IMPLANT_TRIGGER_DEATH_ANY
|
||||
|
||||
/obj/item/implant/death_alarm/get_data()
|
||||
var/dat = {"<b>Implant Specifications:</b><BR>
|
||||
@@ -17,9 +18,10 @@
|
||||
<b>Integrity:</b> Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."}
|
||||
return dat
|
||||
|
||||
/obj/item/implant/death_alarm/Destroy()
|
||||
UnregisterSignal(imp_in, COMSIG_MOB_DEATH)
|
||||
return ..()
|
||||
/obj/item/implant/death_alarm/implant(mob/target)
|
||||
. = ..()
|
||||
if(.)
|
||||
mobname = target.real_name
|
||||
|
||||
/obj/item/implant/death_alarm/activate(cause) // Death signal sends name followed by the gibbed / not gibbed check
|
||||
var/mob/M = imp_in
|
||||
@@ -48,14 +50,7 @@
|
||||
/obj/item/implant/death_alarm/emp_act(severity) //for some reason alarms stop going off in case they are emp'd, even without this
|
||||
activate("emp") //let's shout that this dude is dead
|
||||
|
||||
/obj/item/implant/death_alarm/implant(mob/target)
|
||||
if(..())
|
||||
mobname = target.real_name
|
||||
RegisterSignal(target, COMSIG_MOB_DEATH, /obj/item/implant/death_alarm.proc/check_gibbed_activate)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/implant/death_alarm/proc/check_gibbed_activate(datum/source, gibbed)
|
||||
/obj/item/implant/death_alarm/death_trigger(mob/source, gibbed)
|
||||
if(gibbed)
|
||||
activate("gib")
|
||||
else
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
var/medium = 0.8
|
||||
var/heavy = 0.4
|
||||
var/delay = 7
|
||||
trigger_causes = IMPLANT_TRIGGER_DEATH_ONCE // Not surviving that
|
||||
|
||||
/obj/item/implant/explosive/get_data()
|
||||
var/dat = {"<b>Implant Specifications:</b><BR>
|
||||
@@ -22,9 +23,8 @@
|
||||
"}
|
||||
return dat
|
||||
|
||||
/obj/item/implant/explosive/trigger(emote, mob/source, force)
|
||||
if(force && emote == "deathgasp")
|
||||
activate("death")
|
||||
/obj/item/implant/explosive/death_trigger(mob/source, gibbed)
|
||||
activate("death")
|
||||
|
||||
/obj/item/implant/explosive/activate(cause)
|
||||
if(!cause || !imp_in)
|
||||
@@ -142,6 +142,7 @@
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "remains"
|
||||
actions_types = list(/datum/action/item_action/hands_free/activate/always)
|
||||
trigger_causes = IMPLANT_TRIGGER_DEATH_ONCE | IMPLANT_TRIGGER_NOT_WHEN_GIBBED
|
||||
|
||||
/obj/item/implant/dust/get_data()
|
||||
var/dat = {"<b>Implant Specifications:</b><BR>
|
||||
@@ -155,9 +156,8 @@
|
||||
"}
|
||||
return dat
|
||||
|
||||
/obj/item/implant/dust/trigger(emote, mob/source, force)
|
||||
if(force && emote == "deathgasp")
|
||||
activate("death")
|
||||
/obj/item/implant/dust/death_trigger(emote, mob/source, force)
|
||||
activate("death")
|
||||
|
||||
/obj/item/implant/dust/activate(cause)
|
||||
if(!cause || !imp_in || cause == "emp")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
desc = "Teaches you the arts of Krav Maga in 5 short instructional videos beamed directly into your eyeballs."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state ="scroll2"
|
||||
activated = 1
|
||||
activated = IMPLANT_ACTIVATED_ACTIVE
|
||||
origin_tech = "materials=2;biotech=4;combat=5;syndicate=4"
|
||||
var/datum/martial_art/krav_maga/style = new
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "mindshield implant"
|
||||
desc = "Stops people messing with your mind."
|
||||
origin_tech = "materials=2;biotech=4;programming=4"
|
||||
activated = 0
|
||||
activated = IMPLANT_ACTIVATED_PASSIVE
|
||||
|
||||
/obj/item/implant/mindshield/get_data()
|
||||
var/dat = {"<b>Implant Specifications:</b><BR>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
desc = "Lets you shoot your guns"
|
||||
icon_state = "auth"
|
||||
origin_tech = "magnets=2;programming=7;biotech=5;syndicate=5"
|
||||
activated = 0
|
||||
activated = IMPLANT_ACTIVATED_PASSIVE
|
||||
|
||||
/obj/item/implant/weapons_auth/get_data()
|
||||
var/dat = {"<b>Implant Specifications:</b><BR>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/item/implant/tracking
|
||||
name = "tracking implant"
|
||||
desc = "Track with this."
|
||||
activated = 0
|
||||
activated = IMPLANT_ACTIVATED_PASSIVE
|
||||
origin_tech = "materials=2;magnets=2;programming=2;biotech=2"
|
||||
var/id = 1
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
|
||||
/obj/attack_animal(mob/living/simple_animal/M)
|
||||
if((M.a_intent == INTENT_HELP && M.ckey) || (!M.melee_damage_upper && !M.obj_damage))
|
||||
M.custom_emote(1, "[M.friendly] [src].")
|
||||
M.custom_emote(EMOTE_VISIBLE, "[M.friendly] [src].")
|
||||
return 0
|
||||
else
|
||||
var/play_soundeffect = 1
|
||||
|
||||
@@ -141,6 +141,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_PRAY]'><font color='[check_mute(M.client.ckey, MUTE_PRAY) ? "red" : "#6685f5"]'>PRAY</font></a> |
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_ADMINHELP]'><font color='[check_mute(M.client.ckey, MUTE_ADMINHELP) ? "red" : "#6685f5"]'>ADMINHELP</font></a> |
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_DEADCHAT]'><font color='[check_mute(M.client.ckey, MUTE_DEADCHAT) ?" red" : "#6685f5"]'>DEADCHAT</font></a>]
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_EMOTE]'><font color='[check_mute(M.client.ckey, MUTE_EMOTE) ?" red" : "#6685f5"]'>EMOTE</font></a>]
|
||||
(<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_ALL]'><font color='[check_mute(M.client.ckey, MUTE_ALL) ? "red" : "#6685f5"]'>toggle all</font></a>)
|
||||
"}
|
||||
|
||||
|
||||
@@ -222,13 +222,22 @@
|
||||
var/mute_string
|
||||
|
||||
switch(mute_type)
|
||||
if(MUTE_IC) mute_string = "IC (say and emote)"
|
||||
if(MUTE_OOC) mute_string = "OOC"
|
||||
if(MUTE_PRAY) mute_string = "pray"
|
||||
if(MUTE_ADMINHELP) mute_string = "adminhelp, admin PM and ASAY"
|
||||
if(MUTE_DEADCHAT) mute_string = "deadchat and DSAY"
|
||||
if(MUTE_ALL) mute_string = "everything"
|
||||
else return
|
||||
if(MUTE_IC)
|
||||
mute_string = "IC (say and emote)"
|
||||
if(MUTE_OOC)
|
||||
mute_string = "OOC"
|
||||
if(MUTE_PRAY)
|
||||
mute_string = "pray"
|
||||
if(MUTE_ADMINHELP)
|
||||
mute_string = "adminhelp, admin PM and ASAY"
|
||||
if(MUTE_DEADCHAT)
|
||||
mute_string = "deadchat and DSAY"
|
||||
if(MUTE_EMOTE)
|
||||
mute_string = "emote"
|
||||
if(MUTE_ALL)
|
||||
mute_string = "everything"
|
||||
else
|
||||
return
|
||||
|
||||
if(automute)
|
||||
muteunmute = "auto-muted"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
name = "exile implant"
|
||||
desc = "Prevents you from returning from away missions"
|
||||
origin_tech = "materials=2;biotech=3;magnets=2;bluespace=3"
|
||||
activated = 0
|
||||
activated = IMPLANT_ACTIVATED_PASSIVE
|
||||
|
||||
/obj/item/implant/exile/get_data()
|
||||
var/dat = {"<b>Implant Specifications:</b><BR>
|
||||
|
||||
@@ -43,8 +43,7 @@
|
||||
nightmare()
|
||||
if(ishuman(src))
|
||||
if(prob(10))
|
||||
custom_emote(1,"writhes in [p_their()] sleep.")
|
||||
dir = pick(GLOB.cardinal)
|
||||
emote("nightmare")
|
||||
|
||||
/mob/living/carbon/proc/experience_dream(dream_image, isNightmare)
|
||||
dreaming--
|
||||
|
||||
@@ -6,28 +6,6 @@
|
||||
|
||||
return say_dead(message)
|
||||
|
||||
|
||||
/mob/dead/observer/emote(act, type, message, force)
|
||||
message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN))
|
||||
|
||||
if(!message)
|
||||
return
|
||||
|
||||
if(act != "me")
|
||||
return
|
||||
|
||||
log_ghostemote(message, src)
|
||||
|
||||
if(src.client)
|
||||
if(check_mute(client.ckey, MUTE_DEADCHAT))
|
||||
to_chat(src, "<span class='warning'>You cannot emote in deadchat (muted).</span>")
|
||||
return
|
||||
|
||||
if(src.client.handle_spam_prevention(message, MUTE_DEADCHAT))
|
||||
return
|
||||
|
||||
. = src.emote_dead(message)
|
||||
|
||||
/mob/dead/observer/handle_track(message, verb = "says", mob/speaker = null, speaker_name, atom/follow_target, hard_to_hear)
|
||||
return "[speaker_name] ([ghost_follow_link(follow_target, ghost=src)])"
|
||||
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
#define EMOTE_COOLDOWN 20 //Time in deciseconds that the cooldown lasts
|
||||
|
||||
//Emote Cooldown System (it's so simple!)
|
||||
/mob/proc/handle_emote_CD(cooldown = EMOTE_COOLDOWN)
|
||||
if(emote_cd == 3) //Spam those emotes
|
||||
return FALSE
|
||||
if(emote_cd == 2) // Cooldown emotes were disabled by an admin, prevent use
|
||||
return TRUE
|
||||
if(emote_cd == 1) // Already on CD, prevent use
|
||||
return TRUE
|
||||
|
||||
emote_cd = TRUE // Starting cooldown
|
||||
spawn(cooldown)
|
||||
if(emote_cd == 2)
|
||||
return // Don't reset if cooldown emotes were disabled by an admin during the cooldown
|
||||
emote_cd = FALSE // Cooldown complete, ready for more!
|
||||
return FALSE // Proceed with emote
|
||||
|
||||
//--FalseIncarnate
|
||||
|
||||
/mob/proc/handle_emote_param(target, not_self, vicinity, return_mob) //Only returns not null if the target param is valid.
|
||||
var/view_vicinity = vicinity ? vicinity : null //not_self means we'll only return if target is valid and not us
|
||||
if(target) //vicinity is the distance passed to the view proc.
|
||||
for(var/mob/A in view(view_vicinity, null)) //if set, return_mob will cause this proc to return the mob instead of just its name if the target is valid.
|
||||
if(target == A.name && (!not_self || (not_self && target != name)))
|
||||
if(return_mob)
|
||||
return A
|
||||
else
|
||||
return target
|
||||
|
||||
// All mobs should have custom emote, really..
|
||||
/mob/proc/custom_emote(m_type=EMOTE_VISUAL, message = null)
|
||||
if(stat || !use_me && usr == src)
|
||||
if(usr)
|
||||
to_chat(usr, "You are unable to emote.")
|
||||
return
|
||||
var/muzzled = is_muzzled()
|
||||
if(muzzled)
|
||||
var/obj/item/clothing/mask/muzzle/M = wear_mask
|
||||
if(m_type == EMOTE_SOUND && M.mute >= MUZZLE_MUTE_MUFFLE)
|
||||
return //Not all muzzles block sound
|
||||
if(m_type == EMOTE_SOUND && !can_speak())
|
||||
return
|
||||
|
||||
var/input
|
||||
if(!message)
|
||||
input = sanitize(copytext(input(src,"Choose an emote to display.") as text|null,1,MAX_MESSAGE_LEN))
|
||||
else
|
||||
input = message
|
||||
if(input)
|
||||
message = "<B>[src]</B> [input]"
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
if(message)
|
||||
log_emote(message, src)
|
||||
if(isliving(src)) //isliving because these are defined on the mob/living level not mob
|
||||
var/mob/living/L = src
|
||||
L.say_log += "EMOTE: [input]" //say log too so it is easier on admins instead of having to merge the two with timestamps etc
|
||||
L.emote_log += input //emote only log if an admin wants to search just for emotes they don't have to sift through the say
|
||||
create_log(EMOTE_LOG, input) // TODO after #13047: Include the channel
|
||||
// Hearing gasp and such every five seconds is not good emotes were not global for a reason.
|
||||
// Maybe some people are okay with that.
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue //skip monkeys and leavers
|
||||
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(findtext(message, " snores.")) //Because we have so many sleeping people.
|
||||
break
|
||||
|
||||
if(isobserver(M) && M.get_preference(PREFTOGGLE_CHAT_GHOSTSIGHT) && !(M in viewers(src, null)) && client) // The client check makes sure people with ghost sight don't get spammed by simple mobs emoting.
|
||||
M.show_message(message)
|
||||
|
||||
// Type 1 (Visual) emotes are sent to anyone in view of the item
|
||||
if(m_type & EMOTE_VISUAL)
|
||||
var/runechat_text = input
|
||||
if(length(input) > 100)
|
||||
runechat_text = "[copytext(input, 1, 101)]..."
|
||||
var/list/can_see = get_mobs_in_view(1,src) //Allows silicon & mmi mobs carried around to see the emotes of the person carrying them around.
|
||||
can_see |= viewers(src,null)
|
||||
for(var/mob/O in can_see)
|
||||
|
||||
if(O.status_flags & PASSEMOTES)
|
||||
|
||||
for(var/obj/item/holder/H in O.contents)
|
||||
H.show_message(message, m_type)
|
||||
|
||||
for(var/mob/living/M in O.contents)
|
||||
M.show_message(message, m_type)
|
||||
|
||||
O.show_message(message, m_type)
|
||||
if(O.client?.prefs.toggles2 & PREFTOGGLE_2_RUNECHAT)
|
||||
O.create_chat_message(src, runechat_text, symbol = RUNECHAT_SYMBOL_EMOTE)
|
||||
|
||||
// Type 2 (Audible) emotes are sent to anyone in hear range
|
||||
// of the *LOCATION* -- this is important for pAIs to be heard
|
||||
else if(m_type & EMOTE_SOUND)
|
||||
for(var/mob/O in get_mobs_in_view(7,src))
|
||||
|
||||
if(O.status_flags & PASSEMOTES)
|
||||
|
||||
for(var/obj/item/holder/H in O.contents)
|
||||
H.show_message(message, m_type)
|
||||
|
||||
for(var/mob/living/M in O.contents)
|
||||
M.show_message(message, m_type)
|
||||
|
||||
O.show_message(message, m_type)
|
||||
|
||||
/mob/proc/emote_dead(message)
|
||||
if(check_mute(client.ckey, MUTE_DEADCHAT))
|
||||
to_chat(src, "<span class='warning'>You cannot send deadchat emotes (muted).</span>")
|
||||
return
|
||||
|
||||
if(!(client.prefs.toggles & PREFTOGGLE_CHAT_DEAD))
|
||||
to_chat(src, "<span class='warning'>You have deadchat muted.</span>")
|
||||
return
|
||||
|
||||
if(!src.client.holder)
|
||||
if(!GLOB.dsay_enabled)
|
||||
to_chat(src, "<span class='warning'>Deadchat is globally muted</span>")
|
||||
return
|
||||
|
||||
|
||||
var/input
|
||||
if(!message)
|
||||
input = sanitize(copytext(input(src, "Choose an emote to display.") as text|null, 1, MAX_MESSAGE_LEN))
|
||||
else
|
||||
input = message
|
||||
|
||||
if(input)
|
||||
message = "<span class='game deadsay'><span class='prefix'>DEAD:</span> <b>[src]</b> [message]</span>"
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
if(message)
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(check_rights(R_ADMIN|R_MOD, 0, M) && M.get_preference(PREFTOGGLE_CHAT_DEAD)) // Show the emote to admins/mods
|
||||
to_chat(M, message)
|
||||
|
||||
else if(M.stat == DEAD && M.get_preference(PREFTOGGLE_CHAT_DEAD)) // Show the emote to regular ghosts with deadchat toggled on
|
||||
M.show_message(message, 2)
|
||||
@@ -1,141 +0,0 @@
|
||||
/mob/living/carbon/alien/humanoid/emote(act, m_type = 1, message = null, force)
|
||||
var/param = null
|
||||
if(findtext(act, "-", 1, null))
|
||||
var/t1 = findtext(act, "-", 1, null)
|
||||
param = copytext(act, t1 + 1, length(act) + 1)
|
||||
act = copytext(act, 1, t1)
|
||||
|
||||
// if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
|
||||
// act = copytext(act,1,length(act)) //seriously who the fuck wrote this
|
||||
var/muzzled = is_muzzled()
|
||||
|
||||
var/on_CD = 0
|
||||
act = lowertext(act)
|
||||
|
||||
//cooldown system handled by /code/modules/mob/emotes.dm
|
||||
switch(act)
|
||||
if("roar")
|
||||
on_CD = handle_emote_CD()
|
||||
if("deathgasp")
|
||||
on_CD = handle_emote_CD()
|
||||
if("hiss")
|
||||
on_CD = handle_emote_CD()
|
||||
if("gnarl")
|
||||
on_CD = handle_emote_CD()
|
||||
if("flip")
|
||||
on_CD = handle_emote_CD()
|
||||
|
||||
if(!force && on_CD == 1)
|
||||
return
|
||||
|
||||
switch(act)
|
||||
|
||||
|
||||
|
||||
if("sign")
|
||||
if(!restrained())
|
||||
var/num = null
|
||||
if(text2num(param))
|
||||
num = "the number [text2num(param)]"
|
||||
if(num)
|
||||
message = "<B>\The [src]</B> signs [num]."
|
||||
m_type = 1
|
||||
if("burp")
|
||||
if(!muzzled)
|
||||
message = "<B>\The [src]</B> burps."
|
||||
m_type = 2
|
||||
if("deathgasp")
|
||||
message = "<B>\The [src]</B> lets out a waning guttural screech, green blood bubbling from its maw..."
|
||||
m_type = 2
|
||||
if("scratch")
|
||||
if(!restrained())
|
||||
message = "<B>\The [src]</B> scratches."
|
||||
m_type = 1
|
||||
if("whimper")
|
||||
if(!muzzled)
|
||||
message = "<B>\The [src]</B> whimpers."
|
||||
m_type = 2
|
||||
if("roar")
|
||||
if(!muzzled)
|
||||
message = "<B>\The [src]</B> roars."
|
||||
m_type = 2
|
||||
if("hiss")
|
||||
if(!muzzled)
|
||||
message = "<B>\The [src]</B> hisses."
|
||||
m_type = 2
|
||||
if("tail")
|
||||
message = "<B>\The [src]</B> waves its tail."
|
||||
m_type = 1
|
||||
if("gasp")
|
||||
message = "<B>\The [src]</B> gasps."
|
||||
m_type = 2
|
||||
if("shiver")
|
||||
message = "<B>\The [src]</B> shivers."
|
||||
m_type = 2
|
||||
if("drool")
|
||||
message = "<B>\The [src]</B> drools."
|
||||
m_type = 1
|
||||
if("scretch")
|
||||
if(!muzzled)
|
||||
message = "<B>\The [src]</B> scretches."
|
||||
m_type = 2
|
||||
if("choke")
|
||||
message = "<B>\The [src]</B> chokes."
|
||||
m_type = 2
|
||||
if("moan")
|
||||
message = "<B>\The [src]</B> moans!"
|
||||
m_type = 2
|
||||
if("nod")
|
||||
message = "<B>\The [src]</B> nods its head."
|
||||
m_type = 1
|
||||
if("sit")
|
||||
message = "<B>\The [src]</B> sits down."
|
||||
m_type = 1
|
||||
if("sway")
|
||||
message = "<B>\The [src]</B> sways around dizzily."
|
||||
m_type = 1
|
||||
if("sulk")
|
||||
message = "<B>\The [src]</B> sulks down sadly."
|
||||
m_type = 1
|
||||
if("twitch")
|
||||
message = "<B>\The [src]</B> twitches violently."
|
||||
m_type = 1
|
||||
if("dance")
|
||||
if(!restrained())
|
||||
message = "<B>\The [src]</B> dances around happily."
|
||||
m_type = 1
|
||||
if("roll")
|
||||
if(!restrained())
|
||||
message = "<B>\The [src]</B> rolls."
|
||||
m_type = 1
|
||||
if("shake")
|
||||
message = "<B>\The [src]</B> shakes its head."
|
||||
m_type = 1
|
||||
if("gnarl")
|
||||
if(!muzzled)
|
||||
message = "<B>\The [src]</B> gnarls and shows its teeth.."
|
||||
m_type = 2
|
||||
if("jump")
|
||||
message = "<B>\The [src]</B> jumps!"
|
||||
m_type = 1
|
||||
if("collapse")
|
||||
Paralyse(4 SECONDS)
|
||||
message = "<B>\The [src]</B> collapses!"
|
||||
m_type = 2
|
||||
if("flip")
|
||||
m_type = 1
|
||||
message = "<B>\The [src]</B> does a flip!"
|
||||
SpinAnimation(5,1)
|
||||
if("help")
|
||||
to_chat(src, "burp, flip, deathgasp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roar, roll, scratch,\nscretch, shake, sign-#, sit, sulk, sway, tail, twitch, whimper")
|
||||
|
||||
if(!stat)
|
||||
if(act == "roar")
|
||||
playsound(src.loc, 'sound/voice/hiss5.ogg', 50, 1, 1)
|
||||
if(act == "deathgasp")
|
||||
playsound(src.loc, 'sound/voice/hiss6.ogg', 80, 1, 1)
|
||||
if(act == "hiss")
|
||||
playsound(src.loc, 'sound/voice/hiss1.ogg', 30, 1, 1)
|
||||
if(act == "gnarl")
|
||||
playsound(src.loc, 'sound/voice/hiss4.ogg', 30, 1, 1)
|
||||
..()
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Emotes usable by humanoid xenomorphs.
|
||||
*/
|
||||
/datum/emote/living/carbon/alien/humanoid
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/alien/humanoid)
|
||||
|
||||
/datum/emote/living/carbon/alien/humanoid/roar
|
||||
key = "roar"
|
||||
key_third_person = "roars"
|
||||
message = "roars!"
|
||||
message_param = "roars at %t!"
|
||||
emote_type = EMOTE_SOUND | EMOTE_MOUTH
|
||||
sound = "sound/voice/hiss5.ogg"
|
||||
volume = 80
|
||||
|
||||
/datum/emote/living/carbon/alien/humanoid/hiss
|
||||
key = "hiss"
|
||||
key_third_person = "hisses"
|
||||
message = "hisses!"
|
||||
message_param = "hisses at %t!"
|
||||
emote_type = EMOTE_SOUND | EMOTE_MOUTH
|
||||
sound = "sound/voice/hiss1.ogg"
|
||||
volume = 30
|
||||
|
||||
/datum/emote/living/carbon/alien/humanoid/gnarl
|
||||
key = "gnarl"
|
||||
key_third_person = "gnarls"
|
||||
message = "gnarls and shows its teeth."
|
||||
message_param = "gnarls and flashes its teeth at %t."
|
||||
sound = "sound/voice/hiss4.ogg"
|
||||
emote_type = EMOTE_SOUND | EMOTE_MOUTH
|
||||
volume = 30
|
||||
@@ -1,126 +0,0 @@
|
||||
/mob/living/carbon/alien/larva/emote(act, m_type = 1, message = null, force)
|
||||
var/param = null
|
||||
if(findtext(act, "-", 1, null))
|
||||
var/t1 = findtext(act, "-", 1, null)
|
||||
param = copytext(act, t1 + 1, length(act) + 1)
|
||||
act = copytext(act, 1, t1)
|
||||
|
||||
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
|
||||
act = copytext(act,1,length(act))
|
||||
var/muzzled = is_muzzled()
|
||||
act = lowertext(act)
|
||||
switch(act)
|
||||
if("me")
|
||||
if(HAS_TRAIT(src, TRAIT_MUTE))
|
||||
return
|
||||
if(src.client)
|
||||
if(check_mute(client.ckey, MUTE_IC))
|
||||
to_chat(src, "<span class='warning'>You cannot send IC messages (muted).</span>")
|
||||
return
|
||||
if(src.client.handle_spam_prevention(message, MUTE_IC))
|
||||
return
|
||||
if(stat)
|
||||
return
|
||||
if(!(message))
|
||||
return
|
||||
return custom_emote(m_type, message)
|
||||
|
||||
if("custom")
|
||||
return custom_emote(m_type, message)
|
||||
if("sign")
|
||||
if(!src.restrained())
|
||||
message = text("<B>The alien</B> signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null))
|
||||
m_type = 1
|
||||
if("burp")
|
||||
if(!muzzled)
|
||||
message = "<B>[src]</B> burps."
|
||||
m_type = 2
|
||||
if("scratch")
|
||||
if(!src.restrained())
|
||||
message = "<B>[src]</B> scratches."
|
||||
m_type = 1
|
||||
if("whimper")
|
||||
if(!muzzled)
|
||||
message = "<B>[src]</B> whimpers."
|
||||
m_type = 2
|
||||
// if("roar")
|
||||
// if(!muzzled)
|
||||
// message = "<B>[src]</B> roars." Commenting out since larva shouldn't roar /N
|
||||
// m_type = 2
|
||||
if("tail")
|
||||
message = "<B>[src]</B> waves its tail."
|
||||
m_type = 1
|
||||
if("gasp")
|
||||
message = "<B>[src]</B> gasps."
|
||||
m_type = 2
|
||||
if("shiver")
|
||||
message = "<B>[src]</B> shivers."
|
||||
m_type = 2
|
||||
if("drool")
|
||||
message = "<B>[src]</B> drools."
|
||||
m_type = 1
|
||||
if("scretch")
|
||||
if(!muzzled)
|
||||
message = "<B>[src]</B> scretches."
|
||||
m_type = 2
|
||||
if("choke")
|
||||
message = "<B>[src]</B> chokes."
|
||||
m_type = 2
|
||||
if("moan")
|
||||
message = "<B>[src]</B> moans!"
|
||||
m_type = 2
|
||||
if("nod")
|
||||
message = "<B>[src]</B> nods its head."
|
||||
m_type = 1
|
||||
// if("sit")
|
||||
// message = "<B>[src]</B> sits down." //Larvan can't sit down, /N
|
||||
// m_type = 1
|
||||
if("sway")
|
||||
message = "<B>[src]</B> sways around dizzily."
|
||||
m_type = 1
|
||||
if("sulk")
|
||||
message = "<B>[src]</B> sulks down sadly."
|
||||
m_type = 1
|
||||
if("twitch")
|
||||
message = "<B>[src]</B> twitches violently."
|
||||
m_type = 1
|
||||
if("dance")
|
||||
if(!src.restrained())
|
||||
message = "<B>[src]</B> dances around happily."
|
||||
m_type = 1
|
||||
if("roll")
|
||||
if(!src.restrained())
|
||||
message = "<B>[src]</B> rolls."
|
||||
m_type = 1
|
||||
if("shake")
|
||||
message = "<B>[src]</B> shakes its head."
|
||||
m_type = 1
|
||||
if("gnarl")
|
||||
if(!muzzled)
|
||||
message = "<B>[src]</B> gnarls and shows its teeth.."
|
||||
m_type = 2
|
||||
if("jump")
|
||||
message = "<B>[src]</B> jumps!"
|
||||
m_type = 1
|
||||
if("hiss_")
|
||||
message = "<B>[src]</B> hisses softly."
|
||||
m_type = 1
|
||||
if("collapse")
|
||||
Paralyse(4 SECONDS)
|
||||
message = text("<B>[]</B> collapses!", src)
|
||||
m_type = 2
|
||||
if("help")
|
||||
to_chat(src, "burp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, twitch, whimper")
|
||||
else
|
||||
to_chat(src, text("Invalid Emote: []", act))
|
||||
if((message && src.stat == 0))
|
||||
log_emote(message, src)
|
||||
if(m_type & 1)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(message, m_type)
|
||||
//Foreach goto(703)
|
||||
else
|
||||
for(var/mob/O in hearers(src, null))
|
||||
O.show_message(message, m_type)
|
||||
//Foreach goto(746)
|
||||
return
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Emotes usable by brains, but only while they're in MMIs.
|
||||
*/
|
||||
/datum/emote/living/carbon/brain
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/brain)
|
||||
mob_type_blacklist_typecache = null
|
||||
/// The message that will be displayed to themselves, since brains can't really see their own emotes
|
||||
var/self_message
|
||||
|
||||
/datum/emote/living/carbon/brain/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
if(self_message)
|
||||
to_chat(user, self_message)
|
||||
|
||||
/datum/emote/living/carbon/brain/can_run_emote(mob/user, status_check, intentional)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
var/mob/living/carbon/brain/B = user
|
||||
|
||||
if(!(B.container && istype(B.container, /obj/item/mmi))) // No MMI, no emotes
|
||||
return FALSE
|
||||
|
||||
// So, brains can't really see their own emotes so we'll probably just want to send an extra message
|
||||
|
||||
/datum/emote/living/carbon/brain/alarm
|
||||
key = "alarm"
|
||||
key_third_person = "alarms"
|
||||
message = "sounds an alarm."
|
||||
self_message = "You sound an alarm."
|
||||
|
||||
/datum/emote/living/carbon/brain/alert
|
||||
key = "alert"
|
||||
key_third_person = "alerts"
|
||||
message = "lets out a distressed noise."
|
||||
self_message = "You let out a distressed noise."
|
||||
|
||||
/datum/emote/living/carbon/brain/notice
|
||||
key = "notice"
|
||||
message = "plays a loud tone."
|
||||
self_message = "You play a loud tone."
|
||||
|
||||
/datum/emote/living/carbon/brain/flash
|
||||
key = "flash"
|
||||
message = "starts flashing its lights quickly!"
|
||||
|
||||
/datum/emote/living/carbon/brain/whistle
|
||||
key = "whistle"
|
||||
key_third_person = "whistles"
|
||||
message = "whistles."
|
||||
self_message = "You whistle."
|
||||
|
||||
/datum/emote/living/carbon/brain/beep
|
||||
key = "beep"
|
||||
key_third_person = "beeps"
|
||||
message = "beeps."
|
||||
self_message = "You beep."
|
||||
|
||||
/datum/emote/living/carbon/brain/boop
|
||||
key = "boop"
|
||||
key_third_person = "boops"
|
||||
message = "boops."
|
||||
self_message = "You boop."
|
||||
@@ -1,51 +0,0 @@
|
||||
/mob/living/carbon/brain/emote(act,m_type = 1, message = null, force)
|
||||
if(!(container && istype(container, /obj/item/mmi)))//No MMI, no emotes
|
||||
return
|
||||
|
||||
if(findtext(act, "-", 1, null))
|
||||
var/t1 = findtext(act, "-", 1, null)
|
||||
act = copytext(act, 1, t1)
|
||||
|
||||
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
|
||||
act = copytext(act,1,length(act))
|
||||
|
||||
if(src.stat == DEAD)
|
||||
return
|
||||
act = lowertext(act)
|
||||
switch(act)
|
||||
|
||||
if("alarm")
|
||||
to_chat(src, "You sound an alarm.")
|
||||
message = "<B>\The [src]</B> sounds an alarm."
|
||||
m_type = 2
|
||||
if("alert")
|
||||
to_chat(src, "You let out a distressed noise.")
|
||||
message = "<B>\The [src]</B> lets out a distressed noise."
|
||||
m_type = 2
|
||||
if("notice")
|
||||
to_chat(src, "You play a loud tone.")
|
||||
message = "<B>\The [src]</B> plays a loud tone."
|
||||
m_type = 2
|
||||
if("flash")
|
||||
message = "The lights on <B>\the [src]</B> flash quickly."
|
||||
m_type = 1
|
||||
if("blink")
|
||||
message = "<B>\The [src]</B> blinks."
|
||||
m_type = 1
|
||||
if("whistle")
|
||||
to_chat(src, "You whistle.")
|
||||
message = "<B>\The [src]</B> whistles."
|
||||
m_type = 2
|
||||
if("beep")
|
||||
to_chat(src, "You beep.")
|
||||
message = "<B>\The [src]</B> beeps."
|
||||
m_type = 2
|
||||
if("boop")
|
||||
to_chat(src, "You boop.")
|
||||
message = "<B>\The [src]</B> boops."
|
||||
m_type = 2
|
||||
if("help")
|
||||
to_chat(src, "alarm, alert, notice, flash,blink, whistle, beep, boop")
|
||||
|
||||
if(message && !stat)
|
||||
..()
|
||||
@@ -0,0 +1,190 @@
|
||||
/datum/emote/living/carbon
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon)
|
||||
mob_type_blacklist_typecache = list(/mob/living/carbon/brain)
|
||||
|
||||
/datum/emote/living/carbon/blink
|
||||
key = "blink"
|
||||
key_third_person = "blinks"
|
||||
message = "blinks."
|
||||
|
||||
/datum/emote/living/carbon/blink_r
|
||||
key = "blink_r"
|
||||
message = "blinks rapidly."
|
||||
|
||||
/datum/emote/living/carbon/clap
|
||||
key = "clap"
|
||||
key_third_person = "claps"
|
||||
message = "claps."
|
||||
message_mime = "claps silently."
|
||||
message_param = "claps at %t."
|
||||
emote_type = EMOTE_SOUND
|
||||
vary = TRUE
|
||||
|
||||
/datum/emote/living/carbon/clap/run_emote(mob/user, params, type_override, intentional)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!H.bodyparts_by_name[BODY_ZONE_L_ARM] || !H.bodyparts_by_name[BODY_ZONE_R_ARM])
|
||||
if(!H.bodyparts_by_name[BODY_ZONE_L_ARM] && !H.bodyparts_by_name[BODY_ZONE_R_ARM])
|
||||
// no arms...
|
||||
to_chat(user, "<span class='warning'>You need arms to be able to clap.</span>")
|
||||
else
|
||||
// well, we've got at least one
|
||||
user.visible_message("[user] makes the sound of one hand clapping.")
|
||||
return TRUE
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/emote/living/carbon/clap/get_sound(mob/living/user)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!H?.mind.miming)
|
||||
return pick(
|
||||
'sound/misc/clap1.ogg',
|
||||
'sound/misc/clap2.ogg',
|
||||
'sound/misc/clap3.ogg',
|
||||
'sound/misc/clap4.ogg')
|
||||
|
||||
/datum/emote/living/carbon/cross
|
||||
key = "cross"
|
||||
key_third_person = "crosses"
|
||||
message = "crosses their arms."
|
||||
hands_use_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/chuckle
|
||||
key = "chuckle"
|
||||
key_third_person = "chuckles"
|
||||
message = "chuckles."
|
||||
message_mime = "appears to chuckle."
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
muzzled_noises = list("joyful", "upbeat")
|
||||
|
||||
/datum/emote/living/carbon/cough
|
||||
key = "cough"
|
||||
key_third_person = "coughs"
|
||||
message = "coughs!"
|
||||
message_mime = "appears to cough!"
|
||||
emote_type = EMOTE_SOUND | EMOTE_MOUTH
|
||||
vary = TRUE
|
||||
age_based = TRUE
|
||||
volume = 120
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/carbon/cough/get_sound(mob/living/user)
|
||||
. = ..()
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.gender == FEMALE)
|
||||
if(H.dna.species.female_cough_sounds)
|
||||
return pick(H.dna.species.female_cough_sounds)
|
||||
else
|
||||
if(H.dna.species.male_cough_sounds)
|
||||
return pick(H.dna.species.male_cough_sounds)
|
||||
|
||||
/datum/emote/living/carbon/moan
|
||||
key = "moan"
|
||||
key_third_person = "moans"
|
||||
message = "moans!"
|
||||
message_mime = "appears to moan!"
|
||||
muzzled_noises = list("pained")
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/carbon/giggle
|
||||
key = "giggle"
|
||||
key_third_person = "giggles"
|
||||
message = "giggles."
|
||||
message_mime = "giggles silently!"
|
||||
muzzled_noises = list("bubbly")
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
|
||||
/datum/emote/living/carbon/gurgle
|
||||
key = "gurgle"
|
||||
key_third_person = "gurgles"
|
||||
message = "makes an uncomfortable gurgle."
|
||||
muzzled_noises = list("unpleasant", "guttural")
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/carbon/inhale
|
||||
key = "inhale"
|
||||
key_third_person = "inhales"
|
||||
message = "breathes in."
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
muzzled_noises = list("breathy")
|
||||
|
||||
/datum/emote/living/carbon/inhale/sharp
|
||||
key = "inhale_s"
|
||||
key_third_person = "inhales sharply!"
|
||||
message = "takes a deep breath!"
|
||||
|
||||
/datum/emote/living/carbon/kiss
|
||||
key = "kiss"
|
||||
key_third_person = "kisses"
|
||||
message = "blows a kiss."
|
||||
message_param = "blows a kiss at %t!"
|
||||
muzzled_noises = list("smooching")
|
||||
|
||||
/datum/emote/living/carbon/wave
|
||||
key = "wave"
|
||||
key_third_person = "waves"
|
||||
message = "waves."
|
||||
message_param = "waves at %t."
|
||||
hands_use_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/yawn
|
||||
key = "yawn"
|
||||
key_third_person = "yawns"
|
||||
message = "yawns."
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
muzzled_noises = list("tired", "lazy", "sleepy")
|
||||
|
||||
/datum/emote/living/carbon/exhale
|
||||
key = "exhale"
|
||||
key_third_person = "exhales"
|
||||
message = "breathes out."
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
|
||||
/datum/emote/living/carbon/laugh
|
||||
key = "laugh"
|
||||
key_third_person = "laughs"
|
||||
message = "laughs."
|
||||
message_mime = "laughs silently!"
|
||||
message_param = "laughs at %t."
|
||||
muzzled_noises = list("happy", "joyful")
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
|
||||
/datum/emote/living/carbon/scowl
|
||||
key = "scowl"
|
||||
key_third_person = "scowls"
|
||||
message = "scowls."
|
||||
|
||||
/datum/emote/living/groan
|
||||
key = "groan"
|
||||
key_third_person = "groans"
|
||||
message = "groans!"
|
||||
message_mime = "appears to groan!"
|
||||
message_param = "groans at %t."
|
||||
muzzled_noises = list("pained")
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/carbon/sign
|
||||
key = "sign"
|
||||
key_third_person = "signs"
|
||||
message = "signs."
|
||||
message_param = "signs the number %t."
|
||||
param_desc = "number(0-10)"
|
||||
// Humans get their own proc since they have fingers
|
||||
mob_type_blacklist_typecache = list(/mob/living/carbon/human)
|
||||
hands_use_check = TRUE
|
||||
target_behavior = EMOTE_TARGET_BHVR_NUM
|
||||
|
||||
/datum/emote/living/carbon/faint
|
||||
key = "faint"
|
||||
key_third_person = "faints"
|
||||
message = "faints."
|
||||
|
||||
/datum/emote/living/carbon/faint/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
if(. && isliving(user))
|
||||
var/mob/living/L = user
|
||||
L.SetSleeping(2 SECONDS)
|
||||
@@ -86,8 +86,6 @@
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/death(gibbed)
|
||||
if(can_die() && !gibbed && deathgasp_on_death)
|
||||
emote("deathgasp", force = TRUE) //let the world KNOW WE ARE DEAD
|
||||
|
||||
// Only execute the below if we successfully died
|
||||
. = ..(gibbed)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2015,3 +2015,21 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
|
||||
to_chat(usr, "[src] does not have any stored infomation!")
|
||||
else
|
||||
to_chat(usr, "OOC Metadata is not supported by this server!")
|
||||
|
||||
/mob/living/carbon/human/verb/pose()
|
||||
set name = "Set Pose"
|
||||
set desc = "Sets a description which will be shown when someone examines you."
|
||||
set category = "IC"
|
||||
|
||||
// no metagaming
|
||||
if(stat)
|
||||
return
|
||||
|
||||
pose = sanitize(copytext(input(usr, "This is [src]. [p_they(TRUE)] [p_are()]...", "Pose", null) as text, 1, MAX_MESSAGE_LEN))
|
||||
|
||||
/mob/living/carbon/human/verb/set_flavor()
|
||||
set name = "Set Flavour Text"
|
||||
set desc = "Sets an extended description of your character's features."
|
||||
set category = "IC"
|
||||
|
||||
update_flavor_text()
|
||||
|
||||
@@ -0,0 +1,686 @@
|
||||
/datum/emote/living/carbon/human
|
||||
/// Custom messages that should be applied based on species
|
||||
/// Should be an associative list of species name: message
|
||||
var/species_custom_messages = list()
|
||||
/// Custom messages applied to mimes of a particular species
|
||||
var/species_custom_mime_messages = list()
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/human)
|
||||
|
||||
/datum/emote/living/carbon/human/select_message_type(mob/user, msg, intentional)
|
||||
. = ..()
|
||||
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
|
||||
if(!species_custom_messages || (human_user.mind?.miming && !species_custom_mime_messages))
|
||||
return .
|
||||
|
||||
var/custom_message
|
||||
if(user.mind?.miming)
|
||||
custom_message = species_custom_mime_messages[human_user.dna.species?.name]
|
||||
else
|
||||
custom_message = species_custom_messages[human_user.dna.species?.name]
|
||||
|
||||
if(custom_message)
|
||||
return custom_message
|
||||
|
||||
/datum/emote/living/carbon/human/run_emote(mob/user, params, type_override, intentional)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if((emote_type & EMOTE_MOUTH) && !H.mind?.miming)
|
||||
if(H.getOxyLoss() > 10 || H.AmountLoseBreath() >= 8 SECONDS) // no screaming if you don't have enough breath to scream
|
||||
H.emote("gasp")
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/datum/emote/living/carbon/human/airguitar
|
||||
key = "airguitar"
|
||||
message = "is strumming the air and headbanging like a safari chimp."
|
||||
emote_type = EMOTE_VISIBLE
|
||||
hands_use_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/human/cry
|
||||
key = "cry"
|
||||
key_third_person = "cries"
|
||||
message = "cries."
|
||||
muzzled_noises = list("weak", "pathetic", "sad")
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
|
||||
/datum/emote/living/carbon/human/dap
|
||||
key = "dap"
|
||||
key_third_person = "daps"
|
||||
message = "sadly can't find anybody to give daps to, and daps themself. Shameful."
|
||||
message_param = "give daps to %t."
|
||||
emote_target_type = EMOTE_TARGET_MOB
|
||||
hands_use_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/human/eyebrow
|
||||
key = "eyebrow"
|
||||
message = "raises an eyebrow."
|
||||
message_param = "raises an eyebrow at %t."
|
||||
|
||||
/datum/emote/living/carbon/human/grumble
|
||||
key = "grumble"
|
||||
key_third_person = "grumbles"
|
||||
message = "grumbles!"
|
||||
message_mime = "seems to grumble!"
|
||||
message_postfix = "at %t!"
|
||||
muzzled_noises = list("bothered")
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
|
||||
/datum/emote/living/carbon/human/hug
|
||||
key = "hug"
|
||||
key_third_person = "hugs"
|
||||
message = "hugs themselves."
|
||||
message_param = "hugs %t."
|
||||
hands_use_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/human/mumble
|
||||
key = "mumble"
|
||||
key_third_person = "mumbles"
|
||||
message = "mumbles!"
|
||||
message_mime = "seems to be speaking sweet nothings!"
|
||||
message_postfix = "at %t!"
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
|
||||
/datum/emote/living/carbon/human/nod
|
||||
key = "nod"
|
||||
key_third_person = "nods"
|
||||
message = "nods their head."
|
||||
message_param = "nods their head at %t."
|
||||
|
||||
/datum/emote/living/carbon/human/scream
|
||||
key = "scream"
|
||||
key_third_person = "screams"
|
||||
message = "screams!"
|
||||
message_mime = "acts out a scream!"
|
||||
message_postfix = "at %t!"
|
||||
muzzled_noises = list("very loud")
|
||||
emote_type = EMOTE_SOUND | EMOTE_MOUTH
|
||||
only_forced_audio = FALSE
|
||||
vary = TRUE
|
||||
age_based = TRUE
|
||||
cooldown = 5 SECONDS
|
||||
mob_type_blacklist_typecache = list(
|
||||
/mob/living/carbon/human/monkey, // screech instead
|
||||
/mob/living/silicon // Robot sounds
|
||||
)
|
||||
|
||||
/datum/emote/living/carbon/human/scream/select_message_type(mob/user, msg, intentional)
|
||||
. = ..()
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.dna.species?.scream_verb)
|
||||
if(H.mind?.miming)
|
||||
return "[H.dna.species?.scream_verb] silently!"
|
||||
else
|
||||
return "[H.dna.species?.scream_verb]!"
|
||||
|
||||
/datum/emote/living/carbon/human/scream/get_sound(mob/living/user)
|
||||
var/mob/living/carbon/human/human = user
|
||||
if(human.mind?.miming || !istype(human))
|
||||
return
|
||||
if(human.gender == FEMALE)
|
||||
return human.dna.species.female_scream_sound
|
||||
else
|
||||
return human.dna.species.male_scream_sound
|
||||
|
||||
/datum/emote/living/carbon/human/gasp
|
||||
key = "gasp"
|
||||
key_third_person = "gasps"
|
||||
message = "gasps!"
|
||||
message_mime = "appears to be gasping!"
|
||||
emote_type = EMOTE_SOUND // Don't make this one a mouth emote since we don't want it to be caught by nobreath
|
||||
age_based = TRUE
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
volume = 100
|
||||
|
||||
/datum/emote/living/carbon/human/gasp/get_sound(mob/user)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.is_muzzled())
|
||||
// If you're muzzled you're not making noise
|
||||
return
|
||||
|
||||
if(H.health > 0)
|
||||
return H.dna.species.gasp_sound
|
||||
|
||||
if(H.gender == FEMALE)
|
||||
return pick(H.dna.species.female_dying_gasp_sounds)
|
||||
else
|
||||
return pick(H.dna.species.male_dying_gasp_sounds)
|
||||
|
||||
/datum/emote/living/carbon/human/shake
|
||||
key = "shake"
|
||||
key_third_person = "shakes"
|
||||
message = "shakes their head."
|
||||
message_param = "shakes their head at %t."
|
||||
|
||||
/datum/emote/living/carbon/human/pale
|
||||
key = "pale"
|
||||
message = "goes pale for a second."
|
||||
|
||||
/datum/emote/living/carbon/human/raise
|
||||
key = "raise"
|
||||
key_third_person = "raises"
|
||||
message = "raises a hand."
|
||||
hands_use_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/human/salute
|
||||
key = "salute"
|
||||
key_third_person = "salutes"
|
||||
message = "salutes."
|
||||
message_param = "salutes to %t."
|
||||
hands_use_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/human/shrug
|
||||
key = "shrug"
|
||||
key_third_person = "shrugs"
|
||||
message = "shrugs."
|
||||
|
||||
/datum/emote/living/carbon/human/sniff
|
||||
key = "sniff"
|
||||
key_third_person = "sniff"
|
||||
message = "sniffs."
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
|
||||
/datum/emote/living/carbon/human/johnny
|
||||
key = "johnny"
|
||||
message = "takes a drag from a cigarette and blows their own name out in smoke."
|
||||
message_param = "dummy" // Gets handled in select_param
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
target_behavior = EMOTE_TARGET_BHVR_DEFAULT_TO_BASE
|
||||
emote_target_type = EMOTE_TARGET_MOB
|
||||
|
||||
/datum/emote/living/carbon/human/johnny/select_param(mob/user, params)
|
||||
if(!params)
|
||||
return message
|
||||
var/mob/target = find_target(user, params, EMOTE_TARGET_MOB)
|
||||
if(!target)
|
||||
return message
|
||||
var/msg = message
|
||||
if(user.mind?.miming)
|
||||
msg = "takes a drag from a cigarette and blows \"[target.name]\" out in smoke."
|
||||
else
|
||||
msg = "says, \"[target.name], please. They had a family.\" [user] takes a drag from a cigarette and blows [user.p_their()] name out in smoke."
|
||||
return msg
|
||||
|
||||
/datum/emote/living/carbon/human/johnny/run_emote(mob/user, params, type_override, intentional)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!istype(H.wear_mask, /obj/item/clothing/mask/cigarette))
|
||||
to_chat(user, "<span class='warning'>You can't be that cool without a cigarette between your lips.</span>")
|
||||
return TRUE
|
||||
|
||||
var/obj/item/clothing/mask/cigarette/cig = H.wear_mask
|
||||
|
||||
if(!cig.lit)
|
||||
to_chat(user, "<span class='warning'>You have to light that [cig] first, cool cat.</span>")
|
||||
return TRUE
|
||||
|
||||
if(H.getOxyLoss() > 30)
|
||||
user.visible_message(
|
||||
"<span class='warning'>[user] gasps for air and swallows their cigarette!</span>",
|
||||
"<span class='warning'>You gasp for air and accidentally swallow your [cig]!</span>"
|
||||
)
|
||||
if(cig.lit)
|
||||
to_chat(user, "<span class='userdanger'>The lit [cig] burns on the way down!")
|
||||
user.unEquip(cig)
|
||||
qdel(cig)
|
||||
H.adjustFireLoss(5)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/datum/emote/living/carbon/human/sneeze
|
||||
key = "sneeze"
|
||||
key_third_person = "sneezes"
|
||||
message = "sneezes."
|
||||
muzzled_noises = list("strange", "sharp")
|
||||
emote_type = EMOTE_SOUND | EMOTE_MOUTH
|
||||
volume = 70
|
||||
|
||||
/datum/emote/living/carbon/human/sneeze/get_sound(mob/user)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.gender == FEMALE)
|
||||
return H.dna.species.female_sneeze_sound
|
||||
else
|
||||
return H.dna.species.male_sneeze_sound
|
||||
|
||||
/datum/emote/living/carbon/human/slap
|
||||
key = "slap"
|
||||
key_third_person = "slaps"
|
||||
hands_use_check = TRUE
|
||||
cooldown = 3 SECONDS // to prevent endless table slamming
|
||||
|
||||
/datum/emote/living/carbon/human/slap/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
var/obj/item/slapper/N = new(user)
|
||||
if(user.put_in_hands(N))
|
||||
to_chat(user, "<span class='notice'>You ready your slapping hand.</span>")
|
||||
else
|
||||
qdel(N)
|
||||
to_chat(user, "<span class='warning'>You're incapable of slapping in your current state.</span>")
|
||||
|
||||
/datum/emote/living/carbon/human/wink
|
||||
key = "wink"
|
||||
key_third_person = "winks"
|
||||
message = "winks."
|
||||
|
||||
/datum/emote/living/carbon/human/highfive
|
||||
key = "highfive"
|
||||
key_third_person = "highfives"
|
||||
message = "requests a highfive."
|
||||
hands_use_check = TRUE
|
||||
cooldown = 3 SECONDS
|
||||
|
||||
/datum/emote/living/carbon/human/highfive/can_run_emote(mob/user, status_check, intentional)
|
||||
. = ..()
|
||||
var/mob/living/carbon/user_carbon = user
|
||||
if(user_carbon.restrained())
|
||||
return FALSE
|
||||
|
||||
/datum/emote/living/carbon/human/highfive/proc/wiz_cleanup(mob/user, mob/highfived)
|
||||
user.status_flags &= ~GODMODE
|
||||
highfived.status_flags &= ~GODMODE
|
||||
|
||||
/datum/emote/living/carbon/human/highfive/run_emote(mob/user, params, type_override, intentional)
|
||||
var/mob/living/carbon/user_carbon = user
|
||||
if(user_carbon.has_status_effect(STATUS_EFFECT_HIGHFIVE))
|
||||
user.visible_message("[user.name] shakes [user.p_their()] hand around slightly, impatiently waiting for someone to high-five them.")
|
||||
return TRUE
|
||||
user_carbon.apply_status_effect(STATUS_EFFECT_HIGHFIVE)
|
||||
for(var/mob/living/L in orange(1))
|
||||
if(L.has_status_effect(STATUS_EFFECT_HIGHFIVE) && L != user)
|
||||
if(iswizard(user) && iswizard(L))
|
||||
user.visible_message("<span class='biggerdanger'><b>[user.name]</b> and <b>[L.name]</b> high-five EPICALLY!</span>")
|
||||
user_carbon.status_flags |= GODMODE
|
||||
L.status_flags |= GODMODE
|
||||
explosion(get_turf(user), 5, 2, 1, 3)
|
||||
// explosions have a spawn so this makes sure that we don't get gibbed
|
||||
addtimer(CALLBACK(src, .proc/wiz_cleanup, user_carbon, L), 1)
|
||||
user_carbon.remove_status_effect(STATUS_EFFECT_HIGHFIVE)
|
||||
L.remove_status_effect(STATUS_EFFECT_HIGHFIVE)
|
||||
return TRUE
|
||||
user.visible_message("<b>[user.name]</b> and <b>[L.name]</b> high-five!")
|
||||
playsound(user, 'sound/effects/snap.ogg', 50)
|
||||
user_carbon.remove_status_effect(STATUS_EFFECT_HIGHFIVE)
|
||||
L.remove_status_effect(STATUS_EFFECT_HIGHFIVE)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/datum/emote/living/carbon/human/handshake
|
||||
key = "handshake"
|
||||
message = "holds out their hand."
|
||||
hands_use_check = TRUE
|
||||
emote_target_type = EMOTE_TARGET_MOB
|
||||
target_behavior = EMOTE_TARGET_BHVR_DEFAULT_TO_BASE
|
||||
|
||||
/datum/emote/living/carbon/human/handshake/act_on_target(mob/user, target)
|
||||
. = ..()
|
||||
if(!target)
|
||||
user.visible_message(
|
||||
"[user] seems to shake hands with empty space.",
|
||||
"You shake the air's hand."
|
||||
)
|
||||
return EMOTE_ACT_STOP_EXECUTION
|
||||
|
||||
if(!user.Adjacent(target) || !ishuman(target))
|
||||
message_param = "extends a hand towards %t."
|
||||
return TRUE
|
||||
|
||||
var/mob/living/carbon/human/human_target = target
|
||||
|
||||
if(human_target.canmove && !human_target.r_hand && !human_target.restrained())
|
||||
message_param = "shakes hands with %t."
|
||||
else
|
||||
message_param = "holds out [user.p_their()] hand to %t."
|
||||
|
||||
/datum/emote/living/carbon/human/handshake/run_emote(mob/user, params, type_override, intentional)
|
||||
var/mob/living/target
|
||||
for(var/mob/living/A in oview(5, user))
|
||||
if(params == A.name)
|
||||
target = A
|
||||
|
||||
if(!target)
|
||||
user.visible_message(
|
||||
"[user] seems to shake hands with empty space.",
|
||||
"You shake the air's hand."
|
||||
)
|
||||
return TRUE
|
||||
|
||||
if(target.canmove && !target.r_hand && !target.restrained())
|
||||
message_param = "shakes hands with %t."
|
||||
else
|
||||
message_param = "holds out [user.p_their()] hand to %t."
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/emote/living/carbon/human/snap
|
||||
key = "snap"
|
||||
key_third_person = "snaps"
|
||||
message = "snaps their fingers."
|
||||
message_param = "snaps their fingers at %t."
|
||||
sound = "sound/effects/fingersnap.ogg"
|
||||
emote_type = EMOTE_SOUND
|
||||
|
||||
/datum/emote/living/carbon/human/snap/run_emote(mob/user, params, type_override, intentional)
|
||||
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/organ/external/LH = H.get_organ("l_hand")
|
||||
var/obj/item/organ/external/RH = H.get_organ("r_hand")
|
||||
var/left_hand_good = FALSE
|
||||
var/right_hand_good = FALSE
|
||||
if(LH && !(LH.status & ORGAN_SPLINTED) && !(LH.status & ORGAN_BROKEN))
|
||||
left_hand_good = TRUE
|
||||
if(RH && !(RH.status & ORGAN_SPLINTED) && !(RH.status & ORGAN_BROKEN))
|
||||
right_hand_good = TRUE
|
||||
|
||||
if(!left_hand_good && !right_hand_good)
|
||||
to_chat(user, "You need at least one hand in good working order to snap your fingers.")
|
||||
return TRUE
|
||||
|
||||
if(prob(5))
|
||||
user.visible_message("<span class='danger'><b>[user]</b> snaps [p_their()] fingers right off!</span>")
|
||||
playsound(user.loc, 'sound/effects/snap.ogg', 50, 1)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/datum/emote/living/carbon/human/fart
|
||||
key = "fart"
|
||||
key_third_person = "farts"
|
||||
message = "farts."
|
||||
message_param = "farts in %t's general direction."
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
|
||||
/datum/emote/living/carbon/human/fart/run_emote(mob/user, params, type_override, intentional)
|
||||
var/farted_on_something = FALSE
|
||||
for(var/atom/A in get_turf(user))
|
||||
farted_on_something = A.fart_act(user) || farted_on_something
|
||||
if(!farted_on_something)
|
||||
return ..()
|
||||
|
||||
/datum/emote/living/carbon/sign/signal
|
||||
key = "signal"
|
||||
key_third_person = "signals"
|
||||
message_param = "raises %t fingers."
|
||||
param_desc = "number(0-10)"
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/human)
|
||||
hands_use_check = TRUE
|
||||
|
||||
|
||||
/////////
|
||||
// Species-specific emotes
|
||||
|
||||
/datum/emote/living/carbon/human/wag
|
||||
key = "wag"
|
||||
key_third_person = "wags"
|
||||
message = "starts wagging their tail."
|
||||
emote_type = EMOTE_VISIBLE | EMOTE_FORCE_NO_RUNECHAT
|
||||
species_type_whitelist_typecache = list(
|
||||
/datum/species/unathi,
|
||||
/datum/species/vulpkanin,
|
||||
/datum/species/tajaran,
|
||||
/datum/species/vox
|
||||
)
|
||||
|
||||
/datum/emote/living/carbon/human/proc/can_wag(mob/user)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!(H.dna.species.bodyflags & TAIL_WAGGING))
|
||||
return FALSE
|
||||
var/obscured = H.wear_suit && (H.wear_suit.flags_inv & HIDETAIL)
|
||||
if(!istype(H))
|
||||
return FALSE
|
||||
if(istype(H.body_accessory, /datum/body_accessory/tail))
|
||||
if(!H.body_accessory.try_restrictions(user))
|
||||
return FALSE
|
||||
|
||||
if(H.dna.species.bodyflags & TAIL_WAGGING && obscured)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/emote/living/carbon/human/wag/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.start_tail_wagging()
|
||||
|
||||
|
||||
/datum/emote/living/carbon/human/wag/can_run_emote(mob/user, status_check = TRUE, intentional)
|
||||
if(!..())
|
||||
return FALSE
|
||||
|
||||
if(!can_wag(user))
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/emote/living/carbon/human/wag/stop
|
||||
key = "swag" // B)
|
||||
key_third_person = "swags"
|
||||
message = "stops wagging their tail."
|
||||
|
||||
/datum/emote/living/carbon/human/wag/stop/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.stop_tail_wagging()
|
||||
|
||||
///Snowflake emotes only for le epic chimp
|
||||
/datum/emote/living/carbon/human/monkey
|
||||
species_type_whitelist_typecache = list(/datum/species/monkey)
|
||||
|
||||
|
||||
// Note: subtype of human scream, not monkey, so we need the overrides.
|
||||
/datum/emote/living/carbon/human/scream/screech
|
||||
key = "screech"
|
||||
key_third_person = "screeches"
|
||||
message = "screeches!"
|
||||
message_param = "screeches at %t!"
|
||||
vary = FALSE
|
||||
mob_type_blacklist_typecache = list()
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/human/monkey)
|
||||
species_type_whitelist_typecache = list(/datum/species/monkey)
|
||||
|
||||
/datum/emote/living/carbon/human/scream/screech/roar
|
||||
key = "roar"
|
||||
key_third_person = "roars"
|
||||
message = "roars!"
|
||||
message_param = "roars at %t!"
|
||||
|
||||
/datum/emote/living/carbon/human/monkey/gnarl
|
||||
key = "gnarl"
|
||||
key_third_person = "gnarls"
|
||||
message = "gnarls and shows their teeth!"
|
||||
message_param = "gnarls and shows their teeth at %t."
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
|
||||
/datum/emote/living/carbon/human/monkey/roll
|
||||
key = "roll"
|
||||
key_third_person = "rolls"
|
||||
message = "rolls."
|
||||
hands_use_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/human/monkey/roll/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
if(.)
|
||||
user.SpinAnimation(10, 1)
|
||||
|
||||
/datum/emote/living/carbon/human/monkey/scratch
|
||||
key = "scratch"
|
||||
key_third_person = "scratches"
|
||||
message = "scratches."
|
||||
hands_use_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/human/monkey/tail
|
||||
key = "tail"
|
||||
message = "waves their tail."
|
||||
|
||||
///////
|
||||
// More specific human species emotes
|
||||
|
||||
/datum/emote/living/carbon/human/flap
|
||||
key = "flap"
|
||||
key_third_person = "flaps"
|
||||
message = "flaps their wings."
|
||||
species_type_whitelist_typecache = list(/datum/species/moth)
|
||||
|
||||
/datum/emote/living/carbon/human/flap/angry
|
||||
key = "aflap"
|
||||
key_third_person = "aflaps"
|
||||
message = "flaps their wings ANGRILY!"
|
||||
|
||||
/datum/emote/living/carbon/human/flutter
|
||||
key = "flutter"
|
||||
key_third_person = "flutters"
|
||||
message = "flutters their wings."
|
||||
species_type_whitelist_typecache = list(/datum/species/moth)
|
||||
|
||||
/datum/emote/living/carbon/human/quill
|
||||
key = "quill"
|
||||
key_third_person = "quills"
|
||||
message = "rustles their quills."
|
||||
message_param = "rustles their quills at %t."
|
||||
emote_type = EMOTE_SOUND
|
||||
age_based = TRUE
|
||||
// Credit to sound-ideas (freesfx.co.uk) for the sound.
|
||||
sound = "sound/effects/voxrustle.ogg"
|
||||
species_type_whitelist_typecache = list(/datum/species/vox)
|
||||
|
||||
/datum/emote/living/carbon/human/warble
|
||||
key = "warble"
|
||||
key_third_person = "warbles"
|
||||
message = "warbles."
|
||||
message_param = "warbles at %t."
|
||||
emote_type = EMOTE_SOUND
|
||||
age_based = TRUE
|
||||
// Copyright CC BY 3.0 alienistcog (freesound.org) for the sound.
|
||||
sound = "sound/effects/warble.ogg"
|
||||
species_type_whitelist_typecache = list(/datum/species/skrell)
|
||||
|
||||
/datum/emote/living/carbon/human/clack
|
||||
key = "clack"
|
||||
key_third_person = "clacks"
|
||||
message = "clacks their mandibles."
|
||||
message_param = "clacks their mandibles at %t."
|
||||
species_type_whitelist_typecache = list(/datum/species/kidan)
|
||||
emote_type = EMOTE_SOUND
|
||||
audio_cooldown = 3 SECONDS
|
||||
age_based = TRUE
|
||||
// Credit to DrMinky (freesound.org) for the sound.
|
||||
sound = "sound/effects/Kidanclack.ogg"
|
||||
|
||||
/datum/emote/living/carbon/human/clack/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
mineral_scan_pulse(get_turf(src), range = world.view)
|
||||
|
||||
/datum/emote/living/carbon/human/clack/click
|
||||
key = "click"
|
||||
key_third_person = "clicks"
|
||||
message = "clicks their mandibles."
|
||||
message_param = "clicks their mandibles at %t."
|
||||
// Credit to DrMinky (freesound.org) for the sound.
|
||||
sound = "sound/effects/Kidanclack2.ogg"
|
||||
|
||||
/datum/emote/living/carbon/human/drask_talk
|
||||
species_type_whitelist_typecache = list(/datum/species/drask)
|
||||
emote_type = EMOTE_SOUND
|
||||
age_based = TRUE
|
||||
sound = "sound/voice/drasktalk.ogg"
|
||||
|
||||
/datum/emote/living/carbon/human/drask_talk/drone
|
||||
key = "drone"
|
||||
key_third_person = "drones"
|
||||
message = "drones."
|
||||
message_param = "drones at %t."
|
||||
|
||||
/datum/emote/living/carbon/human/drask_talk/hum
|
||||
key = "hum"
|
||||
key_third_person = "hums"
|
||||
message = "hums."
|
||||
message_param = "hums at %t."
|
||||
|
||||
/datum/emote/living/carbon/human/drask_talk/rumble
|
||||
key = "rumble"
|
||||
key_third_person = "rumbles"
|
||||
message = "rumbles."
|
||||
message_param = "rumbles at %t."
|
||||
|
||||
/datum/emote/living/carbon/human/hiss
|
||||
key = "hiss"
|
||||
key_third_person = "hisses"
|
||||
message = "hisses."
|
||||
message_param = "hisses at %t."
|
||||
species_type_whitelist_typecache = list(/datum/species/unathi)
|
||||
emote_type = EMOTE_SOUND | EMOTE_MOUTH
|
||||
age_based = TRUE
|
||||
// Credit to Jamius (freesound.org) for the sound.
|
||||
sound = "sound/effects/unathihiss.ogg"
|
||||
muzzled_noises = list("weak hissing")
|
||||
|
||||
/datum/emote/living/carbon/human/creak
|
||||
key = "creak"
|
||||
key_third_person = "creaks"
|
||||
message = "creaks."
|
||||
message_param = "creaks at %t."
|
||||
emote_type = EMOTE_SOUND
|
||||
age_based = TRUE
|
||||
species_type_whitelist_typecache = list(/datum/species/diona)
|
||||
sound = "sound/voice/dionatalk1.ogg"
|
||||
|
||||
/datum/emote/living/carbon/human/squish
|
||||
key = "squish"
|
||||
key_third_person = "squishes"
|
||||
message = "squishes."
|
||||
message_param = "squishes at %t."
|
||||
emote_type = EMOTE_SOUND
|
||||
age_based = TRUE
|
||||
// Credit to DrMinky (freesound.org) for the sound.
|
||||
sound = "sound/effects/slime_squish.ogg"
|
||||
|
||||
/datum/emote/living/carbon/human/squish/can_run_emote(mob/user, status_check, intentional)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(isslimeperson(src)) //Only Slime People can squish
|
||||
return TRUE
|
||||
else
|
||||
var/mob/living/carbon/human/H = user
|
||||
for(var/obj/item/organ/external/L in H.bodyparts) // if your limbs are squishy you can squish too!
|
||||
if(istype(L.dna.species, /datum/species/slime))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/emote/living/carbon/human/howl
|
||||
key = "howl"
|
||||
key_third_person = "howls"
|
||||
message = "howls."
|
||||
message_mime = "acts out a howl."
|
||||
message_param = "howls at %t."
|
||||
species_type_whitelist_typecache = list(/datum/species/vulpkanin)
|
||||
emote_type = EMOTE_SOUND | EMOTE_MOUTH
|
||||
age_based = TRUE
|
||||
sound = "sound/goonstation/voice/howl.ogg"
|
||||
muzzled_noises = list("very loud")
|
||||
volume = 100
|
||||
cooldown = 10 SECONDS
|
||||
|
||||
/datum/emote/living/carbon/human/growl
|
||||
key = "growl"
|
||||
key_third_person = "growls"
|
||||
message = "growls."
|
||||
message_mime = "growls silently."
|
||||
message_param = "growls at %t."
|
||||
species_type_whitelist_typecache = list(/datum/species/vulpkanin)
|
||||
sound = "growls" // what the fuck why is this just top level
|
||||
volume = 80
|
||||
muzzled_noises = list("annoyed")
|
||||
emote_type = EMOTE_SOUND | EMOTE_MOUTH
|
||||
|
||||
/datum/emote/living/carbon/human/rattle
|
||||
key = "rattle"
|
||||
key_third_person = "rattles"
|
||||
message = "rattles their bones."
|
||||
message_param = "rattles their bones at %t."
|
||||
species_type_whitelist_typecache = list(/datum/species/skeleton, /datum/species/plasmaman)
|
||||
@@ -67,7 +67,7 @@
|
||||
if(!(lying || resting))
|
||||
if(!HAS_TRAIT(src, TRAIT_NOPAIN))
|
||||
emote("scream")
|
||||
custom_emote(1, "collapses!")
|
||||
emote("collapses")
|
||||
Weaken(10 SECONDS) //can't emote while weakened, apparently.
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
continue
|
||||
|
||||
var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ")
|
||||
custom_emote(1, "[HAS_TRAIT(src, TRAIT_NOPAIN) ? "" : emote_scream ]drops what [p_they()] [p_were()] holding in [p_their()] [E.name]!")
|
||||
custom_emote(EMOTE_VISIBLE, "[HAS_TRAIT(src, TRAIT_NOPAIN) ? "" : emote_scream ]drops what [p_they()] [p_were()] holding in [p_their()] [E.name]!")
|
||||
|
||||
else if(E.is_malfunctioning())
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
if(!unEquip(r_hand))
|
||||
continue
|
||||
|
||||
custom_emote(1, "drops what [p_they()] [p_were()] holding, [p_their()] [E.name] malfunctioning!")
|
||||
custom_emote(EMOTE_VISIBLE, "drops what [p_they()] [p_were()] holding, [p_their()] [E.name] malfunctioning!")
|
||||
|
||||
do_sparks(5, 0, src)
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
SetLoseBreath(0)
|
||||
|
||||
if(!gibbed && deathgasp_on_death)
|
||||
emote("deathgasp", force = TRUE)
|
||||
emote("deathgasp")
|
||||
|
||||
if(mind && suiciding)
|
||||
mind.suicided = TRUE
|
||||
|
||||
@@ -317,7 +317,7 @@
|
||||
/mob/living/attack_animal(mob/living/simple_animal/M)
|
||||
M.face_atom(src)
|
||||
if((M.a_intent == INTENT_HELP && M.ckey) || M.melee_damage_upper == 0)
|
||||
M.custom_emote(1, "[M.friendly] [src].")
|
||||
M.custom_emote(EMOTE_VISIBLE, "[M.friendly] [src].")
|
||||
return FALSE
|
||||
if(HAS_TRAIT(M, TRAIT_PACIFISM))
|
||||
to_chat(M, "<span class='warning'>You don't want to hurt anyone!</span>")
|
||||
|
||||
@@ -0,0 +1,434 @@
|
||||
/datum/emote/living
|
||||
mob_type_allowed_typecache = /mob/living
|
||||
mob_type_blacklist_typecache = list(
|
||||
/mob/living/carbon/brain, // nice try
|
||||
/mob/living/captive_brain,
|
||||
/mob/living/silicon,
|
||||
/mob/living/simple_animal/bot
|
||||
)
|
||||
message_postfix = "at %t."
|
||||
|
||||
/datum/emote/living/should_play_sound(mob/user, intentional)
|
||||
. = ..()
|
||||
if(user.mind?.miming)
|
||||
return FALSE // shh
|
||||
return .
|
||||
|
||||
/datum/emote/living/blush
|
||||
key = "blush"
|
||||
key_third_person = "blushes"
|
||||
message = "blushes."
|
||||
|
||||
/datum/emote/living/bow
|
||||
key = "bow"
|
||||
key_third_person = "bows"
|
||||
message = "bows."
|
||||
message_param = "bows to %t."
|
||||
message_postfix = "to %t."
|
||||
|
||||
/datum/emote/living/burp
|
||||
key = "burp"
|
||||
key_third_person = "burps"
|
||||
message = "burps."
|
||||
message_mime = "opens their mouth rather obnoxiously."
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
muzzled_noises = list("peculiar")
|
||||
|
||||
/datum/emote/living/choke
|
||||
key = "choke"
|
||||
key_third_person = "chokes"
|
||||
message = "chokes!"
|
||||
message_mime = "clutches their throat desperately!"
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
muzzled_noises = list("gagging", "strong")
|
||||
|
||||
/datum/emote/living/collapse
|
||||
key = "collapse"
|
||||
key_third_person = "collapses"
|
||||
message = "collapses!"
|
||||
emote_type = EMOTE_VISIBLE
|
||||
|
||||
/datum/emote/living/collapse/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
if(. && isliving(user))
|
||||
var/mob/living/L = user
|
||||
L.Paralyse(4 SECONDS)
|
||||
|
||||
/datum/emote/living/dance
|
||||
key = "dance"
|
||||
key_third_person = "dances"
|
||||
message = "dances around happily."
|
||||
|
||||
/datum/emote/living/jump
|
||||
key = "jump"
|
||||
key_third_person = "jumps"
|
||||
message = "jumps!"
|
||||
|
||||
/datum/emote/living/deathgasp
|
||||
key = "deathgasp"
|
||||
key_third_person = "deathgasps"
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE // make sure deathgasp gets runechatted regardless
|
||||
age_based = TRUE
|
||||
cooldown = 10 SECONDS
|
||||
volume = 40
|
||||
unintentional_stat_allowed = DEAD
|
||||
message = "seizes up and falls limp, their eyes dead and lifeless..."
|
||||
message_alien = "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, green blood bubbling from its maw..."
|
||||
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_simple = "stops moving..."
|
||||
|
||||
mob_type_blacklist_typecache = list(
|
||||
/mob/living/carbon/brain,
|
||||
/mob/living/captive_brain
|
||||
)
|
||||
|
||||
/datum/emote/living/deathgasp/get_sound(mob/living/user)
|
||||
. = ..()
|
||||
|
||||
if(isanimal(user))
|
||||
var/mob/living/simple_animal/S = user
|
||||
if(S.deathmessage)
|
||||
message_simple = S.deathmessage
|
||||
return S.death_sound
|
||||
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.dna.species)
|
||||
message = H.dna.species.death_message
|
||||
return pick(H.dna.species.death_sounds)
|
||||
|
||||
if(isalien(user))
|
||||
var/mob/living/carbon/alien/A = user
|
||||
message_alien = A.death_message
|
||||
return A.death_sound
|
||||
|
||||
if(issilicon(user))
|
||||
var/mob/living/silicon/SI = user
|
||||
return SI.death_sound
|
||||
|
||||
/datum/emote/living/drool
|
||||
key = "drool"
|
||||
key_third_person = "drools"
|
||||
message = "drools."
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/quiver
|
||||
key = "quiver"
|
||||
key_third_person = "quivers"
|
||||
message = "quivers."
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/frown
|
||||
key = "frown"
|
||||
key_third_person = "frowns"
|
||||
message = "frowns."
|
||||
message_param = "frowns at %t."
|
||||
|
||||
/datum/emote/living/gag
|
||||
key = "gag"
|
||||
key_third_person = "gags"
|
||||
message = "gags."
|
||||
message_mime = "appears to gag."
|
||||
message_param = "gags at %t."
|
||||
emote_type = 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/grimace
|
||||
key = "grimace"
|
||||
key_third_person = "grimaces"
|
||||
message = "grimaces."
|
||||
|
||||
/datum/emote/living/look
|
||||
key = "look"
|
||||
key_third_person = "looks"
|
||||
message = "looks."
|
||||
message_param = "looks at %t."
|
||||
|
||||
/datum/emote/living/bshake
|
||||
key = "bshake"
|
||||
key_third_person = "bshakes"
|
||||
message = "shakes."
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/shudder
|
||||
key = "shudder"
|
||||
key_third_person = "shudders"
|
||||
message = "shudders."
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/point
|
||||
key = "point"
|
||||
key_third_person = "points"
|
||||
message = "points."
|
||||
message_param = "points at %t."
|
||||
hands_use_check = TRUE
|
||||
target_behavior = EMOTE_TARGET_BHVR_USE_PARAMS_ANYWAY
|
||||
emote_target_type = EMOTE_TARGET_ANY
|
||||
|
||||
/datum/emote/living/point/act_on_target(mob/user, target)
|
||||
if(!target)
|
||||
return
|
||||
|
||||
user.pointed(target)
|
||||
|
||||
/datum/emote/living/point/run_emote(mob/user, params, type_override, intentional)
|
||||
// again, /tg/ has some flavor when pointing (like if you only have one leg) that applies debuffs
|
||||
// but it's so common that seems unnecessary for here
|
||||
message_param = initial(message_param) // reset
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!H.has_left_hand() && !H.has_right_hand())
|
||||
if(H.get_num_legs() != 0)
|
||||
message_param = "tries to point at %t with a leg."
|
||||
else
|
||||
// nugget
|
||||
message_param = "<span class='userdanger>bumps [user.p_their()] head on the ground</span> trying to motion towards %t."
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/emote/living/pout
|
||||
key = "pout"
|
||||
key_third_person = "pouts"
|
||||
message = "pouts."
|
||||
|
||||
/datum/emote/living/scream
|
||||
key = "scream"
|
||||
key_third_person = "screams"
|
||||
message = "screams!"
|
||||
message_mime = "acts out a scream!"
|
||||
message_simple = "whimpers."
|
||||
message_alien = "roars!"
|
||||
emote_type = EMOTE_SOUND | EMOTE_MOUTH
|
||||
mob_type_blacklist_typecache = list(
|
||||
// Humans and silicons get specialized scream.
|
||||
/mob/living/carbon/human,
|
||||
/mob/living/silicon
|
||||
)
|
||||
volume = 80
|
||||
|
||||
/datum/emote/living/scream/get_sound(mob/living/user)
|
||||
. = ..()
|
||||
if(isalien(user))
|
||||
return "sound/voice/hiss5.ogg"
|
||||
|
||||
/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."
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/sigh
|
||||
key = "sigh"
|
||||
key_third_person = "sighs"
|
||||
message = "sighs."
|
||||
message_mime = "appears to sigh."
|
||||
muzzled_noises = list("weak")
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
|
||||
/datum/emote/living/sigh/happy
|
||||
key = "hsigh"
|
||||
key_third_person = "hsighs"
|
||||
message = "sighs contentedly."
|
||||
message_mime = "appears to sigh contentedly"
|
||||
muzzled_noises = list("chill", "relaxed")
|
||||
|
||||
/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."
|
||||
message_param = "smiles at %t."
|
||||
|
||||
/datum/emote/living/smug
|
||||
key = "smug"
|
||||
key_third_person = "smugs"
|
||||
message = "grins smugly."
|
||||
message_param = "grins smugly at %t."
|
||||
|
||||
/datum/emote/living/sniff
|
||||
key = "sniff"
|
||||
key_third_person = "sniffs"
|
||||
message = "sniffs."
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/snore
|
||||
key = "snore"
|
||||
key_third_person = "snores"
|
||||
message = "snores."
|
||||
message_mime = "sleeps soundly."
|
||||
message_simple = "stirs in their sleep."
|
||||
message_robot = "dreams of electric sheep..."
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
// lock it so these emotes can only be used while unconscious
|
||||
stat_allowed = UNCONSCIOUS
|
||||
max_stat_allowed = UNCONSCIOUS
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
max_unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/nightmare
|
||||
key = "nightmare"
|
||||
message = "writhes in their sleep."
|
||||
emote_type = EMOTE_VISIBLE
|
||||
stat_allowed = UNCONSCIOUS
|
||||
max_stat_allowed = UNCONSCIOUS
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
max_unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/nightmare/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
user.dir = pick(GLOB.cardinal)
|
||||
|
||||
/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."
|
||||
message_robot = "tests their actuators."
|
||||
|
||||
/datum/emote/living/sulk
|
||||
key = "sulk"
|
||||
key_third_person = "sulks"
|
||||
message = "sulks down sadly."
|
||||
|
||||
/datum/emote/living/sway
|
||||
key = "sway"
|
||||
key_third_person = "sways"
|
||||
message = "sways around dizzily."
|
||||
|
||||
/datum/emote/living/swear
|
||||
key = "swear"
|
||||
key_third_person = "swears"
|
||||
message = "says a swear word!"
|
||||
message_param = "says a swear word at %t!"
|
||||
message_mime = "makes a rude gesture!"
|
||||
message_simple = "makes an angry noise!"
|
||||
message_robot = "makes a particularly offensive series of beeps!"
|
||||
message_postfix = "at %t!"
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
|
||||
mob_type_blacklist_typecache = list(
|
||||
/mob/living/carbon/brain,
|
||||
/mob/living/captive_brain
|
||||
)
|
||||
|
||||
/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!"
|
||||
|
||||
/datum/emote/living/twitch
|
||||
key = "twitch"
|
||||
key_third_person = "twitches"
|
||||
message = "twitches violently."
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/twitch_s
|
||||
key = "twitch_s"
|
||||
message = "twitches."
|
||||
unintentional_stat_allowed = UNCONSCIOUS
|
||||
|
||||
/datum/emote/living/whimper
|
||||
key = "whimper"
|
||||
key_third_person = "whimpers"
|
||||
message = "whimpers."
|
||||
message_mime = "appears hurt."
|
||||
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
|
||||
muzzled_noises = list("weak", "pathetic")
|
||||
|
||||
/datum/emote/living/wsmile
|
||||
key = "wsmile"
|
||||
key_third_person = "wsmiles"
|
||||
message = "smiles weakly."
|
||||
|
||||
/datum/emote/living/custom
|
||||
key = "me"
|
||||
key_third_person = "custom"
|
||||
message = null
|
||||
mob_type_blacklist_typecache = list(
|
||||
/mob/living/carbon/brain, // nice try
|
||||
/mob/living/captive_brain
|
||||
)
|
||||
|
||||
// Custom emotes should be able to be forced out regardless of context.
|
||||
// It falls on the caller to determine whether or not it should actually be called.
|
||||
unintentional_stat_allowed = DEAD
|
||||
|
||||
/datum/emote/living/custom/proc/check_invalid(mob/user, input)
|
||||
var/static/regex/stop_bad_mime = regex(@"says|exclaims|yells|asks")
|
||||
if(stop_bad_mime.Find(input, 1, 1))
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/emote/living/custom/run_emote(mob/user, params, type_override = null, intentional = FALSE)
|
||||
var/custom_emote
|
||||
var/custom_emote_type
|
||||
|
||||
if(QDELETED(user))
|
||||
return FALSE
|
||||
else if(check_mute(user?.client?.ckey, MUTE_IC))
|
||||
to_chat(user, "<span class='boldwarning'>You cannot send IC messages (muted).</span>")
|
||||
return FALSE
|
||||
else if(!params)
|
||||
custom_emote = copytext(sanitize(input("Choose an emote to display.") as text|null), 1, MAX_MESSAGE_LEN)
|
||||
if(custom_emote && !check_invalid(user, custom_emote))
|
||||
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
|
||||
switch(type)
|
||||
if("Visible")
|
||||
custom_emote_type = EMOTE_VISIBLE
|
||||
if("Hearable")
|
||||
custom_emote_type = EMOTE_AUDIBLE
|
||||
else
|
||||
to_chat(user,"<span class='warning'>Unable to use this emote, must be either hearable or visible.</span>")
|
||||
return
|
||||
else
|
||||
custom_emote = params
|
||||
if(type_override)
|
||||
custom_emote_type = type_override
|
||||
|
||||
message = custom_emote
|
||||
emote_type = custom_emote_type
|
||||
. = ..()
|
||||
message = initial(message)
|
||||
emote_type = initial(emote_type)
|
||||
|
||||
/datum/emote/living/custom/replace_pronoun(mob/user, message)
|
||||
// Trust the user said what they mean
|
||||
return message
|
||||
|
||||
@@ -125,7 +125,7 @@ GLOBAL_LIST_EMPTY(channel_to_radio_key)
|
||||
var/message_mode = parse_message_mode(message, "headset")
|
||||
|
||||
if(copytext(message, 1, 2) == "*")
|
||||
return emote(copytext(message, 2))
|
||||
return emote(copytext(message, 2), intentional = TRUE)
|
||||
|
||||
//parse the radio code and consume it
|
||||
if(message_mode)
|
||||
@@ -295,44 +295,6 @@ GLOBAL_LIST_EMPTY(channel_to_radio_key)
|
||||
/mob/living/proc/GetVoice()
|
||||
return name
|
||||
|
||||
/mob/living/emote(act, type, message, force) //emote code is terrible, this is so that anything that isn't already snowflaked to shit can call the parent and handle emoting sanely
|
||||
if(client)
|
||||
if(check_mute(client.ckey, MUTE_IC))
|
||||
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
|
||||
return
|
||||
|
||||
if(stat)
|
||||
return 0
|
||||
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(act && type && message) //parent call
|
||||
log_emote(message, src)
|
||||
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
if(!M.client)
|
||||
continue //skip monkeys and leavers
|
||||
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(isobserver(M) && M.get_preference(PREFTOGGLE_CHAT_GHOSTSIGHT) && !(M in viewers(src, null)) && client) // The client check makes sure people with ghost sight don't get spammed by simple mobs emoting.
|
||||
M.show_message(message)
|
||||
|
||||
switch(type)
|
||||
if(1) //Visible
|
||||
visible_message(message)
|
||||
return 1
|
||||
if(2) //Audible
|
||||
audible_message(message)
|
||||
return 1
|
||||
|
||||
else //everything else failed, emote is probably invalid
|
||||
if(act == "help")
|
||||
return //except help, because help is handled individually
|
||||
to_chat(src, "<span class='notice'>Unusable emote '[act]'. Say *help for a list.</span>")
|
||||
|
||||
/mob/living/whisper(message as text)
|
||||
message = trim_strip_html_properly(message)
|
||||
|
||||
|
||||
@@ -45,6 +45,6 @@
|
||||
|
||||
/mob/living/silicon/death(gibbed)
|
||||
. = ..()
|
||||
if(!gibbed)
|
||||
if(. && !gibbed)
|
||||
if(death_sound)
|
||||
playsound(get_turf(src), death_sound, 200, 1)
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/mob/living/silicon/emote(act, m_type=1, message = null, force)
|
||||
var/param = null
|
||||
if(findtext(act, "-", 1, null))
|
||||
var/t1 = findtext(act, "-", 1, null)
|
||||
param = copytext(act, t1 + 1, length(act) + 1)
|
||||
act = copytext(act, 1, t1)
|
||||
|
||||
//Emote Cooldown System (it's so simple!)
|
||||
//handle_emote_CD() located in [code\modules\mob\emote.dm]
|
||||
var/on_CD = 0
|
||||
act = lowertext(act)
|
||||
switch(act)
|
||||
//Cooldown-inducing emotes
|
||||
if("scream", "screams")
|
||||
on_CD = handle_emote_CD(50) //longer cooldown
|
||||
if("ping","pings","buzz","buzzs","buzzes","beep","beeps","yes","no", "buzz2")
|
||||
//halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT.
|
||||
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
|
||||
//Everything else, including typos of the above emotes
|
||||
else
|
||||
on_CD = 0 //If it doesn't induce the cooldown, we won't check for the cooldown
|
||||
|
||||
if(!force && on_CD == 1) // Check if we need to suppress the emote attempt.
|
||||
return // Suppress emote, you're still cooling off.
|
||||
//--FalseIncarnate
|
||||
|
||||
switch(act)
|
||||
if("ping","pings")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> pings[M ? " at [M]" : ""]."
|
||||
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("buzz","buzzs","buzzes")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> buzzes[M ? " at [M]" : ""]."
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("beep","beeps")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> beeps[M ? " at [M]" : ""]."
|
||||
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("yes")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> emits an affirmative blip[M ? " at [M]" : ""]."
|
||||
playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("no")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> emits a negative blip[M ? " at [M]" : ""]."
|
||||
playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("scream", "screams")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> screams[M ? " at [M]" : ""]!"
|
||||
playsound(src.loc, 'sound/goonstation/voice/robot_scream.ogg', 80, 0)
|
||||
m_type = 2
|
||||
|
||||
if("buzz2")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> emits an irritated buzzing sound[M ? " at [M]" : ""]."
|
||||
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
|
||||
if("help")
|
||||
to_chat(src, "yes, no, beep, ping, buzz, scream, buzz2")
|
||||
|
||||
..()
|
||||
@@ -49,9 +49,6 @@
|
||||
|
||||
/mob/living/silicon/robot/death(gibbed)
|
||||
if(can_die())
|
||||
if(!gibbed && deathgasp_on_death)
|
||||
emote("deathgasp", force = TRUE)
|
||||
|
||||
if(module)
|
||||
module.handle_death(src, gibbed)
|
||||
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/mob/living/silicon/robot/drone/say(message)
|
||||
if(copytext(message, 1, 2) == "*")
|
||||
return emote(copytext(message, 2))
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/robot/drone/whisper_say(list/message_pieces)
|
||||
say(multilingual_to_message(message_pieces)) //drones do not get to whisper, only speak normally
|
||||
return 1
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
/mob/living/silicon/robot/emote(act, m_type=1, message = null, force)
|
||||
var/param = null
|
||||
if(findtext(act, "-", 1, null))
|
||||
var/t1 = findtext(act, "-", 1, null)
|
||||
param = copytext(act, t1 + 1, length(act) + 1)
|
||||
act = copytext(act, 1, t1)
|
||||
|
||||
//Emote Cooldown System (it's so simple!)
|
||||
//handle_emote_CD() located in [code\modules\mob\emote.dm]
|
||||
var/on_CD = 0
|
||||
act = lowertext(act)
|
||||
switch(act)
|
||||
//Cooldown-inducing emotes
|
||||
if("law","flip","flips","halt") //halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT.
|
||||
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
|
||||
if("spin","spins")
|
||||
on_CD = handle_emote_CD(5 SECONDS)
|
||||
//Everything else, including typos of the above emotes
|
||||
else
|
||||
on_CD = 0 //If it doesn't induce the cooldown, we won't check for the cooldown
|
||||
|
||||
if(!force && on_CD == 1) // Check if we need to suppress the emote attempt.
|
||||
return // Suppress emote, you're still cooling off.
|
||||
//--FalseIncarnate
|
||||
|
||||
switch(act)
|
||||
|
||||
if("salute","salutes")
|
||||
if(!src.buckled)
|
||||
var/M = null
|
||||
if(param)
|
||||
for(var/mob/A in view(null, null))
|
||||
if(param == A.name)
|
||||
M = A
|
||||
break
|
||||
if(!M)
|
||||
param = null
|
||||
|
||||
if(param)
|
||||
message = "<B>[src]</B> salutes to [param]."
|
||||
else
|
||||
message = "<B>[src]</b> salutes."
|
||||
m_type = 1
|
||||
if("bow","bows")
|
||||
if(!src.buckled)
|
||||
var/M = null
|
||||
if(param)
|
||||
for(var/mob/A in view(null, null))
|
||||
if(param == A.name)
|
||||
M = A
|
||||
break
|
||||
if(!M)
|
||||
param = null
|
||||
|
||||
if(param)
|
||||
message = "<B>[src]</B> bows to [param]."
|
||||
else
|
||||
message = "<B>[src]</B> bows."
|
||||
m_type = 1
|
||||
|
||||
if("clap","claps")
|
||||
if(!src.restrained())
|
||||
message = "<B>[src]</B> claps."
|
||||
m_type = 2
|
||||
if("flap","flaps")
|
||||
if(!src.restrained())
|
||||
message = "<B>[src]</B> flaps its wings."
|
||||
m_type = 2
|
||||
|
||||
if("aflap","aflaps")
|
||||
if(!src.restrained())
|
||||
message = "<B>[src]</B> flaps its wings ANGRILY!"
|
||||
m_type = 2
|
||||
|
||||
if("twitch")
|
||||
message = "<B>[src]</B> twitches violently."
|
||||
m_type = 1
|
||||
|
||||
if("twitch_s","twitches")
|
||||
message = "<B>[src]</B> twitches."
|
||||
m_type = 1
|
||||
|
||||
if("nod","nods")
|
||||
message = "<B>[src]</B> nods."
|
||||
m_type = 1
|
||||
|
||||
if("deathgasp")
|
||||
message = "<B>[src]</B> shudders violently for a moment, then becomes motionless, its eyes slowly darkening."
|
||||
m_type = 1
|
||||
|
||||
if("glare","glares")
|
||||
var/M = null
|
||||
if(param)
|
||||
for(var/mob/A in view(null, null))
|
||||
if(param == A.name)
|
||||
M = A
|
||||
break
|
||||
if(!M)
|
||||
param = null
|
||||
|
||||
if(param)
|
||||
message = "<B>[src]</B> glares at [param]."
|
||||
else
|
||||
message = "<B>[src]</B> glares."
|
||||
|
||||
if("stare","stares")
|
||||
var/M = null
|
||||
if(param)
|
||||
for(var/mob/A in view(null, null))
|
||||
if(param == A.name)
|
||||
M = A
|
||||
break
|
||||
if(!M)
|
||||
param = null
|
||||
|
||||
if(param)
|
||||
message = "<B>[src]</B> stares at [param]."
|
||||
else
|
||||
message = "<B>[src]</B> stares."
|
||||
|
||||
if("look","looks")
|
||||
var/M = null
|
||||
if(param)
|
||||
for(var/mob/A in view(null, null))
|
||||
if(param == A.name)
|
||||
M = A
|
||||
break
|
||||
|
||||
if(!M)
|
||||
param = null
|
||||
|
||||
if(param)
|
||||
message = "<B>[src]</B> looks at [param]."
|
||||
else
|
||||
message = "<B>[src]</B> looks."
|
||||
m_type = 1
|
||||
|
||||
|
||||
if("law")
|
||||
if(istype(module,/obj/item/robot_module/security))
|
||||
message = "<B>[src]</B> shows its legal authorization barcode."
|
||||
|
||||
playsound(src.loc, 'sound/voice/biamthelaw.ogg', 50, 0)
|
||||
m_type = 2
|
||||
else
|
||||
to_chat(src, "You are not THE LAW, pal.")
|
||||
|
||||
if("halt")
|
||||
if(istype(module,/obj/item/robot_module/security))
|
||||
message = "<B>[src]</B>'s speakers skreech, \"Halt! Security!\"."
|
||||
|
||||
playsound(src.loc, 'sound/voice/halt.ogg', 50, 0)
|
||||
m_type = 2
|
||||
else
|
||||
to_chat(src, "You are not security.")
|
||||
|
||||
if("flip","flips")
|
||||
m_type = 1
|
||||
message = "<B>[src]</B> does a flip!"
|
||||
src.SpinAnimation(5,1)
|
||||
|
||||
if("spin","spins")
|
||||
spin(20, 1)
|
||||
message = "<B>[src]</B> spins!"
|
||||
|
||||
if("help")
|
||||
to_chat(src, "salute, bow-(none)/mob, clap, flap, aflap, twitch, twitches, nod, deathgasp, glare-(none)/mob, stare-(none)/mob, look,\n law, halt, flip, spin")
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/silicon/robot/verb/powerwarn()
|
||||
set category = "Robot Commands"
|
||||
set name = "Power Warning"
|
||||
|
||||
if(handle_emote_CD(50))
|
||||
return
|
||||
|
||||
if(!is_component_functioning("power cell") || !cell || !cell.charge)
|
||||
visible_message("The power warning light on <span class='name'>[src]</span> flashes urgently.",\
|
||||
"You announce you are operating in low power mode.")
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You can only use this emote when you're out of charge.</span>")
|
||||
@@ -1528,3 +1528,19 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
|
||||
/mob/living/silicon/robot/can_see_reagents()
|
||||
return see_reagents
|
||||
|
||||
/mob/living/silicon/robot/verb/powerwarn()
|
||||
set category = "Robot Commands"
|
||||
set name = "Power Warning"
|
||||
|
||||
|
||||
|
||||
if(!is_component_functioning("power cell") || !cell || !cell.charge)
|
||||
if(!start_audio_emote_cooldown(10 SECONDS))
|
||||
to_chat(src, "<span class='warning'>The low-power capacitor for your speaker system is still recharging, please try again later.</span>")
|
||||
return
|
||||
visible_message("<span class='warning'>The power warning light on <span class='name'>[src]</span> flashes urgently.</span>",\
|
||||
"<span class='warning'>You announce you are operating in low power mode.</span>")
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You can only use this emote when you're out of charge.</span>")
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
to_chat(src, "<i><span class='game say'>Holopad action relayed, <span class='name'>[real_name]</span> <span class='message'>[message]</span></span></i>")
|
||||
|
||||
for(var/mob/M in viewers(T.loc))
|
||||
M.show_message(rendered, 2)
|
||||
M.show_message(rendered, EMOTE_VISIBLE)
|
||||
|
||||
log_emote("(HPAD) [message]", src)
|
||||
else //This shouldn't occur, but better safe then sorry.
|
||||
@@ -107,10 +107,10 @@
|
||||
return
|
||||
return 1
|
||||
|
||||
/mob/living/silicon/ai/emote(act, type, message, force)
|
||||
/mob/living/silicon/ai/emote(act, type, message, intentional = TRUE, force_silence = FALSE)
|
||||
var/obj/machinery/hologram/holopad/T = current
|
||||
if(istype(T) && T.masters[src])//Is the AI using a holopad?
|
||||
src.holopad_emote(message)
|
||||
holopad_emote(message)
|
||||
else //Emote normally, then.
|
||||
..()
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/datum/emote/living/silicon
|
||||
// Humans are allowed for the sake of IPCs
|
||||
mob_type_allowed_typecache = list(/mob/living/silicon, /mob/living/simple_animal/bot, /mob/living/carbon/human)
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
/datum/emote/living/silicon/can_run_emote(mob/user, status_check, intentional)
|
||||
. = ..()
|
||||
// Let IPCs (and people with robo-heads) make beep-boop noises
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/organ/external/head/head = H.get_organ(BODY_ZONE_HEAD)
|
||||
if(head && !head.is_robotic())
|
||||
return FALSE
|
||||
|
||||
/datum/emote/living/silicon/scream
|
||||
key = "scream"
|
||||
key_third_person = "screams"
|
||||
message = "screams!"
|
||||
message_param = "screams at %t!"
|
||||
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
|
||||
vary = TRUE
|
||||
sound = "sound/goonstation/voice/robot_scream.ogg"
|
||||
volume = 80
|
||||
|
||||
/datum/emote/living/silicon/ping
|
||||
key = "ping"
|
||||
key_third_person = "pings"
|
||||
message = "pings."
|
||||
message_param = "pings at %t."
|
||||
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
|
||||
sound = "sound/machines/ping.ogg"
|
||||
|
||||
/datum/emote/living/silicon/buzz
|
||||
key = "buzz"
|
||||
key_third_person = "buzzes"
|
||||
message = "buzzes."
|
||||
message_param = "buzzes at %t."
|
||||
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
|
||||
sound = "sound/machines/buzz-sigh.ogg"
|
||||
|
||||
/datum/emote/living/silicon/buzz2
|
||||
key = "buzz2"
|
||||
message = "emits an irritated buzzing sound."
|
||||
message_param = "emits an irritated buzzing sound at %t."
|
||||
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
|
||||
sound = "sound/machines/buzz-two.ogg"
|
||||
|
||||
/datum/emote/living/silicon/beep
|
||||
key = "beep"
|
||||
key_third_person = "beeps"
|
||||
message = "beeps."
|
||||
message_param = "beeps at %t."
|
||||
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
|
||||
sound = "sound/machines/twobeep.ogg"
|
||||
|
||||
/datum/emote/living/silicon/yes
|
||||
key = "yes"
|
||||
message = "emits an affirmative blip."
|
||||
message_param = "emits an affirmative blip at %t."
|
||||
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
|
||||
sound = "sound/machines/synth_yes.ogg"
|
||||
|
||||
/datum/emote/living/silicon/no
|
||||
key = "no"
|
||||
message = "emits a negative blip."
|
||||
message_param = "emits a negative blip at %t."
|
||||
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
|
||||
sound = "sound/machines/synth_no.ogg"
|
||||
|
||||
/datum/emote/living/silicon/law
|
||||
key = "law"
|
||||
message = "shows its legal authorization barcode."
|
||||
message_param = "shows %t its legal authorization barcode."
|
||||
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
|
||||
sound = "sound/voice/biamthelaw.ogg"
|
||||
|
||||
/datum/emote/living/silicon/law/can_run_emote(mob/user, status_check, intentional)
|
||||
. = ..()
|
||||
var/mob/living/silicon/robot/bot = user
|
||||
if(!istype(bot) || !istype(bot.module, /obj/item/robot_module/security))
|
||||
return FALSE
|
||||
|
||||
/datum/emote/living/silicon/halt
|
||||
key = "halt"
|
||||
message = "screeches \"HALT! SECURITY!\" from its speakers."
|
||||
message_param = "instructs %t to HALT."
|
||||
emote_type = EMOTE_SOUND
|
||||
sound = "sound/voice/halt.ogg"
|
||||
|
||||
/datum/emote/living/silicon/halt/can_run_emote(mob/user, status_check, intentional)
|
||||
. = ..()
|
||||
var/mob/living/silicon/robot/bot = user
|
||||
if(!istype(bot) || !istype(bot.module, /obj/item/robot_module/security))
|
||||
return FALSE
|
||||
@@ -1,4 +1,5 @@
|
||||
//Defines for bots are now found in code\__DEFINES\bots.dm
|
||||
// Emotes for bots are shared with silicon, and are found at code/modules/mob/living/silicon/emotes.dm
|
||||
|
||||
// AI (i.e. game AI, not the AI player) controlled bots
|
||||
/mob/living/simple_animal/bot
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/mob/living/simple_animal/bot/emote(act, m_type = 1, message = null, force)
|
||||
var/param = null
|
||||
if(findtext(act, "-", 1, null))
|
||||
var/t1 = findtext(act, "-", 1, null)
|
||||
param = copytext(act, t1 + 1, length(act) + 1)
|
||||
act = copytext(act, 1, t1)
|
||||
|
||||
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
|
||||
act = copytext(act,1,length(act))
|
||||
|
||||
//Emote Cooldown System (it's so simple!)
|
||||
//handle_emote_CD() located in [code\modules\mob\emote.dm]
|
||||
var/on_CD = 0
|
||||
act = lowertext(act)
|
||||
switch(act)
|
||||
//Cooldown-inducing emotes
|
||||
if("scream", "screams")
|
||||
on_CD = handle_emote_CD(50) //longer cooldown
|
||||
if("ping","buzz","beep","yes","no") //halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT.
|
||||
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
|
||||
//Everything else, including typos of the above emotes
|
||||
else
|
||||
on_CD = 0 //If it doesn't induce the cooldown, we won't check for the cooldown
|
||||
|
||||
if(!force && on_CD == 1) // Check if we need to suppress the emote attempt.
|
||||
return // Suppress emote, you're still cooling off.
|
||||
//--FalseIncarnate
|
||||
|
||||
switch(act)
|
||||
if("ping")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> pings[M ? " at [M]" : ""]."
|
||||
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("buzz")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> buzzes[M ? " at [M]" : ""]."
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("beep")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> beeps[M ? " at [M]" : ""]."
|
||||
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("yes")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> emits an affirmative blip[M ? " at [M]" : ""]."
|
||||
playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("no")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> emits an negative blip[M ? " at [M]" : ""]."
|
||||
playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("scream", "screams")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> screams[M ? " at [M]" : ""]!"
|
||||
playsound(src.loc, 'sound/goonstation/voice/robot_scream.ogg', 80, 0)
|
||||
m_type = 2
|
||||
|
||||
if("help")
|
||||
to_chat(src, "scream(s), yes, no, beep, buzz, ping")
|
||||
..()
|
||||
@@ -11,7 +11,6 @@
|
||||
speak_emote = list("purrs", "meows")
|
||||
emote_hear = list("meows", "mews")
|
||||
emote_see = list("shakes its head", "shivers")
|
||||
var/meow_sound = 'sound/creatures/cat_meow.ogg' //Used in emote.
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
see_in_dark = 6
|
||||
@@ -104,26 +103,26 @@
|
||||
/mob/living/simple_animal/pet/cat/handle_automated_action()
|
||||
if(!stat && !buckled)
|
||||
if(prob(1))
|
||||
custom_emote(1, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
|
||||
custom_emote(EMOTE_VISIBLE, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
|
||||
StartResting()
|
||||
else if(prob(1))
|
||||
custom_emote(1, pick("sits down.", "crouches on its hind legs.", "looks alert."))
|
||||
custom_emote(EMOTE_VISIBLE, pick("sits down.", "crouches on its hind legs.", "looks alert."))
|
||||
icon_state = "[icon_living]_sit"
|
||||
collar_type = "[initial(collar_type)]_sit"
|
||||
resting = TRUE
|
||||
update_canmove()
|
||||
else if(prob(1))
|
||||
if(resting)
|
||||
custom_emote(1, pick("gets up and meows.", "walks around.", "stops resting."))
|
||||
custom_emote(EMOTE_VISIBLE, pick("gets up and meows.", "walks around.", "stops resting."))
|
||||
StopResting()
|
||||
else
|
||||
custom_emote(1, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
|
||||
custom_emote(EMOTE_VISIBLE, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
|
||||
|
||||
//MICE!
|
||||
if(eats_mice && isturf(loc) && !incapacitated())
|
||||
for(var/mob/living/simple_animal/mouse/M in view(1, src))
|
||||
if(!M.stat && Adjacent(M))
|
||||
custom_emote(1, "splats \the [M]!")
|
||||
custom_emote(EMOTE_VISIBLE, "splats \the [M]!")
|
||||
M.death()
|
||||
M.splat()
|
||||
movement_target = null
|
||||
@@ -131,7 +130,7 @@
|
||||
break
|
||||
for(var/obj/item/toy/cattoy/T in view(1, src))
|
||||
if(T.cooldown < (world.time - 400))
|
||||
custom_emote(1, "bats \the [T] around with its paw!")
|
||||
custom_emote(EMOTE_VISIBLE, "bats \the [T] around with its paw!")
|
||||
T.cooldown = world.time
|
||||
|
||||
/mob/living/simple_animal/pet/cat/handle_automated_movement()
|
||||
@@ -155,41 +154,6 @@
|
||||
stop_automated_movement = 1
|
||||
walk_to(src,movement_target,0,3)
|
||||
|
||||
/mob/living/simple_animal/pet/cat/emote(act, m_type = 1, message = null, force)
|
||||
if(stat != CONSCIOUS)
|
||||
return
|
||||
|
||||
var/on_CD = 0
|
||||
act = lowertext(act)
|
||||
switch(act)
|
||||
if("meow")
|
||||
on_CD = handle_emote_CD()
|
||||
if("hiss")
|
||||
on_CD = handle_emote_CD()
|
||||
if("purr")
|
||||
on_CD = handle_emote_CD()
|
||||
else
|
||||
on_CD = 0
|
||||
|
||||
if(!force && on_CD == 1)
|
||||
return
|
||||
|
||||
switch(act)
|
||||
if("meow")
|
||||
message = "<B>[src]</B> [pick(emote_hear)]!"
|
||||
m_type = 2 //audible
|
||||
playsound(src, meow_sound, 50, 0.75)
|
||||
if("hiss")
|
||||
message = "<B>[src]</B> hisses!"
|
||||
m_type = 2
|
||||
if("purr")
|
||||
message = "<B>[src]</B> purrs."
|
||||
m_type = 2
|
||||
if("help")
|
||||
to_chat(src, "scream, meow, hiss, purr")
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Proc
|
||||
name = "Proc"
|
||||
gender = MALE
|
||||
@@ -215,7 +179,6 @@
|
||||
icon_living = "Syndicat"
|
||||
icon_dead = "Syndicat_dead"
|
||||
icon_resting = "Syndicat_rest"
|
||||
meow_sound = null //Need robo-meow.
|
||||
gender = FEMALE
|
||||
faction = list("syndicate")
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
melee_damage_upper = 8
|
||||
attacktext = "bites"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
var/chirp_sound = 'sound/creatures/nymphchirp.ogg' //used in emote
|
||||
|
||||
speed = 0
|
||||
stop_automated_movement = 0
|
||||
@@ -277,31 +276,6 @@
|
||||
to_chat(src, "<span class='warning'>You don't have any hands!</span>")
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/diona/emote(act, m_type = 1, message = null, force)
|
||||
if(stat != CONSCIOUS)
|
||||
return
|
||||
|
||||
var/on_CD = 0
|
||||
act = lowertext(act)
|
||||
switch(act)
|
||||
if("chirp")
|
||||
on_CD = handle_emote_CD()
|
||||
else
|
||||
on_CD = 0
|
||||
|
||||
if(!force && on_CD == 1)
|
||||
return
|
||||
|
||||
switch(act) //IMPORTANT: Emotes MUST NOT CONFLICT anywhere along the chain.
|
||||
if("chirp")
|
||||
message = "<B>\The [src]</B> chirps!"
|
||||
m_type = 2 //audible
|
||||
playsound(src, chirp_sound, 40, 1, 1)
|
||||
if("help")
|
||||
to_chat(src, "scream, chirp")
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/diona/npc_safe(mob/user)
|
||||
if(!jobban_isbanned(user, ROLE_NYMPH))
|
||||
return TRUE
|
||||
|
||||
@@ -43,40 +43,6 @@
|
||||
return
|
||||
playsound(src, yelp_sound, 75, TRUE)
|
||||
|
||||
/mob/living/simple_animal/pet/dog/emote(act, m_type = 1, message = null, force)
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
var/on_CD = 0
|
||||
act = lowertext(act)
|
||||
switch(act)
|
||||
if("bark")
|
||||
on_CD = handle_emote_CD()
|
||||
if("yelp")
|
||||
on_CD = handle_emote_CD()
|
||||
else
|
||||
on_CD = 0
|
||||
|
||||
if(!force && on_CD == 1)
|
||||
return
|
||||
|
||||
switch(act)
|
||||
if("bark")
|
||||
message = "<B>[src]</B> [pick(src.speak_emote)]!"
|
||||
m_type = 2 //audible
|
||||
playsound(src, pick(src.bark_sound), 50, TRUE)
|
||||
if("yelp")
|
||||
message = "<B>[src]</B> yelps!"
|
||||
m_type = 2 //audible
|
||||
playsound(src, yelp_sound, 75, TRUE)
|
||||
if("growl")
|
||||
message = "<B>[src]</B> growls!"
|
||||
m_type = 2 //audible
|
||||
if("help")
|
||||
to_chat(src, "scream, bark, growl")
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/pet/dog/attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
switch(M.a_intent)
|
||||
@@ -90,10 +56,10 @@
|
||||
if(change > 0)
|
||||
if(M && stat != DEAD) // Added check to see if this mob (the corgi) is dead to fix issue 2454
|
||||
new /obj/effect/temp_visual/heart(loc)
|
||||
custom_emote(1, "yaps happily!")
|
||||
custom_emote(EMOTE_VISIBLE, "yaps happily!")
|
||||
else
|
||||
if(M && stat != DEAD) // Same check here, even though emote checks it as well (poor form to check it only in the help case)
|
||||
custom_emote(1, "growls!")
|
||||
emote("growl")
|
||||
|
||||
//Corgis and pugs are now under one dog subtype
|
||||
|
||||
@@ -564,7 +530,7 @@
|
||||
if(isturf(movement_target.loc))
|
||||
movement_target.attack_animal(src) // Eat the thing
|
||||
else if(prob(30) && ishuman(movement_target.loc)) // mean hooman has stolen it
|
||||
custom_emote(EMOTE_VISUAL, "stares at [movement_target.loc]'s [movement_target] with a sad puppy-face.")
|
||||
custom_emote(EMOTE_VISIBLE, "stares at [movement_target.loc]'s [movement_target] with a sad puppy-face.")
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/corgi
|
||||
name = "Corgi meat"
|
||||
@@ -669,7 +635,7 @@
|
||||
. = ..()
|
||||
if(!resting && !buckled)
|
||||
if(prob(1))
|
||||
custom_emote(1, pick("dances around.","chases her tail."))
|
||||
custom_emote(EMOTE_VISIBLE, pick("dances around.","chases her tail."))
|
||||
spin(20, 1)
|
||||
|
||||
/mob/living/simple_animal/pet/dog/corgi/exoticcorgi
|
||||
@@ -765,7 +731,7 @@
|
||||
. = ..()
|
||||
if(!resting && !buckled)
|
||||
if(prob(1))
|
||||
custom_emote(1, pick("chases its tail."))
|
||||
custom_emote(EMOTE_VISIBLE, pick("chases its tail."))
|
||||
spawn(0)
|
||||
for(var/i in list(1, 2, 4, 8, 4, 2, 1, 2, 4, 8, 4, 2, 1, 2, 4, 8, 4, 2))
|
||||
dir = i
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/datum/emote/living/simple_animal
|
||||
mob_type_allowed_typecache = list(/mob/living/simple_animal)
|
||||
|
||||
/datum/emote/living/simple_animal/diona_chirp
|
||||
key = "chirp"
|
||||
key_third_person = "chirps"
|
||||
message = "chirps!"
|
||||
sound = "sound/creatures/nymphchirp.ogg"
|
||||
emote_type = EMOTE_SOUND
|
||||
mob_type_allowed_typecache = list(/mob/living/simple_animal/diona)
|
||||
|
||||
// Dog emotes
|
||||
|
||||
/datum/emote/living/simple_animal/pet/dog
|
||||
mob_type_allowed_typecache = list(/mob/living/simple_animal/pet/dog)
|
||||
|
||||
/datum/emote/living/simple_animal/pet/dog/bark
|
||||
key = "bark"
|
||||
key_third_person = "barks"
|
||||
message = "barks."
|
||||
message_param = "barks at %t."
|
||||
emote_type = EMOTE_SOUND
|
||||
|
||||
/datum/emote/living/simple_animal/pet/dog/bark/get_sound(mob/living/user)
|
||||
. = ..()
|
||||
|
||||
var/mob/living/simple_animal/pet/dog/D = user
|
||||
message = pick(D.speak_emote)
|
||||
return pick(D.bark_sound)
|
||||
|
||||
/datum/emote/living/simple_animal/pet/dog/yelp
|
||||
key = "yelp"
|
||||
key_third_person = "yelps"
|
||||
message = "yelps!"
|
||||
message_param = "yelps at %t!"
|
||||
emote_type = EMOTE_SOUND
|
||||
|
||||
/datum/emote/living/simple_animal/pet/dog/yelp/get_sound(mob/living/user)
|
||||
var/mob/living/simple_animal/pet/dog/D = user
|
||||
return D.yelp_sound
|
||||
|
||||
/datum/emote/living/simple_animal/pet/dog/growl
|
||||
key = "growl"
|
||||
key_third_person = "growls"
|
||||
message = "growls!"
|
||||
message_param = "growls at %t!"
|
||||
emote_type = EMOTE_SOUND
|
||||
sound = "growl"
|
||||
|
||||
// Mouse
|
||||
|
||||
/datum/emote/living/simple_animal/mouse
|
||||
mob_type_allowed_typecache = list(/mob/living/simple_animal/mouse)
|
||||
|
||||
/datum/emote/living/simple_animal/mouse/squeak
|
||||
key = "squeak"
|
||||
key_third_person = "squeaks"
|
||||
message = "squeaks!"
|
||||
message_param = "squeaks at %t!"
|
||||
emote_type = EMOTE_SOUND
|
||||
|
||||
/datum/emote/living/simple_animal/mouse/squeak/get_sound(mob/living/user)
|
||||
var/mob/living/simple_animal/mouse/M = user
|
||||
return M.squeak_sound
|
||||
|
||||
// cat
|
||||
|
||||
/datum/emote/living/simple_animal/pet/cat
|
||||
mob_type_allowed_typecache = list(/mob/living/simple_animal/pet/cat)
|
||||
|
||||
/datum/emote/living/simple_animal/pet/cat/meow
|
||||
key = "meow"
|
||||
key_third_person = "meows"
|
||||
message = "meows."
|
||||
message_param = "meows at %t."
|
||||
sound = "sound/creatures/cat_meow.ogg"
|
||||
emote_type = EMOTE_SOUND
|
||||
|
||||
/datum/emote/living/simple_animal/pet/cat/meow/run_emote(mob/user, params, type_override, intentional)
|
||||
var/mob/living/simple_animal/pet/cat/C = user
|
||||
message = pick(C.emote_hear)
|
||||
. = ..()
|
||||
|
||||
/datum/emote/living/simple_animal/pet/cat/hiss
|
||||
key = "hiss"
|
||||
key_third_person = "hisses"
|
||||
message = "hisses!"
|
||||
message_param = "hisses at %t!"
|
||||
|
||||
/datum/emote/living/simple_animal/pet/cat/purr
|
||||
key = "purr"
|
||||
key_third_person = "purrs"
|
||||
message = "purrs."
|
||||
@@ -67,7 +67,7 @@
|
||||
if(prob(1))
|
||||
StopResting()
|
||||
else if(prob(5))
|
||||
custom_emote(2, "snuffles")
|
||||
custom_emote(EMOTE_AUDIBLE, "snuffles")
|
||||
else if(prob(0.5))
|
||||
StartResting()
|
||||
|
||||
@@ -119,31 +119,6 @@
|
||||
if(client)
|
||||
client.time_died_as_mouse = world.time
|
||||
|
||||
/mob/living/simple_animal/mouse/emote(act, m_type = 1, message = null, force)
|
||||
if(stat != CONSCIOUS)
|
||||
return
|
||||
|
||||
var/on_CD = 0
|
||||
act = lowertext(act)
|
||||
switch(act)
|
||||
if("squeak") //Mouse time
|
||||
on_CD = handle_emote_CD()
|
||||
else
|
||||
on_CD = 0
|
||||
|
||||
if(!force && on_CD == 1)
|
||||
return
|
||||
|
||||
switch(act)
|
||||
if("squeak")
|
||||
message = "<B>\The [src]</B> [pick(emote_hear)]!"
|
||||
m_type = 2 //audible
|
||||
playsound(src, squeak_sound, 40, 1)
|
||||
if("help")
|
||||
to_chat(src, "scream, squeak")
|
||||
|
||||
..()
|
||||
|
||||
/*
|
||||
* Mouse types
|
||||
*/
|
||||
|
||||
@@ -47,11 +47,11 @@
|
||||
return
|
||||
if(resting)
|
||||
if(!wants_to_rest())
|
||||
custom_emote(1, "growls, and gets up.")
|
||||
custom_emote(EMOTE_VISIBLE, "growls, and gets up.")
|
||||
playsound(get_turf(src), 'sound/hallucinations/growl2.ogg', 50, 1)
|
||||
StopResting()
|
||||
else if(wants_to_rest())
|
||||
custom_emote(1, "lays down, and starts to lick their wounds.")
|
||||
custom_emote(EMOTE_VISIBLE, "lays down, and starts to lick their wounds.")
|
||||
StartResting()
|
||||
|
||||
/mob/living/simple_animal/hostile/hellhound/examine(mob/user)
|
||||
|
||||
@@ -330,7 +330,7 @@
|
||||
/mob/living/simple_animal/hostile/proc/Aggro()
|
||||
vision_range = aggro_vision_range
|
||||
if(target && emote_taunt.len && prob(taunt_chance))
|
||||
emote("me", 1, "[pick(emote_taunt)] at [target].")
|
||||
custom_emote(EMOTE_VISIBLE, "[pick(emote_taunt)] at [target].")
|
||||
taunt_chance = max(taunt_chance-7,2)
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/LoseAggro()
|
||||
|
||||
@@ -394,7 +394,7 @@ Difficulty: Medium
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message()
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message)
|
||||
if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
/mob/living/simple_animal/parrot/death(gibbed)
|
||||
if(can_die())
|
||||
if(held_item)
|
||||
custom_emote(EMOTE_VISUAL, "lets go of [held_item]!")
|
||||
custom_emote(EMOTE_VISIBLE, "lets go of [held_item]!")
|
||||
drop_held_item()
|
||||
walk(src, 0)
|
||||
return ..()
|
||||
@@ -247,7 +247,7 @@
|
||||
parrot_state |= PARROT_ATTACK
|
||||
else
|
||||
if(held_item)
|
||||
custom_emote(EMOTE_VISUAL, "lets go of [held_item]!")
|
||||
custom_emote(EMOTE_VISIBLE, "lets go of [held_item]!")
|
||||
|
||||
parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell!
|
||||
drop_held_item(FALSE)
|
||||
@@ -347,7 +347,7 @@
|
||||
//Search for item to steal
|
||||
parrot_interest = search_for_perch_and_item()
|
||||
if(parrot_interest)
|
||||
custom_emote(EMOTE_VISUAL, "looks in [parrot_interest]'s direction and takes flight.")
|
||||
custom_emote(EMOTE_VISIBLE, "looks in [parrot_interest]'s direction and takes flight.")
|
||||
parrot_state = PARROT_SWOOP|PARROT_STEAL
|
||||
icon_state = "parrot_fly"
|
||||
return
|
||||
@@ -371,7 +371,7 @@
|
||||
parrot_interest = AM
|
||||
parrot_state = PARROT_SWOOP|PARROT_STEAL
|
||||
face_atom(AM)
|
||||
custom_emote(EMOTE_VISUAL, "turns and flies towards [parrot_interest].")
|
||||
custom_emote(EMOTE_VISIBLE, "turns and flies towards [parrot_interest].")
|
||||
return
|
||||
else //Else it's a perch
|
||||
parrot_perch = AM
|
||||
@@ -493,10 +493,10 @@
|
||||
var/obj/item/organ/external/affecting = H.get_organ(ran_zone(pick(parrot_dam_zone)))
|
||||
|
||||
H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, MELEE), sharp = TRUE)
|
||||
custom_emote(EMOTE_VISUAL, pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons."))
|
||||
custom_emote(EMOTE_VISIBLE, pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons."))
|
||||
else
|
||||
L.adjustBruteLoss(damage)
|
||||
custom_emote(EMOTE_VISUAL, pick("pecks at [L].", "claws [L]."))
|
||||
custom_emote(EMOTE_VISIBLE, pick("pecks at [L].", "claws [L]."))
|
||||
return
|
||||
//Otherwise, fly towards the mob!
|
||||
else
|
||||
|
||||
@@ -229,23 +229,23 @@
|
||||
else
|
||||
randomValue -= speak.len
|
||||
if(emote_see && randomValue <= emote_see.len)
|
||||
custom_emote(1, pick(emote_see))
|
||||
custom_emote(EMOTE_VISIBLE, pick(emote_see))
|
||||
else
|
||||
custom_emote(2, pick(emote_hear))
|
||||
custom_emote(EMOTE_AUDIBLE, pick(emote_hear))
|
||||
else
|
||||
say(pick(speak))
|
||||
else
|
||||
if(!(emote_hear && emote_hear.len) && (emote_see && emote_see.len))
|
||||
custom_emote(1, pick(emote_see))
|
||||
custom_emote(EMOTE_VISIBLE, pick(emote_see))
|
||||
if((emote_hear && emote_hear.len) && !(emote_see && emote_see.len))
|
||||
custom_emote(2, pick(emote_hear))
|
||||
custom_emote(EMOTE_AUDIBLE, pick(emote_hear))
|
||||
if((emote_hear && emote_hear.len) && (emote_see && emote_see.len))
|
||||
var/length = emote_hear.len + emote_see.len
|
||||
var/pick = rand(1,length)
|
||||
if(pick <= emote_see.len)
|
||||
custom_emote(1, pick(emote_see))
|
||||
custom_emote(EMOTE_VISIBLE, pick(emote_see))
|
||||
else
|
||||
custom_emote(2,pick(emote_hear))
|
||||
custom_emote(EMOTE_AUDIBLE, pick(emote_hear))
|
||||
|
||||
|
||||
/mob/living/simple_animal/handle_environment(datum/gas_mixture/environment)
|
||||
@@ -316,20 +316,6 @@
|
||||
pcollar.forceMove(drop_location())
|
||||
pcollar = null
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/emote(act, m_type = 1, message = null, force)
|
||||
if(stat)
|
||||
return
|
||||
act = lowertext(act)
|
||||
switch(act) //IMPORTANT: Emotes MUST NOT CONFLICT anywhere along the chain.
|
||||
if("scream")
|
||||
message = "<B>\The [src]</B> whimpers."
|
||||
m_type = 2
|
||||
if("help")
|
||||
to_chat(src, "scream")
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/say_quote(message)
|
||||
var/verb = "says"
|
||||
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
/mob/living/simple_animal/slime/emote(act, m_type = 1, message = null, force)
|
||||
if(stat)
|
||||
return
|
||||
|
||||
if(findtext(act, "-", 1, null))
|
||||
var/t1 = findtext(act, "-", 1, null)
|
||||
//param = copytext(act, t1 + 1, length(act) + 1)
|
||||
act = copytext(act, 1, t1)
|
||||
|
||||
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
|
||||
act = copytext(act,1,length(act))
|
||||
|
||||
act = lowertext(act)
|
||||
|
||||
var/regenerate_icons
|
||||
|
||||
switch(act) //Alphabetical please
|
||||
if("me")
|
||||
if(HAS_TRAIT(src, TRAIT_MUTE))
|
||||
return
|
||||
if(src.client)
|
||||
if(check_mute(client.ckey, MUTE_IC))
|
||||
to_chat(src, "<span class='warning'>You cannot send IC messages (muted).</span>")
|
||||
return
|
||||
if(src.client.handle_spam_prevention(message, MUTE_IC))
|
||||
return
|
||||
if(stat)
|
||||
return
|
||||
if(!(message))
|
||||
return
|
||||
return custom_emote(m_type, message)
|
||||
if("bounce")
|
||||
message = "<B>[src]</B> bounces in place."
|
||||
m_type = 1
|
||||
|
||||
if("custom")
|
||||
return custom_emote(m_type, message)
|
||||
|
||||
if("jiggle")
|
||||
message = "<B>[src]</B> jiggles!"
|
||||
m_type = 1
|
||||
|
||||
if("light")
|
||||
message = "<B>[src]</B> lights up for a bit, then stops."
|
||||
m_type = 1
|
||||
|
||||
if("moan")
|
||||
message = "<B>[src]</B> moans."
|
||||
m_type = 2
|
||||
|
||||
if("shiver")
|
||||
message = "<B>[src]</B> shivers."
|
||||
m_type = 2
|
||||
|
||||
if("sway")
|
||||
message = "<B>[src]</B> sways around dizzily."
|
||||
m_type = 1
|
||||
|
||||
if("twitch")
|
||||
message = "<B>[src]</B> twitches."
|
||||
m_type = 1
|
||||
|
||||
if("vibrate")
|
||||
message = "<B>[src]</B> vibrates!"
|
||||
m_type = 1
|
||||
|
||||
if("noface") //mfw I have no face
|
||||
mood = null
|
||||
regenerate_icons = 1
|
||||
|
||||
if("smile")
|
||||
mood = "mischevous"
|
||||
regenerate_icons = 1
|
||||
|
||||
if(":3")
|
||||
mood = ":33"
|
||||
regenerate_icons = 1
|
||||
|
||||
if("pout")
|
||||
mood = "pout"
|
||||
regenerate_icons = 1
|
||||
|
||||
if("frown")
|
||||
mood = "sad"
|
||||
regenerate_icons = 1
|
||||
|
||||
if("scowl")
|
||||
mood = "angry"
|
||||
regenerate_icons = 1
|
||||
|
||||
if("help") //This is an exception
|
||||
to_chat(src, "Help for slime emotes. You can use these emotes with say \"*emote\":\n\nbounce, custom, jiggle, light, moan, shiver, sway, twitch, vibrate. \n\nYou may also change your face with: \n\nsmile, :3, pout, frown, scowl, noface")
|
||||
|
||||
else
|
||||
to_chat(src, "<span class='notice'>Unusable emote '[act]'. Say *help for a list.</span>")
|
||||
if((message && stat == CONSCIOUS))
|
||||
if(client)
|
||||
log_emote("[name]/[key] : [message]", src)
|
||||
if(m_type & 1)
|
||||
visible_message(message)
|
||||
else
|
||||
loc.audible_message(message)
|
||||
|
||||
if(regenerate_icons)
|
||||
regenerate_icons()
|
||||
@@ -0,0 +1,66 @@
|
||||
/// Sentinel value; passing this as mood sets mood to null.
|
||||
#define MOOD_RESET "reset"
|
||||
|
||||
/datum/emote/living/simple_animal/slime
|
||||
mob_type_allowed_typecache = list(/mob/living/simple_animal/slime)
|
||||
/// Apply mood of the emote. Set this to MOOD_RESET to cause the emote to reset the mood back to default.
|
||||
var/mood
|
||||
|
||||
/datum/emote/living/simple_animal/slime/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
if(mood)
|
||||
var/mob/living/simple_animal/slime/S = user
|
||||
if(mood == MOOD_RESET)
|
||||
S.mood = null
|
||||
else
|
||||
S.mood = mood
|
||||
|
||||
/datum/emote/living/simple_animal/slime/bounce
|
||||
key = "bounce"
|
||||
key_third_person = "bounces"
|
||||
message = "bounces in place."
|
||||
|
||||
/datum/emote/living/simple_animal/slime/jiggle
|
||||
key = "jiggle"
|
||||
key_third_person = "jiggles"
|
||||
message = "jiggles!"
|
||||
|
||||
/datum/emote/living/simple_animal/slime/light
|
||||
key = "light"
|
||||
key_third_person = "lights"
|
||||
message = "lights up for a bit, then stops."
|
||||
|
||||
/datum/emote/living/simple_animal/slime/vibrate
|
||||
key = "vibrate"
|
||||
key_third_person = "vibrates"
|
||||
message = "vibrates!"
|
||||
|
||||
/datum/emote/living/simple_animal/slime/noface
|
||||
// mfw no face
|
||||
key = "noface"
|
||||
mood = MOOD_RESET
|
||||
|
||||
/datum/emote/living/simple_animal/slime/smile
|
||||
key = "smile"
|
||||
mood = "mischevous"
|
||||
|
||||
/datum/emote/living/simple_animal/slime/colon_three
|
||||
key = ":3"
|
||||
mood = ":33"
|
||||
|
||||
/datum/emote/living/simple_animal/slime/pout
|
||||
key = "pout"
|
||||
mood = "pout"
|
||||
|
||||
/datum/emote/living/simple_animal/slime/sad
|
||||
key = "frown"
|
||||
mood = "sad"
|
||||
|
||||
/datum/emote/living/simple_animal/slime/scowl
|
||||
key = "scowl"
|
||||
mood = "angry"
|
||||
|
||||
#undef MOOD_RESET
|
||||
+13
-13
@@ -70,26 +70,26 @@
|
||||
t+= "<span class='notice'>N2O: [environment.sleeping_agent] \n</span>"
|
||||
t+= "<span class='notice'>Agent B: [environment.agent_b] \n</span>"
|
||||
|
||||
usr.show_message(t, 1)
|
||||
usr.show_message(t, EMOTE_VISIBLE)
|
||||
|
||||
/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
|
||||
|
||||
if(!client) return
|
||||
|
||||
if(type)
|
||||
if(type & 1 && !has_vision(information_only=TRUE))//Vision related
|
||||
if(type & EMOTE_VISIBLE && !has_vision(information_only=TRUE))//Vision related
|
||||
if(!(alt))
|
||||
return
|
||||
else
|
||||
msg = alt
|
||||
type = alt_type
|
||||
if(type & EMOTE_AUDIBLE && !can_hear())//Hearing related
|
||||
if(!( alt ))
|
||||
return
|
||||
else
|
||||
msg = alt
|
||||
type = alt_type
|
||||
if(type & 2 && !can_hear())//Hearing related
|
||||
if(!( alt ))
|
||||
return
|
||||
else
|
||||
msg = alt
|
||||
type = alt_type
|
||||
if(type & 1 && !has_vision(information_only=TRUE))
|
||||
if(type & EMOTE_VISIBLE && !has_vision(information_only=TRUE))
|
||||
return
|
||||
// Added voice muffling for Issue 41.
|
||||
if(stat == UNCONSCIOUS)
|
||||
@@ -111,7 +111,7 @@
|
||||
var/msg = message
|
||||
if(self_message && M == src)
|
||||
msg = self_message
|
||||
M.show_message(msg, 1, blind_message, 2)
|
||||
M.show_message(msg, EMOTE_VISIBLE, blind_message, EMOTE_AUDIBLE)
|
||||
|
||||
// Show a message to all mobs in sight of this atom
|
||||
// Use for objects performing visible actions
|
||||
@@ -121,7 +121,7 @@
|
||||
for(var/mob/M in get_mobs_in_view(7, src))
|
||||
if(!M.client)
|
||||
continue
|
||||
M.show_message(message, 1, blind_message, 2)
|
||||
M.show_message(message, EMOTE_VISIBLE, blind_message, EMOTE_AUDIBLE)
|
||||
|
||||
// Show a message to all mobs in earshot of this one
|
||||
// This would be for audible actions by the src mob
|
||||
@@ -135,7 +135,7 @@
|
||||
range = hearing_distance
|
||||
var/msg = message
|
||||
for(var/mob/M in get_mobs_in_view(range, src))
|
||||
M.show_message(msg, 2, deaf_message, 1)
|
||||
M.show_message(msg, EMOTE_AUDIBLE, deaf_message, EMOTE_VISIBLE)
|
||||
|
||||
// based on say code
|
||||
var/omsg = replacetext(message, "<B>[src]</B> ", "")
|
||||
@@ -161,7 +161,7 @@
|
||||
if(hearing_distance)
|
||||
range = hearing_distance
|
||||
for(var/mob/M in get_mobs_in_view(range, src))
|
||||
M.show_message(message, 2, deaf_message, 1)
|
||||
M.show_message(message, EMOTE_AUDIBLE, deaf_message, EMOTE_VISIBLE)
|
||||
|
||||
/mob/proc/findname(msg)
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
var/list/languages = list() // For speaking/listening.
|
||||
var/list/abilities = list() // For species-derived or admin-given powers.
|
||||
var/list/speak_emote = list("says") // Verbs used when speaking. Defaults to 'say' if speak_emote is null.
|
||||
var/emote_type = 1 // Define emote default type, 1 for seen emotes, 2 for heard emotes
|
||||
var/emote_type = EMOTE_VISIBLE // Define emote default type, 1 for seen emotes, 2 for heard emotes
|
||||
var/name_archive //For admin things like possession
|
||||
|
||||
var/timeofdeath = 0 //Living
|
||||
@@ -98,7 +98,17 @@
|
||||
|
||||
var/in_throw_mode = 0
|
||||
|
||||
var/emote_cd = 0 // Used to supress emote spamming. 1 if on CD, 2 if disabled by admin (manually set), else 0
|
||||
// See /datum/emote
|
||||
|
||||
/// Cooldown on audio effects from emotes.
|
||||
var/audio_emote_cd_status = EMOTE_READY
|
||||
|
||||
/// Override for cooldowns on non-audio emotes. Should be a number in deciseconds.
|
||||
var/emote_cooldown_override = null
|
||||
|
||||
/// Tracks last uses of emotes for cooldown purposes
|
||||
var/list/emotes_used
|
||||
var/list/emotes_on_cooldown
|
||||
|
||||
var/job = null //Living
|
||||
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
|
||||
// The datum in use is defined in code/datums/emotes.dm
|
||||
|
||||
/**
|
||||
* Send an emote.
|
||||
*
|
||||
* * emote_key: Key of the emote being triggered
|
||||
* * m_type: Type of the emote, like EMOTE_AUDIBLE. If this is not null, the default type of the emote will be overridden.
|
||||
* * message: Custom parameter for the emote. This should be used if you want to pass something like a target programmatically.
|
||||
* * intentional: Whether or not the emote was deliberately triggered by the mob. If true, it's forced, which skips some checks when calling the emote.
|
||||
* * force_silence: If true, unusable/nonexistent emotes will not notify the user.
|
||||
*/
|
||||
/mob/proc/emote(emote_key, type_override = null, message = null, intentional = FALSE, force_silence = FALSE)
|
||||
emote_key = lowertext(emote_key)
|
||||
var/param = message
|
||||
var/custom_param_offset = findtext(emote_key, EMOTE_PARAM_SEPARATOR, 1, null)
|
||||
if(custom_param_offset)
|
||||
param = copytext(emote_key, custom_param_offset + length(emote_key[custom_param_offset]))
|
||||
emote_key = copytext(emote_key, 1, custom_param_offset)
|
||||
|
||||
var/list/key_emotes = GLOB.emote_list[emote_key]
|
||||
|
||||
if(!length(key_emotes))
|
||||
if(intentional && !force_silence)
|
||||
to_chat(src, "<span class='notice'>'[emote_key]' emote does not exist. Say *help for a list.</span>")
|
||||
else if(!intentional)
|
||||
CRASH("Emote with key [emote_key] was attempted to be called, though doesn't exist!")
|
||||
return FALSE
|
||||
var/silenced = FALSE
|
||||
for(var/datum/emote/P in key_emotes)
|
||||
if(!P.check_cooldown(src, intentional))
|
||||
// if an emote's on cooldown, don't spam them with messages of not being able to use it
|
||||
silenced = TRUE
|
||||
continue
|
||||
if(P.try_run_emote(src, param, type_override, intentional))
|
||||
return TRUE
|
||||
if(intentional && !silenced && !force_silence)
|
||||
to_chat(src, "<span class='notice'>Unusable emote '[emote_key]'. Say *help for a list.</span>")
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Perform a custom emote.
|
||||
*
|
||||
* * m_type: Type of message to send.
|
||||
* * message: Content of the message. If none is provided, the user will be prompted to choose the input.
|
||||
* * intentional: Whether or not the user intendeded to perform the emote.
|
||||
*/
|
||||
/mob/proc/custom_emote(m_type = EMOTE_VISIBLE, message = null, intentional = FALSE)
|
||||
var/input = ""
|
||||
if(!message && !client)
|
||||
CRASH("An empty custom emote was called from a client-less mob.")
|
||||
else if (!message)
|
||||
input = sanitize(copytext(input(src,"Choose an emote to display.") as text|null, 1, MAX_MESSAGE_LEN))
|
||||
else
|
||||
input = message
|
||||
|
||||
emote("me", m_type, input, intentional)
|
||||
|
||||
/**
|
||||
* Get a list of all emote keys usable by the current mob.
|
||||
*
|
||||
* * intentional_use: Whether or not to check based on if the action was intentional.
|
||||
*/
|
||||
/mob/proc/usable_emote_keys(intentional_use = TRUE)
|
||||
var/list/all_keys = list()
|
||||
for(var/key in GLOB.emote_list)
|
||||
for(var/datum/emote/P in GLOB.emote_list[key])
|
||||
if(P.key in all_keys)
|
||||
continue
|
||||
if(P.can_run_emote(src, status_check = FALSE, intentional = null))
|
||||
all_keys += P.key
|
||||
if(P.key_third_person)
|
||||
all_keys += P.key_third_person
|
||||
|
||||
return all_keys
|
||||
|
||||
/datum/emote/help
|
||||
key = "help"
|
||||
mob_type_ignore_stat_typecache = list(/mob/dead/observer, /mob/living/silicon/ai)
|
||||
|
||||
/datum/emote/help/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
var/list/base_keys = list()
|
||||
var/list/all_keys = list()
|
||||
var/list/species_emotes = list()
|
||||
var/list/message = list("Available emotes, you can use them with say \"*emote\": ")
|
||||
|
||||
var/mob/living/carbon/human/H = user
|
||||
for(var/key in GLOB.emote_list)
|
||||
for(var/datum/emote/P in GLOB.emote_list[key])
|
||||
var/full_key = P.key
|
||||
if(P.key in all_keys)
|
||||
continue
|
||||
if(P.can_run_emote(user, status_check = FALSE, intentional = TRUE))
|
||||
if(P.message_param && P.param_desc)
|
||||
// Add our parameter description, like flap-user
|
||||
full_key = P.key + "\[[EMOTE_PARAM_SEPARATOR][P.param_desc]\]"
|
||||
if(istype(H) && P.species_type_whitelist_typecache && H.dna && is_type_in_typecache(H.dna.species, P.species_type_whitelist_typecache))
|
||||
species_emotes += full_key
|
||||
else
|
||||
base_keys += full_key
|
||||
all_keys += P.key
|
||||
|
||||
base_keys = sortList(base_keys)
|
||||
message += base_keys.Join(", ")
|
||||
message += "."
|
||||
message = message.Join("")
|
||||
if(length(species_emotes) > 0)
|
||||
species_emotes = sortList(species_emotes)
|
||||
message += "\n<u>[user?.dna?.species.name] specific emotes</u> :- "
|
||||
message += species_emotes.Join(", ")
|
||||
message += "."
|
||||
to_chat(user, message)
|
||||
|
||||
/datum/emote/flip
|
||||
key = "flip"
|
||||
key_third_person = "flips"
|
||||
message = "does a flip!"
|
||||
hands_use_check = TRUE
|
||||
emote_type = EMOTE_VISIBLE | EMOTE_FORCE_NO_RUNECHAT // don't need an emote to see that
|
||||
mob_type_allowed_typecache = list(/mob/living, /mob/dead/observer) // okay but what if we allowed ghosts to flip as well
|
||||
mob_type_blacklist_typecache = list(/mob/living/carbon/brain, /mob/camera, /mob/living/silicon/ai)
|
||||
mob_type_ignore_stat_typecache = list(/mob/dead/observer)
|
||||
|
||||
/datum/emote/flip/run_emote(mob/user, params, type_override, intentional)
|
||||
|
||||
if(isobserver(user))
|
||||
user.SpinAnimation(5, 1)
|
||||
return TRUE
|
||||
|
||||
var/mob/living/L = user
|
||||
|
||||
if(user.lying || (istype(L) && L.IsWeakened()))
|
||||
message = "flops and flails around on the floor."
|
||||
return ..()
|
||||
else if(params)
|
||||
message_param = "flips in %t's general direction."
|
||||
else if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H.get_active_hand(), /obj/item/grab))
|
||||
var/obj/item/grab/G = H.get_active_hand()
|
||||
if(G && G.affecting)
|
||||
if(H.buckled || G.affecting.buckled)
|
||||
to_chat(user, "<span class='warning'>[G.affecting] is buckled, you can't flip around [G.affecting.p_them()]!</span>")
|
||||
return TRUE
|
||||
var/turf/oldloc = user.loc
|
||||
var/turf/newloc = G.affecting.loc
|
||||
if(isturf(oldloc) && isturf(newloc))
|
||||
user.SpinAnimation(5, 1)
|
||||
user.glide_for(0.6 SECONDS) // This and the glide_for below are purely arbitrary. Pick something that looks aesthetically pleasing.
|
||||
user.forceMove(newloc)
|
||||
G.glide_for(0.6 SECONDS)
|
||||
G.affecting.forceMove(oldloc)
|
||||
message = "flips over [G.affecting]!"
|
||||
return ..()
|
||||
|
||||
user.SpinAnimation(5, 1)
|
||||
|
||||
if(prob(5) && ishuman(user))
|
||||
message = "attempts a flip and crashes to the floor!"
|
||||
sleep(0.3 SECONDS)
|
||||
if(istype(L))
|
||||
L.Weaken(4 SECONDS)
|
||||
return ..()
|
||||
|
||||
. = ..()
|
||||
|
||||
/datum/emote/spin
|
||||
key = "spin"
|
||||
key_third_person = "spins"
|
||||
hands_use_check = TRUE
|
||||
emote_type = EMOTE_VISIBLE | EMOTE_FORCE_NO_RUNECHAT
|
||||
mob_type_allowed_typecache = list(/mob/living, /mob/dead/observer)
|
||||
mob_type_blacklist_typecache = list(/mob/living/carbon/brain, /mob/camera, /mob/living/silicon/ai)
|
||||
mob_type_ignore_stat_typecache = list(/mob/dead/observer)
|
||||
cooldown = 2 SECONDS // how long the spin takes, any faster and mobs can spin
|
||||
|
||||
/datum/emote/spin/run_emote(mob/user, params, type_override, intentional)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
if(prob(95) || isobserver(user) || !ishuman(user))
|
||||
user.spin(20, 1)
|
||||
return TRUE
|
||||
|
||||
user.spin(32, 1)
|
||||
to_chat(user, "<span class='warning'>You spin too much!</span>")
|
||||
var/mob/living/L = user
|
||||
if(istype(L))
|
||||
L.Dizzy(24 SECONDS)
|
||||
L.Confused(24 SECONDS)
|
||||
@@ -744,3 +744,48 @@ GLOBAL_LIST_INIT(intents, list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM
|
||||
message_admins("[src.ckey] just got booted back to lobby with no jobs enabled, but antag rolling enabled. Likely antag rolling abuse.")
|
||||
return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Helper proc to determine if a mob can use emotes that make sound or not.
|
||||
*/
|
||||
/mob/proc/can_use_audio_emote()
|
||||
switch(audio_emote_cd_status)
|
||||
if(EMOTE_INFINITE) // Spam those emotes
|
||||
return TRUE
|
||||
if(EMOTE_ADMIN_BLOCKED) // Cooldown emotes were disabled by an admin, prevent use
|
||||
return FALSE
|
||||
if(EMOTE_ON_COOLDOWN) // Already on CD, prevent use
|
||||
return FALSE
|
||||
if(EMOTE_READY)
|
||||
return TRUE
|
||||
|
||||
CRASH("Invalid emote type")
|
||||
|
||||
/**
|
||||
* # Start the cooldown for an emote that plays audio.
|
||||
*
|
||||
* * cooldown: The amount of time that should be waited before any other audio emote can fire.
|
||||
*/
|
||||
/mob/proc/start_audio_emote_cooldown(cooldown = AUDIO_EMOTE_COOLDOWN)
|
||||
if(!can_use_audio_emote())
|
||||
return FALSE
|
||||
|
||||
if(audio_emote_cd_status == EMOTE_READY)
|
||||
audio_emote_cd_status = EMOTE_ON_COOLDOWN // Starting cooldown
|
||||
addtimer(CALLBACK(src, .proc/on_audio_emote_cooldown_end), cooldown)
|
||||
return TRUE // proceed with emote
|
||||
|
||||
|
||||
/mob/proc/on_audio_emote_cooldown_end()
|
||||
if(audio_emote_cd_status == EMOTE_ON_COOLDOWN)
|
||||
// only reset emotes that probably weren't set by an admin
|
||||
audio_emote_cd_status = EMOTE_READY
|
||||
|
||||
/proc/stat_to_text(stat)
|
||||
switch(stat)
|
||||
if(CONSCIOUS)
|
||||
return "conscious"
|
||||
if(UNCONSCIOUS)
|
||||
return "unconscious"
|
||||
if(DEAD)
|
||||
return "dead"
|
||||
|
||||
+12
-8
@@ -2,6 +2,8 @@
|
||||
#define ILLEGAL_CHARACTERS_LIST list("<" = "", ">" = "", \
|
||||
"\[" = "", "]" = "", "{" = "", "}" = "")
|
||||
|
||||
#define USABLE_DEAD_EMOTES list("*flip", "*spin")
|
||||
|
||||
/mob/proc/say()
|
||||
return
|
||||
|
||||
@@ -39,9 +41,9 @@
|
||||
|
||||
set_typing_indicator(FALSE, TRUE)
|
||||
if(use_me)
|
||||
custom_emote(usr.emote_type, message)
|
||||
custom_emote(usr.emote_type, message, intentional = TRUE)
|
||||
else
|
||||
usr.emote(message)
|
||||
usr.emote(message, intentional = TRUE)
|
||||
|
||||
|
||||
/mob/proc/say_dead(message)
|
||||
@@ -62,6 +64,13 @@
|
||||
if(client.handle_spam_prevention(message, MUTE_DEADCHAT))
|
||||
return
|
||||
|
||||
|
||||
if(message in USABLE_DEAD_EMOTES)
|
||||
emote(copytext(message, 2), intentional = TRUE)
|
||||
log_emote(message, src)
|
||||
create_log(DEADCHAT_LOG, message)
|
||||
return
|
||||
|
||||
say_dead_direct("[pick("complains", "moans", "whines", "laments", "blubbers", "salts")], <span class='message'>\"[message]\"</span>", src)
|
||||
create_log(DEADCHAT_LOG, message)
|
||||
log_ghostsay(message, src)
|
||||
@@ -110,12 +119,6 @@
|
||||
verb = "asks"
|
||||
return verb
|
||||
|
||||
|
||||
/mob/proc/emote(act, type, message, force)
|
||||
if(act == "me")
|
||||
return custom_emote(type, message)
|
||||
|
||||
|
||||
/mob/proc/get_ear()
|
||||
// returns an atom representing a location on the map from which this
|
||||
// mob can hear things
|
||||
@@ -220,4 +223,5 @@
|
||||
. += S.message + " "
|
||||
. = trim_right(.)
|
||||
|
||||
#undef USABLE_DEAD_EMOTES
|
||||
#undef ILLEGAL_CHARACTERS_LIST
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
if(blood_volume)
|
||||
blood_volume = max(blood_volume - amt, 0)
|
||||
if(prob(10 * amt)) // +5% chance per internal bleeding site that we'll cough up blood on a given tick.
|
||||
custom_emote(1, "coughs up blood!")
|
||||
custom_emote(EMOTE_VISIBLE, "coughs up blood!")
|
||||
add_splatter_floor(loc, 1)
|
||||
return 1
|
||||
else if(amt >= 1 && prob(5 * amt)) // +2.5% chance per internal bleeding site that we'll cough up blood on a given tick. Must be bleeding internally in more than one place to have a chance at this.
|
||||
|
||||
@@ -77,10 +77,10 @@
|
||||
|
||||
if(is_bruised())
|
||||
if(prob(2) && !(NO_BLOOD in owner.dna.species.species_traits))
|
||||
owner.custom_emote(1, "coughs up blood!")
|
||||
owner.custom_emote(EMOTE_VISIBLE, "coughs up blood!")
|
||||
owner.bleed(1)
|
||||
if(prob(4))
|
||||
owner.custom_emote(1, "gasps for air!")
|
||||
owner.custom_emote(EMOTE_VISIBLE, "gasps for air!")
|
||||
owner.AdjustLoseBreath(10 SECONDS)
|
||||
|
||||
/obj/item/organ/internal/lungs/proc/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H)
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
I.receive_damage(brute * 0.5)
|
||||
brute -= brute * 0.5
|
||||
|
||||
if(status & ORGAN_BROKEN && prob(40) && brute)
|
||||
if(status & ORGAN_BROKEN && prob(40) && brute && !owner.stat)
|
||||
owner.emote("scream") //getting hit on broken hand hurts
|
||||
if(status & ORGAN_SPLINTED && prob((brute + burn)*4)) //taking damage to splinted limbs removes the splints
|
||||
status &= ~ORGAN_SPLINTED
|
||||
@@ -627,7 +627,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
)
|
||||
to_chat(owner, "<span class='userdanger'>Something feels like it shattered in your [name]!</span>")
|
||||
playsound(owner, "bonebreak", 150, 1)
|
||||
if(!HAS_TRAIT(owner, TRAIT_NOPAIN))
|
||||
if(!HAS_TRAIT(owner, TRAIT_NOPAIN) && !owner.stat)
|
||||
owner.emote("scream")
|
||||
|
||||
status |= ORGAN_BROKEN
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
if(hand && owner.canUnEquip(hand))
|
||||
owner.unEquip(hand)
|
||||
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, dropping what it was holding!</span>")
|
||||
owner.custom_emote(1, "drops what [owner.p_they()] [owner.p_were()] holding, [owner.p_their()] [name] malfunctioning!")
|
||||
owner.custom_emote(EMOTE_VISIBLE, "drops what [owner.p_they()] [owner.p_were()] holding, [owner.p_their()] [name] malfunctioning!")
|
||||
|
||||
/obj/item/organ/external/arm/right
|
||||
limb_name = "r_arm"
|
||||
@@ -92,10 +92,10 @@
|
||||
return
|
||||
if(owner.AmountWeakened())
|
||||
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, preventing you from getting back up!</span>")
|
||||
owner.custom_emote(1, "is unable to get back up, [owner.p_their()] [name] malfunctioning!")
|
||||
owner.custom_emote(EMOTE_VISIBLE, "is unable to get back up, [owner.p_their()] [name] malfunctioning!")
|
||||
else
|
||||
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, dropping you to the ground!</span>")
|
||||
owner.custom_emote(1, "drops to the ground, [owner.p_their()] [name] malfunctioning!")
|
||||
owner.custom_emote(EMOTE_VISIBLE, "drops to the ground, [owner.p_their()] [name] malfunctioning!")
|
||||
switch(severity)
|
||||
if(1)
|
||||
owner.AdjustWeakened(8 SECONDS)
|
||||
@@ -130,10 +130,10 @@
|
||||
return
|
||||
if(owner.AmountWeakened())
|
||||
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, preventing you from getting back up!</span>")
|
||||
owner.custom_emote(1, "is unable to get back up, [owner.p_their()] [name] malfunctioning!")
|
||||
owner.custom_emote(EMOTE_VISIBLE, "is unable to get back up, [owner.p_their()] [name] malfunctioning!")
|
||||
else
|
||||
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, dropping you to the ground!</span>")
|
||||
owner.custom_emote(1, "drops to the ground, [owner.p_their()] [name] malfunctioning!")
|
||||
owner.custom_emote(EMOTE_VISIBLE, "drops to the ground, [owner.p_their()] [name] malfunctioning!")
|
||||
switch(severity)
|
||||
if(1)
|
||||
owner.AdjustWeakened(8 SECONDS)
|
||||
@@ -173,7 +173,7 @@
|
||||
if(hand && owner.canUnEquip(hand))
|
||||
owner.unEquip(hand)
|
||||
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, dropping what it was holding!</span>")
|
||||
owner.custom_emote(1, "drops what [owner.p_they()] [owner.p_were()] holding, [owner.p_their()] [name] malfunctioning!")
|
||||
owner.custom_emote(EMOTE_VISIBLE, "drops what [owner.p_they()] [owner.p_were()] holding, [owner.p_their()] [name] malfunctioning!")
|
||||
|
||||
/obj/item/organ/external/hand/remove()
|
||||
if(owner)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "component_tests.dm"
|
||||
#include "config_sanity.dm"
|
||||
#include "crafting_lists.dm"
|
||||
#include "emotes.dm"
|
||||
#include "log_format.dm"
|
||||
#include "map_templates.dm"
|
||||
#include "purchase_reference_test.dm"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
/datum/unit_test/emote/Run()
|
||||
// be aware that some of these values (like message, message_param) are subject to being set at runtime.
|
||||
for(var/emote_type in subtypesof(/datum/emote))
|
||||
var/datum/emote/cur_emote = new emote_type()
|
||||
if(cur_emote.message_param && !cur_emote.param_desc)
|
||||
Fail("emote [cur_emote] was given a message parameter without a description.")
|
||||
|
||||
// Sanity checks, these emotes probably won't appear to a user but we should make sure they're cleaned up.
|
||||
if(!cur_emote.key)
|
||||
if(cur_emote.message || cur_emote.message_param)
|
||||
Fail("emote [cur_emote] is missing a key but has a message defined.")
|
||||
if(cur_emote.key_third_person)
|
||||
Fail("emote [cur_emote] has a third-person key defined, but no first-person key. Either first person, both, or neither should be defined.")
|
||||
|
||||
// These are ones that might appear to a user, and so could use some special handling.
|
||||
else
|
||||
if(isnull(cur_emote.emote_type))
|
||||
Fail("emote [cur_emote] has a null target type.")
|
||||
|
||||
if(isnum(cur_emote.max_stat_allowed) && cur_emote.max_stat_allowed < cur_emote.stat_allowed)
|
||||
Fail("emote [cur_emote]'s max_stat_allowed is greater than its stat_allowed, and would be unusable.")
|
||||
|
||||
if(isnum(cur_emote.max_unintentional_stat_allowed) && cur_emote.max_unintentional_stat_allowed < cur_emote.unintentional_stat_allowed)
|
||||
Fail("emote [cur_emote]'s max_unintentional_stat_allowed is greater than its unintentional_stat_allowed, and would be unusable.")
|
||||
|
||||
|
||||
/datum/unit_test/emote/proc/has_punctuation(datum/emote/E, msg)
|
||||
return E.remove_ending_punctuation(msg) == msg
|
||||
Reference in New Issue
Block a user