mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2025-12-09 09:56:45 +00:00
/datum/emote - emote refactor, adds vocal cues (#6725)
datumizes and standardizes all emotes because that file is in the fucking way of my saycode rewrite adds vocal cues
This commit is contained in:
34
citadel.dme
34
citadel.dme
@@ -183,6 +183,7 @@
|
||||
#include "code\__DEFINES\controllers\timer.dm"
|
||||
#include "code\__DEFINES\datums\beam.dm"
|
||||
#include "code\__DEFINES\datums\design.dm"
|
||||
#include "code\__DEFINES\datums\emote.dm"
|
||||
#include "code\__DEFINES\dcs\flags.dm"
|
||||
#include "code\__DEFINES\dcs\helpers.dm"
|
||||
#include "code\__DEFINES\dcs\components\riding.dm"
|
||||
@@ -229,6 +230,7 @@
|
||||
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob-clickchain.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob-inventory.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob-perspective.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob-say.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_combat.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_main.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_mobility.dm"
|
||||
@@ -913,6 +915,24 @@
|
||||
#include "code\datums\elements\clothing\dynamic_recolor.dm"
|
||||
#include "code\datums\elements\items\darksight_granter.dm"
|
||||
#include "code\datums\elements\items\hud_granter.dm"
|
||||
#include "code\datums\emote\emote.dm"
|
||||
#include "code\datums\emote\types\standard.dm"
|
||||
#include "code\datums\emote\types\standard\basic.dm"
|
||||
#include "code\datums\emote\types\standard\basic\animal_noise.dm"
|
||||
#include "code\datums\emote\types\standard\basic\general.dm"
|
||||
#include "code\datums\emote\types\standard\basic\machine_noise.dm"
|
||||
#include "code\datums\emote\types\standard\basic\species.dm"
|
||||
#include "code\datums\emote\types\standard\basic\synth_sfx.dm"
|
||||
#include "code\datums\emote\types\standard\basic\general\blink.dm"
|
||||
#include "code\datums\emote\types\standard\basic\general\clap.dm"
|
||||
#include "code\datums\emote\types\standard\basic\general\cough.dm"
|
||||
#include "code\datums\emote\types\standard\basic\general\salute.dm"
|
||||
#include "code\datums\emote\types\standard\basic\general\sneeze.dm"
|
||||
#include "code\datums\emote\types\standard\basic\general\twitch.dm"
|
||||
#include "code\datums\emote\types\standard\basic\species\adherent.dm"
|
||||
#include "code\datums\emote\types\standard\basic\species\promethean.dm"
|
||||
#include "code\datums\emote\types\standard\basic\species\vox.dm"
|
||||
#include "code\datums\emote\types\standard\basic\species\xenomorph.dm"
|
||||
#include "code\datums\event_args\_event_args.dm"
|
||||
#include "code\datums\event_args\actor.dm"
|
||||
#include "code\datums\event_args\clickchain.dm"
|
||||
@@ -994,6 +1014,7 @@
|
||||
#include "code\datums\soundbytes\defs\explosion.dm"
|
||||
#include "code\datums\soundbytes\defs\sparks.dm"
|
||||
#include "code\datums\soundbytes\defs\spray.dm"
|
||||
#include "code\datums\soundbytes\defs\talksound.dm"
|
||||
#include "code\datums\soundbytes\defs\terminal_keyboard.dm"
|
||||
#include "code\datums\soundbytes\effects\combat.dm"
|
||||
#include "code\datums\soundbytes\guns\_guns.dm"
|
||||
@@ -3770,6 +3791,8 @@
|
||||
#include "code\modules\mob\mob-client.dm"
|
||||
#include "code\modules\mob\mob-damage.dm"
|
||||
#include "code\modules\mob\mob-defense.dm"
|
||||
#include "code\modules\mob\mob-emote.dm"
|
||||
#include "code\modules\mob\mob-emote_custom.dm"
|
||||
#include "code\modules\mob\mob-examine.dm"
|
||||
#include "code\modules\mob\mob-hands.dm"
|
||||
#include "code\modules\mob\mob-iff.dm"
|
||||
@@ -3780,6 +3803,9 @@
|
||||
#include "code\modules\mob\mob-inventory-stripping.dm"
|
||||
#include "code\modules\mob\mob-inventory.dm"
|
||||
#include "code\modules\mob\mob-keybind-triggers.dm"
|
||||
#include "code\modules\mob\mob-say-legacy.dm"
|
||||
#include "code\modules\mob\mob-say-triggers.dm"
|
||||
#include "code\modules\mob\mob-say.dm"
|
||||
#include "code\modules\mob\mob-login.dm"
|
||||
#include "code\modules\mob\mob-logout.dm"
|
||||
#include "code\modules\mob\mob-melee_attack_chain.dm"
|
||||
@@ -3795,7 +3821,6 @@
|
||||
#include "code\modules\mob\perspective.dm"
|
||||
#include "code\modules\mob\physiology.dm"
|
||||
#include "code\modules\mob\pulling.dm"
|
||||
#include "code\modules\mob\say.dm"
|
||||
#include "code\modules\mob\say_vr.dm"
|
||||
#include "code\modules\mob\ssd.dm"
|
||||
#include "code\modules\mob\status_procs.dm"
|
||||
@@ -3868,6 +3893,7 @@
|
||||
#include "code\modules\mob\living\living-damage.dm"
|
||||
#include "code\modules\mob\living\living-defense-legacy.dm"
|
||||
#include "code\modules\mob\living\living-defense.dm"
|
||||
#include "code\modules\mob\living\living-emote.dm"
|
||||
#include "code\modules\mob\living\living-interaction.dm"
|
||||
#include "code\modules\mob\living\living-inventory.dm"
|
||||
#include "code\modules\mob\living\living-melee_attack_chain.dm"
|
||||
@@ -3905,6 +3931,7 @@
|
||||
#include "code\modules\mob\living\carbon\carbon-cpr.dm"
|
||||
#include "code\modules\mob\living\carbon\carbon-damage.dm"
|
||||
#include "code\modules\mob\living\carbon\carbon-defense.dm"
|
||||
#include "code\modules\mob\living\carbon\carbon-emote.dm"
|
||||
#include "code\modules\mob\living\carbon\carbon-hands.dm"
|
||||
#include "code\modules\mob\living\carbon\carbon-interaction.dm"
|
||||
#include "code\modules\mob\living\carbon\carbon-movement.dm"
|
||||
@@ -3945,9 +3972,9 @@
|
||||
#include "code\modules\mob\living\carbon\alien\larva\larva.dm"
|
||||
#include "code\modules\mob\living\carbon\alien\larva\life.dm"
|
||||
#include "code\modules\mob\living\carbon\alien\larva\progression.dm"
|
||||
#include "code\modules\mob\living\carbon\brain\brain-emote.dm"
|
||||
#include "code\modules\mob\living\carbon\brain\brain.dm"
|
||||
#include "code\modules\mob\living\carbon\brain\death.dm"
|
||||
#include "code\modules\mob\living\carbon\brain\emote.dm"
|
||||
#include "code\modules\mob\living\carbon\brain\life.dm"
|
||||
#include "code\modules\mob\living\carbon\brain\login.dm"
|
||||
#include "code\modules\mob\living\carbon\brain\MMI.dm"
|
||||
@@ -4019,6 +4046,7 @@
|
||||
#include "code\modules\mob\living\silicon\silicon.dm"
|
||||
#include "code\modules\mob\living\silicon\subystems.dm"
|
||||
#include "code\modules\mob\living\silicon\translation.dm"
|
||||
#include "code\modules\mob\living\silicon\ai\ai-custom_emote.dm"
|
||||
#include "code\modules\mob\living\silicon\ai\ai-examine.dm"
|
||||
#include "code\modules\mob\living\silicon\ai\ai.dm"
|
||||
#include "code\modules\mob\living\silicon\ai\ai_movement.dm"
|
||||
@@ -4349,6 +4377,8 @@
|
||||
#include "code\modules\mob\observer\mobility.dm"
|
||||
#include "code\modules\mob\observer\observer.dm"
|
||||
#include "code\modules\mob\observer\perspective.dm"
|
||||
#include "code\modules\mob\observer\dead\dead-emote.dm"
|
||||
#include "code\modules\mob\observer\dead\dead-emote_custom.dm"
|
||||
#include "code\modules\mob\observer\dead\dead.dm"
|
||||
#include "code\modules\mob\observer\dead\free_vr.dm"
|
||||
#include "code\modules\mob\observer\dead\logout.dm"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
/// NAME: must be a string
|
||||
/// VALUE: the actual enum value, whatever it is
|
||||
#define BITFIELD_NEW(NAME, VALUE) #NAME = ##VALUE
|
||||
#define BITFIELD_NEW(NAME, VALUE) NAME = ##VALUE
|
||||
|
||||
/**
|
||||
* * `ID` the same in `DECLARE_BITFIELD`
|
||||
|
||||
64
code/__DEFINES/datums/emote.dm
Normal file
64
code/__DEFINES/datums/emote.dm
Normal file
@@ -0,0 +1,64 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
//* emote invocation output *//
|
||||
|
||||
/// no emote found
|
||||
#define EMOTE_INVOKE_INVALID 0
|
||||
/// the emote finished
|
||||
#define EMOTE_INVOKE_FINISHED 1
|
||||
/// the emote errored
|
||||
#define EMOTE_INVOKE_ERRORED 2
|
||||
/// the emote is running
|
||||
#define EMOTE_INVOKE_SLEEPING 3
|
||||
|
||||
//* emote_class's ; determines who can do what emote *//
|
||||
//* -- This is broadphase, effectively. *//
|
||||
// todo: DEFINE_BITFIELD_NEW
|
||||
|
||||
/// require body
|
||||
/// * so no brains
|
||||
#define EMOTE_CLASS_IS_BODY (1<<0)
|
||||
/// requires humanoid body
|
||||
/// * so no four legged animals
|
||||
#define EMOTE_CLASS_IS_HUMANOID (1<<1)
|
||||
|
||||
GLOBAL_REAL_LIST(emote_class_bit_descriptors) = list(
|
||||
"requires body",
|
||||
"requires humanoid",
|
||||
)
|
||||
|
||||
//* emote_require's ; more freeform classes that should invoke procs *//
|
||||
//* -- This is narrowphase and doesn't exclude emotes from listings, *//
|
||||
//* generally. *//
|
||||
// todo: DEFINE_BITFIELD_NEW
|
||||
|
||||
/// has a speaker of some kind
|
||||
/// * implies `EMOTE_REQUIRE_VOCALIZATION`
|
||||
#define EMOTE_REQUIRE_SYNTHETIC_SPEAKER (1<<0)
|
||||
/// can talk coherent words
|
||||
/// * implies `EMOTE_REQUIRE_VOCALIZATION`
|
||||
#define EMOTE_REQUIRE_COHERENT_SPEECH (1<<1)
|
||||
/// has a free hand
|
||||
/// * does not imply the actor isn't stunned
|
||||
#define EMOTE_REQUIRE_FREE_HAND (1<<2)
|
||||
/// require being able to make sounds at all
|
||||
#define EMOTE_REQUIRE_VOCALIZATION (1<<3)
|
||||
|
||||
GLOBAL_REAL_LIST(emote_require_bit_descriptors) = list(
|
||||
"requires synthetic speaker",
|
||||
"requires coherent speech",
|
||||
"requires free hand",
|
||||
"requires vocalization",
|
||||
)
|
||||
|
||||
//* emote arbitrary key-value store key's *//
|
||||
|
||||
/// the original parameter string passed in.
|
||||
#define EMOTE_PARAMETER_KEY_ORIGINAL "original"
|
||||
/// the target. hard reference. don't hold onto it for too long.
|
||||
#define EMOTE_PARAMETER_KEY_TARGET "target"
|
||||
/// for basic emotes; custom parameter, as tokens
|
||||
#define EMOTE_PARAMETER_KEY_CUSTOM_TOKENS "custom-tokens"
|
||||
/// resolved target as /atom ref
|
||||
#define EMOTE_PARAMETER_KEY_TARGET_RESOLVED "target-resolved"
|
||||
@@ -0,0 +1,7 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
// TODO: maybe this shouldn't be on mob?
|
||||
// TODO: on saycode refactor this'll be rewritten to atom level saycode receive.
|
||||
// called with (mob/from_mob, raw html, subtle, anti_ghost, saycode_type)
|
||||
#define COMSIG_MOB_ON_RECEIVE_CUSTOM_EMOTE "mob-on_receive_custom_emote"
|
||||
@@ -22,10 +22,6 @@
|
||||
//// From /mob/living/say(): ()
|
||||
#define COMSIG_MOB_SAY "mob_say"
|
||||
|
||||
/// Sent on custom emote. (mob, raw_emote)
|
||||
#define COMSIG_MOB_CUSTOM_EMOTE "custom_emote"
|
||||
/// Sent on subtle/subtler. (mob, raw_emote)
|
||||
#define COMSIG_MOB_SUBTLE_EMOTE "subtle_emote"
|
||||
/// Sent when a mob/login() finishes: (client)
|
||||
#define COMSIG_MOB_CLIENT_LOGIN "comsig_mob_client_login"
|
||||
/// Sent when a mob/logout() begins: (client)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/// works as long as can see
|
||||
#define SAYCODE_TYPE_VISIBLE 1
|
||||
/// works as long as can hear
|
||||
@@ -8,3 +11,8 @@
|
||||
#define SAYCODE_TYPE_LIVING 4
|
||||
/// it just works
|
||||
#define SAYCODE_TYPE_ALWAYS 5
|
||||
/// special
|
||||
///
|
||||
/// * runtime / stack traces if used in actual saycode
|
||||
/// * used in emotes for automatically generating both visible and audible messages
|
||||
#define SAYCODE_TYPE_AUTO 6
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#define ADD_TRAIT_IN(target, trait, source, time) addtimer(CALLBACK(target, TYPE_PROC_REF(/datum, ___callbackaddtrait), trait, source), time);
|
||||
#define REMOVE_TRAIT(target, trait, sources) \
|
||||
do { \
|
||||
var/list/_L = target.status_traits; \
|
||||
@@ -39,21 +40,7 @@
|
||||
}; \
|
||||
} \
|
||||
} while (0)
|
||||
#define REMOVE_TRAITS_NOT_IN(target, sources) \
|
||||
do { \
|
||||
var/list/_L = target.status_traits; \
|
||||
var/list/_S = sources; \
|
||||
if (_L) { \
|
||||
for (var/_T in _L) { \
|
||||
_L[_T] &= _S;\
|
||||
if (!length(_L[_T])) { \
|
||||
_L -= _T } \
|
||||
};\
|
||||
if (!length(_L)) { \
|
||||
target.status_traits = null\
|
||||
};\
|
||||
}\
|
||||
} while (0)
|
||||
#define REMOVE_TRAIT_IN(target, trait, source, time) addtimer(CALLBACK(target, TYPE_PROC_REF(/datum, ___callbackdeltrait), trait, source), time);
|
||||
#define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE)
|
||||
#define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE)
|
||||
#define HAS_TRAIT_FROM_ONLY(target, trait, source) (\
|
||||
@@ -64,6 +51,12 @@
|
||||
: FALSE)
|
||||
#define HAS_TRAIT_NOT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (length(target.status_traits[trait] - source) > 0) : FALSE) : FALSE)
|
||||
|
||||
/datum/proc/___callbackaddtrait(trait, source)
|
||||
ADD_TRAIT(src, trait, source)
|
||||
|
||||
/datum/proc/___callbackdeltrait(trait, source)
|
||||
REMOVE_TRAIT(src, trait, source)
|
||||
|
||||
/// trait registration defines
|
||||
/// due to how defines work, this goes AFTER the trait define!
|
||||
#define DATUM_TRAIT(TYPE, TRAIT)
|
||||
|
||||
@@ -52,8 +52,12 @@ DATUM_TRAIT(/mob, TRAIT_MOB_SLEEPING)
|
||||
#define TRAIT_MOB_FORCED_STANDING "mob_forced_standing"
|
||||
DATUM_TRAIT(/mob, TRAIT_MOB_FORCED_STANDING)
|
||||
|
||||
//? misc
|
||||
//* Misc *//
|
||||
|
||||
/// Emote cooldown trait
|
||||
#define TRAIT_EMOTE_COOLDOWN(KEY) "emote-cd-[KEY]"
|
||||
/// Emote cooldown trait
|
||||
#define TRAIT_EMOTE_GLOBAL_COOLDOWN "emote-cd"
|
||||
/// Tracks whether you're a mime or not.
|
||||
#define TRAIT_MIMING "miming"
|
||||
DATUM_TRAIT(/mob, TRAIT_MIMING)
|
||||
|
||||
@@ -582,7 +582,7 @@
|
||||
if(isnewplayer(player_mob)) // exclude people in the lobby
|
||||
continue
|
||||
if(isobserver(player_mob)) // Ghosts are fine if they were playing once (didn't start as observers)
|
||||
// var/mob/dead/observer/ghost_player = player_mob
|
||||
// var/mob/observer/dead/ghost_player = player_mob
|
||||
// if(ghost_player.started_as_observer) // Exclude people who started as observers
|
||||
continue
|
||||
active_players++
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
var/list/viewrangelist = splittext(view,"x")
|
||||
return list(text2num(viewrangelist[1]), text2num(viewrangelist[2]))
|
||||
|
||||
// TODO: optimize
|
||||
/proc/world_view_max_number()
|
||||
if(isnum(world.view))
|
||||
return world.view
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
/**
|
||||
* Replaces all instances of "$key" in a text string with the given variable.
|
||||
* Replaces all instances of "%%key%%" in a text string with the given variable.
|
||||
*
|
||||
* Keys are provided as a key list associated to replacements.
|
||||
*
|
||||
* Example: string_format("$user hits $target with $weapon", list("user" = src, "target" = target, "weapon" = get_active_held_item()))
|
||||
* Example: string_format("%%user%% hits $target with %%weapon%%", list("user" = src, "target" = target, "weapon" = get_active_held_item()))
|
||||
*/
|
||||
/proc/string_format(str, list/keys)
|
||||
. = str
|
||||
@@ -15,4 +15,4 @@
|
||||
return
|
||||
// todo: optimize this if needed, maybe dynamic regex?
|
||||
for(var/key in keys)
|
||||
. = replacetext_char(., "$[key]", keys[key])
|
||||
. = replacetext_char(., "%%[key]%%", keys[key])
|
||||
|
||||
@@ -5,7 +5,8 @@ SUBSYSTEM_DEF(early_init)
|
||||
subsystem_flags = SS_NO_FIRE
|
||||
|
||||
/datum/controller/subsystem/early_init/Initialize()
|
||||
init_inventory_slot_meta()
|
||||
init_crayon_decal_meta()
|
||||
init_bitfield_meta()
|
||||
init_emote_meta()
|
||||
init_crayon_decal_meta()
|
||||
init_inventory_slot_meta()
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
@@ -11,16 +11,19 @@
|
||||
var/div_slider = slidecolor
|
||||
if(!i["allowed_edit"])
|
||||
div_slider = "locked"
|
||||
var/entry_name = html_encode(i["name"])
|
||||
var/entry_checked = i["checked"]
|
||||
output += {"<li>
|
||||
<label class="switch">
|
||||
<input type="[inputtype]" value="1" name="[i["name"]]"[i["checked"] ? " checked" : ""][i["allowed_edit"] ? "" : " onclick='return false' onkeydown='return false'"]>
|
||||
<input type="[inputtype]" value="1" name="[entry_name]"[entry_checked ? " checked" : ""][i["allowed_edit"] ? "" : " onclick='return false' onkeydown='return false'"] />
|
||||
<div class="slider [div_slider ? "[div_slider]" : ""]"></div>
|
||||
<span>[i["name"]]</span>
|
||||
</label>
|
||||
</li>"}
|
||||
else
|
||||
for (var/i in values)
|
||||
output += {"<li><input id="name="[i["name"]]"" style="width: 50px" type="[type]" name="[i["name"]]" value="[i["value"]]">
|
||||
var/entry_name = html_encode(i["name"])
|
||||
output += {"<li><input id="name="[i["name"]]"" style="width: 50px" type="[type]" name="[entry_name]" value="[i["value"]]" />
|
||||
<label for="[i["name"]]">[i["name"]]</label></li>"}
|
||||
output += {"</ul><div style="text-align:center">
|
||||
<button type="submit" name="button" value="1" style="font-size:large;float:[( Button2 ? "left" : "right" )]">[Button1]</button>"}
|
||||
|
||||
270
code/datums/emote/emote.dm
Normal file
270
code/datums/emote/emote.dm
Normal file
@@ -0,0 +1,270 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
// init'd by early init
|
||||
GLOBAL_LIST(emotes)
|
||||
// init'd by early init
|
||||
GLOBAL_LIST(emote_lookup)
|
||||
|
||||
/proc/init_emote_meta()
|
||||
GLOB.emotes = list()
|
||||
GLOB.emote_lookup = list()
|
||||
|
||||
for(var/datum/emote/path as anything in subtypesof(/datum/emote))
|
||||
if(initial(path.abstract_type) == path)
|
||||
continue
|
||||
var/datum/emote/instance = new path
|
||||
GLOB.emotes += instance
|
||||
|
||||
for(var/binding in islist(instance.bindings) ? instance.bindings : list(instance.bindings))
|
||||
if(GLOB.emote_lookup[binding])
|
||||
var/datum/emote/existing = GLOB.emote_lookup[binding]
|
||||
stack_trace("collision between [existing.type] and [instance.type] on [binding]")
|
||||
break
|
||||
GLOB.emote_lookup[binding] = instance
|
||||
|
||||
tim_sort(GLOB.emotes, /proc/cmp_name_asc)
|
||||
|
||||
/proc/fetch_emote(key) as /datum/emote
|
||||
return GLOB.emote_lookup[key]
|
||||
|
||||
/**
|
||||
* Emotes!
|
||||
*
|
||||
* * Custom /me emotes are not part of this. They're way too weird / expressive.
|
||||
*/
|
||||
/datum/emote
|
||||
abstract_type = /datum/emote
|
||||
|
||||
/// emote name
|
||||
var/name = "Unnamed Emote (Yell at Coders)"
|
||||
/// emote desc, if any
|
||||
var/desc = "An action you can perform with your character. Yell at coders to set descriptions if you see this."
|
||||
/// our bindings key(s)
|
||||
///
|
||||
/// * can be a string or a list
|
||||
/// * if a list, the first string in the list is the primary; rest are alises
|
||||
/// * for now, emote bindings must be unique to a single emote. in the future, this may change.
|
||||
var/bindings
|
||||
/// a prefix to use before our binding
|
||||
/// * applies to all bindings in bindings list if specified
|
||||
var/binding_prefix
|
||||
/// parameter help string rendered as "[binding] [parameter_description]"
|
||||
var/parameter_description
|
||||
|
||||
/// our emote classes
|
||||
/// * A mob must have all of these to use us.
|
||||
/// * Missing a class will stop us from appearing in the mob's emote-help panel at all.
|
||||
var/emote_class = NONE
|
||||
/// our emote require's
|
||||
/// * A mob must have all of these to use us.
|
||||
/// * Unlike `emote_class`, not having this doesn't exclude the emote from the 'help' list,
|
||||
/// as these are assumed to be more temporary.
|
||||
var/emote_require = NONE
|
||||
/// mobility flags needed to invoke (all of them are if set)
|
||||
var/required_mobility_flags = MOBILITY_IS_CONSCIOUS
|
||||
|
||||
/// cannot invoke this again for x time
|
||||
var/self_cooldown = 0 SECONDS
|
||||
|
||||
/datum/emote/New()
|
||||
// preprocess bindings
|
||||
if(binding_prefix)
|
||||
if(islist(bindings))
|
||||
for(var/i in 1 to length(bindings))
|
||||
bindings[i] = "[binding_prefix]-[bindings[i]]"
|
||||
else
|
||||
bindings = "[binding_prefix]-[bindings]"
|
||||
|
||||
//* Checks *//
|
||||
|
||||
/**
|
||||
* Fast check. Emits no errors; can_use() should have all checks in here as this is only used
|
||||
* to do the menu check.
|
||||
*/
|
||||
/datum/emote/proc/can_potentially_use(datum/event_args/actor/actor, use_emote_class)
|
||||
return (emote_class & use_emote_class) == emote_class
|
||||
|
||||
/**
|
||||
* @params
|
||||
* * actor - actor data
|
||||
* * arbitrary - arbitrary processed params
|
||||
* * out_reasons_fail - out reasons we can't be used right now
|
||||
*/
|
||||
/datum/emote/proc/can_use(datum/event_args/actor/actor, list/arbitrary, list/out_reasons_fail)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
|
||||
var/special_check = can_use_special(actor, arbitrary, out_reasons_fail)
|
||||
if(!isnull(special_check))
|
||||
return special_check
|
||||
var/their_class = actor.performer.get_usable_emote_class()
|
||||
var/their_require = actor.performer.get_usable_emote_require()
|
||||
if((their_class & emote_class) != emote_class)
|
||||
var/missing_class = emote_class & ~their_class
|
||||
if(out_reasons_fail)
|
||||
for(var/i in 1 to length(global.emote_class_bit_descriptors))
|
||||
if((1<<(i - 1)) & missing_class)
|
||||
out_reasons_fail?.Add(global.emote_class_bit_descriptors[i])
|
||||
return FALSE
|
||||
if((their_require & emote_require) != emote_require)
|
||||
var/missing_require = emote_require & ~their_require
|
||||
if(out_reasons_fail)
|
||||
for(var/i in 1 to length(global.emote_require_bit_descriptors))
|
||||
if((1<<(i - 1)) & missing_require)
|
||||
out_reasons_fail?.Add(global.emote_require_bit_descriptors[i])
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* @params
|
||||
* * actor - (optional) the provided actor
|
||||
* * arbitrary - (optional) arbitrary processed params
|
||||
* * out_reasons_fail - out reasons we can't be used right now
|
||||
*
|
||||
* @return non-null TRUE / FALSE to override [can_use()]
|
||||
*/
|
||||
/datum/emote/proc/can_use_special(datum/event_args/actor/actor, list/arbitrary, list/out_reasons_fail)
|
||||
return
|
||||
|
||||
//* Execution *//
|
||||
|
||||
/**
|
||||
* Process passed in string (so anything after a **single** space from the emote key) to an 'arbitrary',
|
||||
* which is just how we process params
|
||||
*
|
||||
* @return the 'arbitrary' param passed into the rest of the emote call chain, null on fail
|
||||
*/
|
||||
/datum/emote/proc/process_parameters(parameter_string, datum/event_args/actor/actor, silent)
|
||||
return list(EMOTE_PARAMETER_KEY_ORIGINAL = parameter_string)
|
||||
|
||||
/**
|
||||
* Standard parameter tokenization. Allows double-quoting, single-quoting, and just space-ing
|
||||
* @return list, or null on fail
|
||||
*/
|
||||
/datum/emote/proc/tokenize_parameters(parameter_string, datum/event_args/actor/actor, silent)
|
||||
// incase they try something fishy
|
||||
// notice the length(); curse of RA can be a problem.
|
||||
if(length(parameter_string) >= MAX_MESSAGE_LEN)
|
||||
loudly_reject_failure("---", actor, silent, "Parameters were too large; skipping emote.")
|
||||
return null
|
||||
if(!parameter_string)
|
||||
return list()
|
||||
var/len = length_char(parameter_string)
|
||||
var/in_space = TRUE
|
||||
var/active_border_char
|
||||
var/active_token_pos
|
||||
|
||||
. = list()
|
||||
// TODO: faster regex tokenizer?
|
||||
for(var/pos in 1 to len)
|
||||
var/char = parameter_string[pos]
|
||||
|
||||
var/is_border = FALSE
|
||||
var/ignore_one
|
||||
switch(char)
|
||||
if("\"", "'")
|
||||
if(in_space)
|
||||
is_border = TRUE
|
||||
ignore_one = TRUE
|
||||
else if(char == active_border_char)
|
||||
is_border = TRUE
|
||||
ignore_one = TRUE
|
||||
else
|
||||
// being inside a token = ignored
|
||||
continue
|
||||
// no unicode spaces too bad
|
||||
if(" ")
|
||||
if(in_space)
|
||||
// still in space just keep going
|
||||
continue
|
||||
else
|
||||
if(active_border_char)
|
||||
// special border char; keep going until finding another
|
||||
continue
|
||||
else
|
||||
// we were in a word and aren't bounded by active border char;
|
||||
// this is a border
|
||||
is_border = TRUE
|
||||
ignore_one = TRUE
|
||||
// another character
|
||||
else
|
||||
// if we're in space and we find a non-special non-space
|
||||
// it's the immediate start of a token
|
||||
if(in_space)
|
||||
is_border = TRUE
|
||||
ignore_one = FALSE
|
||||
if(is_border)
|
||||
// we're at the start or an end of a token
|
||||
if(in_space)
|
||||
// start token
|
||||
in_space = FALSE
|
||||
active_token_pos = ignore_one ? pos + 1 : pos
|
||||
switch(char)
|
||||
if("\"", "'")
|
||||
active_border_char = char
|
||||
else
|
||||
// end token
|
||||
var/token = copytext_char(parameter_string, active_token_pos, pos + (ignore_one ? 0 : 1))
|
||||
active_border_char = null
|
||||
in_space = TRUE
|
||||
. += token
|
||||
|
||||
// if we're in a token,
|
||||
if(!in_space)
|
||||
if(active_border_char)
|
||||
// mismatched somewhere
|
||||
loudly_reject_failure(parameter_string, actor, silent, "Mismatched '[active_border_char]' in parameters.")
|
||||
return null
|
||||
else
|
||||
// was using space so just insert last
|
||||
var/last_token = copytext_char(parameter_string, active_token_pos, len + 1)
|
||||
. += last_token
|
||||
|
||||
/**
|
||||
* Tries to run an emote, if someone's allowed to.
|
||||
* * Blocking proc.
|
||||
* @params
|
||||
* * actor - person doing it
|
||||
* * arbitrary - parsed arbitrary params from tokenized parameter string
|
||||
* * silent - don't emit errors to actor
|
||||
* * used_binding - binding used by user, if any
|
||||
*/
|
||||
/datum/emote/proc/try_run_emote(datum/event_args/actor/actor, list/arbitrary, silent, used_binding)
|
||||
var/list/why_not = list()
|
||||
var/can_run = can_use(actor, arbitrary, why_not)
|
||||
if(!can_run)
|
||||
if(!silent)
|
||||
actor?.chat_feedback(SPAN_WARNING("You can't '[used_binding || name]' right now; ([english_list(why_not, "unknown reason")])"))
|
||||
return FALSE
|
||||
run_emote(actor, arbitrary, silent, used_binding)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Blocking proc.
|
||||
*
|
||||
* Runs an emote.
|
||||
* * This can still fail if things fail to be parsed from arbitrary list.
|
||||
*
|
||||
* @params
|
||||
* * actor - actor data
|
||||
* * arbitrary - arbitrary processed params
|
||||
* * silent - suppress errors
|
||||
*
|
||||
* @return pass / fail
|
||||
*/
|
||||
/datum/emote/proc/run_emote(datum/event_args/actor/actor, list/arbitrary, silent, used_binding)
|
||||
return TRUE
|
||||
|
||||
/datum/emote/proc/get_mob_context(mob/invoking)
|
||||
return invoking.emotes_running?[src]
|
||||
|
||||
/datum/emote/proc/set_mob_context(mob/invoking, ctx)
|
||||
if(!invoking.emotes_running)
|
||||
invoking.emotes_running = list()
|
||||
invoking.emotes_running[src] = ctx
|
||||
|
||||
/datum/emote/proc/loudly_reject_failure(parameter_string, datum/event_args/actor/actor, silent, reason)
|
||||
if(!silent)
|
||||
actor?.chat_feedback(
|
||||
SPAN_WARNING("Failed emote parse on {[parameter_string]} - [reason]"),
|
||||
)
|
||||
39
code/datums/emote/types/standard.dm
Normal file
39
code/datums/emote/types/standard.dm
Normal file
@@ -0,0 +1,39 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/**
|
||||
* General handling for SFX / VFX / a lot of other stuff
|
||||
*/
|
||||
/datum/emote/standard
|
||||
abstract_type = /datum/emote/standard
|
||||
|
||||
//* SFX *//
|
||||
/// sound to play, or a list of sounds to pick from (equal weight)
|
||||
var/sfx
|
||||
/// volume of sound to play
|
||||
var/sfx_volume = 75
|
||||
/// vary the sound?
|
||||
var/sfx_vary = TRUE
|
||||
/// extra range
|
||||
///
|
||||
/// todo: legacy; playsound should allow specifying range directly.
|
||||
var/sfx_extra_range = 0
|
||||
|
||||
//* VFX *//
|
||||
// todo: vfx support
|
||||
|
||||
/datum/emote/standard/run_emote(datum/event_args/actor/actor, list/arbitrary, silent, used_binding)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/sfx = get_sfx(actor, arbitrary)
|
||||
play_sfx(actor, arbitrary, sfx)
|
||||
|
||||
/**
|
||||
* Gets a SFX to play.
|
||||
*/
|
||||
/datum/emote/standard/proc/get_sfx(datum/event_args/actor/actor, list/arbitrary)
|
||||
return islist(sfx) ? (length(sfx) ? pick(sfx) : null) : sfx
|
||||
|
||||
/datum/emote/standard/proc/play_sfx(datum/event_args/actor/actor, list/arbitrary, sfx)
|
||||
playsound(actor.performer, sfx, sfx_volume, sfx_vary)
|
||||
224
code/datums/emote/types/standard/basic.dm
Normal file
224
code/datums/emote/types/standard/basic.dm
Normal file
@@ -0,0 +1,224 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/**
|
||||
* Basic emotes that just emit a simple message or something.
|
||||
*
|
||||
* * This is in reality just a generic emote subtype that handles most cases.
|
||||
* * 'arbitrary' will be a list of key-values, with EMOTE_PARAMETER_KEY_*.
|
||||
* * parameters are a list of strings; you can do strings with spaces with "string here". \" will escape doublequotes, \\ will escape a \
|
||||
* * named parameters are not yet supported. it's too expensive to process these.
|
||||
* * you are allowed one custom parameter in addition to default parameters generated by this type (like 'target').
|
||||
* * the custom parameter will be under EMOTE_PARAMETER_KEY_CUSTOM.
|
||||
*
|
||||
* Params
|
||||
*/
|
||||
/datum/emote/standard/basic
|
||||
abstract_type = /datum/emote/standard/basic
|
||||
|
||||
//* Feedback *//
|
||||
|
||||
/// outgoing saycode type flags
|
||||
///
|
||||
/// If set to AUTO, the following happens:
|
||||
/// * If the hearer can see, normal / visible text is used
|
||||
/// * If the hearer can't see an actor, 'someone / something' replaces that actor
|
||||
/// * If the hearer cannot see, audible is used with no replacement.
|
||||
///
|
||||
/// If set to anything that isn't AUTO, the following happens:
|
||||
/// * ALWAYS, LIVING, CONSCIOUS will always use visible string, never audible
|
||||
/// * VISIBLE will always use visible string, never audible
|
||||
/// * AUDIBLE will always use audible string, falling back to visible if it exists
|
||||
var/feedback_saycode_type = SAYCODE_TYPE_AUTO
|
||||
|
||||
/**
|
||||
* Override order as follows:
|
||||
*
|
||||
* 1. Miming, if miming
|
||||
* 2. Muzzled, if muzzled
|
||||
* 3. Targeted, if there is a target
|
||||
* 4. Default
|
||||
*/
|
||||
|
||||
/// if existing, and we're miming, we immediately switch saycode mode to visible if we're on auto
|
||||
///
|
||||
/// * %%USER%% is replaced with the user.
|
||||
/// * If the replacement is at the start of the string, it'll be capitalized as needed.
|
||||
/// * HTML is valid
|
||||
var/feedback_special_miming
|
||||
/// targeted version of miming
|
||||
///
|
||||
/// * %%USER%% is replaced with the user.
|
||||
/// * %%TARGET%% is replaced with a target.
|
||||
/// * If the replacement is at the start of the string, it'll be capitalized as needed.
|
||||
/// * HTML is valid
|
||||
var/feedback_special_miming_targeted
|
||||
|
||||
/// if existing, and we're muzzled, we immediately switch to this
|
||||
///
|
||||
/// * %%USER%% is replaced with the user.
|
||||
/// * If the replacement is at the start of the string, it'll be capitalized as needed.
|
||||
/// * HTML is valid
|
||||
var/feedback_special_muzzled
|
||||
/// targeted version of muzzled
|
||||
///
|
||||
/// * %%USER%% is replaced with the user.
|
||||
/// * %%TARGET%% is replaced with a target.
|
||||
/// * If the replacement is at the start of the string, it'll be capitalized as needed.
|
||||
/// * HTML is valid
|
||||
var/feedback_special_muzzled_targeted
|
||||
/// audible descriptor for muzzled
|
||||
///
|
||||
/// * HTML is valid
|
||||
var/feedback_special_muzzled_audible
|
||||
|
||||
/// the default feedback string
|
||||
///
|
||||
/// * If heard, audible has %%USER%% replaced with "someone" if the viewer is blind.
|
||||
/// * If the replacement is at the start of the string, it'll be capitalized as needed.
|
||||
/// * HTML is valid
|
||||
var/feedback_default = "<b>%%USER%%</b> does something that isn't implemented by the coders. (Yell at coders, someone forgot a default string.)"
|
||||
/// the default targeted feedback sting
|
||||
///
|
||||
/// * %%USER%% is replaced with the user.
|
||||
/// * %%TARGET%% is replaced with a target.
|
||||
/// * If the replacement is at the start of the string, it'll be capitalized as needed.
|
||||
/// * HTML is valid
|
||||
var/feedback_default_targeted
|
||||
/// the default audible descriptor
|
||||
///
|
||||
/// * HTML is valid
|
||||
var/feedback_default_audible = "You hear something that isn't implemented by the coders. (Yell at coders, someone forgot a default string.)"
|
||||
|
||||
//* Parameter *//
|
||||
|
||||
/// has a custom parameter
|
||||
/// * if enabled, it goes *before* target
|
||||
/// * this means that it must be specified to specify a target at all
|
||||
var/parameter_custom = FALSE
|
||||
/// your custom parameter help string
|
||||
var/parameter_custom_description
|
||||
|
||||
//* Targeting *//
|
||||
|
||||
/// Allows targeting?
|
||||
/// * overrides [target_required]
|
||||
var/target_allowed = FALSE
|
||||
/// requires a target?
|
||||
var/target_required = FALSE
|
||||
/// maximum distance target can be from us
|
||||
var/target_range = 7
|
||||
/// allow target self
|
||||
var/target_allow_self = FALSE
|
||||
|
||||
/datum/emote/standard/basic/New()
|
||||
if(isnull(parameter_description))
|
||||
parameter_description = generate_parameter_description()
|
||||
else
|
||||
stack_trace("[NAMEOF(src, parameter_description)] was set, but it should be autogenerated!")
|
||||
..()
|
||||
|
||||
/datum/emote/standard/basic/proc/generate_parameter_description()
|
||||
return "[parameter_custom ? "\[[(parameter_custom_description || "Custom Parameter (Yell at coders!)")]\]" : ""]\
|
||||
[target_allowed ? " \[target[target_required ? "" : "?"]\]" : ""]"
|
||||
|
||||
/datum/emote/standard/basic/process_parameters(parameter_string, datum/event_args/actor/actor, silent)
|
||||
var/list/tokenized = tokenize_parameters(parameter_string, actor, silent)
|
||||
if(tokenized == null)
|
||||
return null
|
||||
. = ..()
|
||||
if(parameter_custom)
|
||||
var/got_target
|
||||
if(target_allowed)
|
||||
if(target_required)
|
||||
if(length(tokenized) <= 2)
|
||||
loudly_reject_failure(parameter_string, actor, silent, "A target is required.")
|
||||
return null
|
||||
if(length(tokenized) >= 2)
|
||||
.[EMOTE_PARAMETER_KEY_TARGET] = tokenized[2]
|
||||
got_target = TRUE
|
||||
if(length(tokenized) >= 1)
|
||||
.[EMOTE_PARAMETER_KEY_CUSTOM_TOKENS] = tokenized.Copy(1, length(tokenized) + got_target ? 0 : 1)
|
||||
else
|
||||
if(target_allowed)
|
||||
if(target_required)
|
||||
if(length(tokenized) <= 1)
|
||||
loudly_reject_failure(parameter_string, actor, silent, "A target is required.")
|
||||
return null
|
||||
if(length(tokenized) >= 1)
|
||||
.[EMOTE_PARAMETER_KEY_TARGET] = tokenized[1]
|
||||
|
||||
/datum/emote/standard/basic/run_emote(datum/event_args/actor/actor, list/arbitrary, silent, used_binding)
|
||||
var/target_string = arbitrary[EMOTE_PARAMETER_KEY_TARGET]
|
||||
if(target_string)
|
||||
var/mob/resolved
|
||||
for(var/mob/maybe_target in hearers())
|
||||
if(maybe_target == actor.performer && !target_allow_self)
|
||||
continue
|
||||
if(findtext(maybe_target.name, target_string))
|
||||
resolved = maybe_target
|
||||
break
|
||||
if(!resolved)
|
||||
if(!silent)
|
||||
actor?.chat_feedback(SPAN_WARNING("No one around you's named '[target_string]'!"))
|
||||
return FALSE
|
||||
else
|
||||
arbitrary[EMOTE_PARAMETER_KEY_TARGET_RESOLVED] = resolved
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
on_run_emote(
|
||||
actor,
|
||||
arbitrary,
|
||||
arbitrary[EMOTE_PARAMETER_KEY_CUSTOM_TOKENS],
|
||||
arbitrary[EMOTE_PARAMETER_KEY_TARGET_RESOLVED],
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/proc/on_run_emote(datum/event_args/actor/actor, list/arbitrary, list/maybe_custom_param_tokens, atom/maybe_target)
|
||||
var/template_string_visible = get_template_string(actor, arbitrary, FALSE)
|
||||
var/template_string_audible = get_template_string(actor, arbitrary, TRUE)
|
||||
var/list/template_parameters = get_template_parameters(actor, arbitrary)
|
||||
|
||||
var/out_visible = string_format(template_string_visible, template_parameters)
|
||||
var/out_audible = string_format(template_string_audible, template_parameters)
|
||||
|
||||
var/list/mob/hearing_mobs = actor.performer.saycode_view_query(null, TRUE, FALSE)
|
||||
// TODO: centralized observer pref check in saycode_view_query
|
||||
var/optimize_this_later_max_number = world_view_max_number() + 2
|
||||
// TODO: proper runechat stuff.
|
||||
actor.performer.say_overhead(out_visible)
|
||||
for(var/mob/hearing as anything in hearing_mobs)
|
||||
if(isobserver(hearing))
|
||||
if((get_dist(hearing, src) > optimize_this_later_max_number) && !hearing.get_preference_toggle(/datum/game_preference_toggle/observer/ghost_sight))
|
||||
continue
|
||||
if(hearing.is_blind())
|
||||
if(hearing.is_deaf())
|
||||
else
|
||||
hearing.show_message(out_audible, SAYCODE_TYPE_ALWAYS)
|
||||
else
|
||||
hearing.show_message(out_visible, SAYCODE_TYPE_ALWAYS)
|
||||
|
||||
/**
|
||||
* Get template parameters for 'feedback_' vars.
|
||||
*/
|
||||
/datum/emote/standard/basic/proc/get_template_parameters(datum/event_args/actor/actor, list/arbitrary)
|
||||
. = list("USER" = actor.performer)
|
||||
if(target_allowed)
|
||||
var/atom/maybe_target = arbitrary[EMOTE_PARAMETER_KEY_TARGET_RESOLVED]
|
||||
.["TARGET"] = maybe_target ? "[maybe_target]" : "something"
|
||||
|
||||
/datum/emote/standard/basic/proc/get_template_string(datum/event_args/actor/actor, list/arbitrary, audible)
|
||||
// TODO: miming
|
||||
// TODO: muzzled
|
||||
if(audible)
|
||||
return feedback_default_audible
|
||||
if(target_allowed && arbitrary[EMOTE_PARAMETER_KEY_TARGET])
|
||||
return feedback_default_targeted
|
||||
return feedback_default
|
||||
|
||||
/**
|
||||
* Processes a custom parameter
|
||||
*/
|
||||
/datum/emote/standard/basic/proc/process_custom_parameter(datum/event_args/actor/actor, string)
|
||||
// default to just spitting the string back out
|
||||
return string
|
||||
73
code/datums/emote/types/standard/basic/animal_noise.dm
Normal file
73
code/datums/emote/types/standard/basic/animal_noise.dm
Normal file
@@ -0,0 +1,73 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/animal_noise
|
||||
abstract_type = /datum/emote/standard/basic/animal_noise
|
||||
emote_require = EMOTE_REQUIRE_VOCALIZATION
|
||||
// TODO: parameter to enable this / set frequency
|
||||
sfx_vary = FALSE
|
||||
|
||||
/datum/emote/standard/basic/animal_noise/awoo
|
||||
name = "Awoo"
|
||||
desc = "Let out an awoo."
|
||||
bindings = "awoo"
|
||||
feedback_special_miming = "<b>%%USER%%</b> acts out an awoo."
|
||||
feedback_default = "<b>%%USER%%</b> awoos!"
|
||||
feedback_default_audible = "You hear an awoo."
|
||||
sfx = 'sound/voice/awoo.ogg'
|
||||
sfx_volume = 50
|
||||
|
||||
/datum/emote/standard/basic/animal_noise/bird_beep
|
||||
name = "Bird Peep"
|
||||
desc = "Peep like a bird."
|
||||
bindings = list(
|
||||
"peep",
|
||||
"bird-peep",
|
||||
)
|
||||
feedback_special_miming = "<b>%%USER%%</b> bobs as if they're peeping like a bird."
|
||||
feedback_default = "<b>%%USER%%</b> peeps like a bird!"
|
||||
feedback_default_audible = "You hear a peep."
|
||||
sfx = 'sound/voice/peep.ogg'
|
||||
sfx_volume = 50
|
||||
|
||||
/datum/emote/standard/basic/animal_noise/clak
|
||||
name = "Clak"
|
||||
desc = "... Clak. What?."
|
||||
bindings = "clak"
|
||||
feedback_default = "<b>%%USER%%</b> <font color='grey' size='2'>CLAKS!</font>!"
|
||||
feedback_default_audible = "You hear a <font color='grey' size='2'>CLAK</font>."
|
||||
sfx = 'sound/spooky/boneclak.ogg'
|
||||
sfx_volume = 50
|
||||
|
||||
/datum/emote/standard/basic/animal_noise/meow
|
||||
name = "Meow"
|
||||
desc = "Let out a meow."
|
||||
bindings = "meow"
|
||||
feedback_special_miming = "<b>%%USER%%</b> acts out a soft mrowl."
|
||||
feedback_default = "<b>%%USER%%</b> mrowls!"
|
||||
feedback_default_audible = "You hear a mrowl."
|
||||
sfx = 'sound/voice/meow1.ogg'
|
||||
sfx_volume = 50
|
||||
|
||||
/datum/emote/standard/basic/animal_noise/nya
|
||||
name = "Nya"
|
||||
desc = "Let out a nya."
|
||||
bindings = "nya"
|
||||
feedback_special_miming = "<b>%%USER%%</b> acts out a cartoony cat noise, whatever that means."
|
||||
feedback_default = "<b>%%USER%%</b> lets out a nya!"
|
||||
feedback_default_audible = "You hear an unrealistically cartoony cat noise."
|
||||
sfx = 'sound/voice/nya.ogg'
|
||||
sfx_volume = 50
|
||||
|
||||
/datum/emote/standard/basic/animal_noise/squeak_mouse
|
||||
name = "Squeak (Mouse)"
|
||||
desc = "Squeak like a mouse."
|
||||
bindings = list(
|
||||
"squeak",
|
||||
"mouse-squeak",
|
||||
)
|
||||
feedback_special_miming = "<b>%%USER%%</b> acts out a soft squeak."
|
||||
feedback_default = "<b>%%USER%%</b> squeaks!"
|
||||
feedback_default_audible = "You hear a squeak."
|
||||
sfx = 'sound/effects/mouse_squeak.ogg'
|
||||
sfx_volume = 50
|
||||
110
code/datums/emote/types/standard/basic/general.dm
Normal file
110
code/datums/emote/types/standard/basic/general.dm
Normal file
@@ -0,0 +1,110 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/general
|
||||
abstract_type = /datum/emote/standard/basic/general
|
||||
|
||||
/datum/emote/standard/basic/general/bow
|
||||
name = "Bow"
|
||||
desc = "Bow, or bow to someone."
|
||||
bindings = "bow"
|
||||
required_mobility_flags = MOBILITY_CAN_STAND
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> bows."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> bows to %%TARGET%%."
|
||||
target_allowed = TRUE
|
||||
|
||||
// todo: you need a face to do this
|
||||
/datum/emote/standard/basic/general/blush
|
||||
name = "Blush"
|
||||
desc = "Blush, or blush at someone."
|
||||
bindings = "blush"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> blushes."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> blushes at %%TARGET%%."
|
||||
target_allowed = TRUE
|
||||
|
||||
// todo: you need a face to do this
|
||||
/datum/emote/standard/basic/general/frown
|
||||
name = "Frown"
|
||||
desc = "Frown, or frown at someone."
|
||||
bindings = "frown"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> frowns."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> frowns at %%TARGET%%."
|
||||
target_allowed = TRUE
|
||||
|
||||
// todo: you need a head to do this
|
||||
/datum/emote/standard/basic/general/nod
|
||||
name = "Nod"
|
||||
desc = "Nod, or nod at someone."
|
||||
bindings = "nod"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> nods."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> nods at %%TARGET%%."
|
||||
target_allowed = TRUE
|
||||
|
||||
/datum/emote/standard/basic/general/raise_hand
|
||||
name = "Raise Hand"
|
||||
desc = "Raise your hand."
|
||||
bindings = "raise"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> raises a hand."
|
||||
emote_require = EMOTE_REQUIRE_FREE_HAND
|
||||
|
||||
/datum/emote/standard/basic/general/shiver
|
||||
name = "Shiver"
|
||||
desc = "Shiver."
|
||||
bindings = "shiver"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> shivers."
|
||||
|
||||
/datum/emote/standard/basic/general/shrug
|
||||
name = "Shrug"
|
||||
desc = "Shrug, or shrug at someone."
|
||||
bindings = "shrug"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> shrugs."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> shrugs at %%TARGET%%."
|
||||
target_allowed = TRUE
|
||||
|
||||
// todo: check has mouth
|
||||
/datum/emote/standard/basic/general/smile
|
||||
name = "Smile"
|
||||
desc = "Smile, or smile at someone."
|
||||
bindings = "smile"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> smiles."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> smiles at %%TARGET%%."
|
||||
target_allowed = TRUE
|
||||
|
||||
// todo: check has mouth
|
||||
/datum/emote/standard/basic/general/smooch
|
||||
name = "Smooch"
|
||||
desc = "Smooch someone standing next to you."
|
||||
bindings = "smooch"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
target_allowed = TRUE
|
||||
target_required = TRUE
|
||||
target_range = 1
|
||||
feedback_default_targeted = "<b>%%USER%%</b> smooches %%TARGET%%."
|
||||
|
||||
/datum/emote/standard/basic/general/wave
|
||||
name = "Wave"
|
||||
desc = "Wave, or wave at someone."
|
||||
bindings = "wave"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> waves."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> waves at %%TARGET%%."
|
||||
target_allowed = TRUE
|
||||
emote_require = EMOTE_REQUIRE_FREE_HAND
|
||||
|
||||
// todo: check has eyes
|
||||
/datum/emote/standard/basic/general/wink
|
||||
name = "Wink"
|
||||
desc = "Wink at someone."
|
||||
bindings = "wink"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> winks."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> winks at %TARGET."
|
||||
target_allowed = TRUE
|
||||
21
code/datums/emote/types/standard/basic/general/blink.dm
Normal file
21
code/datums/emote/types/standard/basic/general/blink.dm
Normal file
@@ -0,0 +1,21 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
// todo: check has eyes
|
||||
/datum/emote/standard/basic/general/blink
|
||||
name = "Blink"
|
||||
desc = "Blink your eyes."
|
||||
bindings = "blink"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> blinks."
|
||||
|
||||
// todo: check has eyes
|
||||
/datum/emote/standard/basic/general/blink_fast
|
||||
name = "Blink Rapidly"
|
||||
desc = "Rapidly blink your eyes."
|
||||
bindings = list(
|
||||
"blink_r",
|
||||
"blink-fast",
|
||||
)
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> blinks rapidly."
|
||||
34
code/datums/emote/types/standard/basic/general/clap.dm
Normal file
34
code/datums/emote/types/standard/basic/general/clap.dm
Normal file
@@ -0,0 +1,34 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/general/clap
|
||||
name = "Clap"
|
||||
desc = "Clap."
|
||||
bindings = "clap"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
sfx = list(
|
||||
'sound/misc/clapping.ogg',
|
||||
'sound/voice/clap2.ogg',
|
||||
'sound/voice/clap3.ogg',
|
||||
'sound/voice/clap4.ogg',
|
||||
)
|
||||
sfx_volume = 75
|
||||
feedback_default = "<b>%%USER%%</b> claps."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> claps for %%TARGET%%."
|
||||
feedback_default_audible = "You hear clapping."
|
||||
target_allowed = TRUE
|
||||
|
||||
/datum/emote/standard/basic/general/golfclap
|
||||
name = "Clap Slowly"
|
||||
desc = "Clap slowly, perhaps sarcastically."
|
||||
bindings = list(
|
||||
"golfclap",
|
||||
"clap-slow",
|
||||
)
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
sfx = 'sound/voice/golfclap.ogg'
|
||||
sfx_volume = 75
|
||||
feedback_default = "<b>%%USER%%</b> slowly claps."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> slowly claps for %%TARGET%%."
|
||||
feedback_default_audible = "You hear sarcastic clapping."
|
||||
target_allowed = TRUE
|
||||
40
code/datums/emote/types/standard/basic/general/cough.dm
Normal file
40
code/datums/emote/types/standard/basic/general/cough.dm
Normal file
@@ -0,0 +1,40 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/general/cough
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
name = "Cough"
|
||||
desc = "Cough."
|
||||
bindings = "cough"
|
||||
emote_require = EMOTE_REQUIRE_VOCALIZATION
|
||||
feedback_default = "<b>%%USER%%</b> coughs."
|
||||
feedback_default_audible = "You hear a cough."
|
||||
feedback_special_miming = "<b>%%USER%%</b> appears to cough."
|
||||
feedback_special_muzzled = "<b>%%USER%%</b> makes a strong noise."
|
||||
feedback_special_muzzled_audible = "You hear a strong noise."
|
||||
|
||||
/datum/emote/standard/basic/general/cough/get_sfx(datum/event_args/actor/actor, list/arbitrary)
|
||||
var/robotic = FALSE
|
||||
var/mob/casted_mob = actor.performer
|
||||
if(iscarbon(casted_mob))
|
||||
var/mob/living/carbon/casted_carbon = casted_mob
|
||||
var/obj/item/organ/internal/maybe_lungs = casted_carbon.organs_by_name[O_LUNGS]
|
||||
if(maybe_lungs.robotic >= ORGAN_ROBOT)
|
||||
robotic = TRUE
|
||||
else
|
||||
if(casted_mob.isSynthetic())
|
||||
robotic = TRUE
|
||||
// yes another check because this will be modularized out later to a gender/robotic lookup,
|
||||
// then a sound lookup.
|
||||
if(iscarbon(casted_mob))
|
||||
var/mob/living/carbon/casted_carbon = casted_mob
|
||||
if(robotic)
|
||||
if(casted_carbon.get_gender() == FEMALE)
|
||||
return 'sound/effects/mob_effects/m_machine_cougha.ogg'
|
||||
else
|
||||
return 'sound/effects/mob_effects/f_machine_cougha.ogg'
|
||||
else
|
||||
if(casted_carbon.get_gender() == FEMALE)
|
||||
return casted_carbon.species?.female_cough_sounds
|
||||
else
|
||||
return casted_carbon.species?.male_cough_sounds
|
||||
13
code/datums/emote/types/standard/basic/general/salute.dm
Normal file
13
code/datums/emote/types/standard/basic/general/salute.dm
Normal file
@@ -0,0 +1,13 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/general/salute
|
||||
name = "Salute"
|
||||
desc = "Salute at someone."
|
||||
bindings = "salute"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
sfx = 'sound/misc/salute.ogg'
|
||||
sfx_volume = 60
|
||||
target_allowed = TRUE
|
||||
feedback_default = "<b>%%USER%%</b> salutes."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> salutes to %%TARGET%%."
|
||||
40
code/datums/emote/types/standard/basic/general/sneeze.dm
Normal file
40
code/datums/emote/types/standard/basic/general/sneeze.dm
Normal file
@@ -0,0 +1,40 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/general/sneeze
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
name = "Sneeze"
|
||||
desc = "Sneeze."
|
||||
bindings = "sneeze"
|
||||
emote_require = EMOTE_REQUIRE_VOCALIZATION
|
||||
feedback_default = "<b>%%USER%%</b> sneezes."
|
||||
feedback_default_audible = "You hear a sneeze."
|
||||
feedback_special_miming = "<b>%%USER%%</b> appears to sneeze."
|
||||
feedback_special_muzzled = "<b>%%USER%%</b> makes a strange noise."
|
||||
feedback_special_muzzled_audible = "You hear a strange noise."
|
||||
|
||||
/datum/emote/standard/basic/general/sneeze/get_sfx(datum/event_args/actor/actor, list/arbitrary)
|
||||
var/robotic = FALSE
|
||||
var/mob/casted_mob = actor.performer
|
||||
if(iscarbon(casted_mob))
|
||||
var/mob/living/carbon/casted_carbon = casted_mob
|
||||
var/obj/item/organ/internal/maybe_lungs = casted_carbon.organs_by_name[O_LUNGS]
|
||||
if(maybe_lungs.robotic >= ORGAN_ROBOT)
|
||||
robotic = TRUE
|
||||
else
|
||||
if(casted_mob.isSynthetic())
|
||||
robotic = TRUE
|
||||
// yes another check because this will be modularized out later to a gender/robotic lookup,
|
||||
// then a sound lookup.
|
||||
if(iscarbon(casted_mob))
|
||||
var/mob/living/carbon/casted_carbon = casted_mob
|
||||
if(robotic)
|
||||
if(casted_carbon.get_gender() == FEMALE)
|
||||
return 'sound/effects/mob_effects/machine_sneeze.ogg'
|
||||
else
|
||||
return 'sound/effects/mob_effects/f_machine_sneeze.ogg'
|
||||
else
|
||||
if(casted_carbon.get_gender() == FEMALE)
|
||||
return casted_carbon.species?.female_sneeze_sound
|
||||
else
|
||||
return casted_carbon.species?.male_sneeze_sound
|
||||
21
code/datums/emote/types/standard/basic/general/twitch.dm
Normal file
21
code/datums/emote/types/standard/basic/general/twitch.dm
Normal file
@@ -0,0 +1,21 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/general/twitch
|
||||
name = "Twitch"
|
||||
desc = "Twitch."
|
||||
bindings = "twitch"
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> twitches."
|
||||
feedback_saycode_type = SAYCODE_TYPE_VISIBLE
|
||||
|
||||
/datum/emote/standard/basic/general/twitch/strong
|
||||
name = "Twitch Violently"
|
||||
desc = "Violently twitch."
|
||||
bindings = list(
|
||||
"twitch_v",
|
||||
"twitch-violently",
|
||||
)
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
feedback_default = "<b>%%USER%%</b> twitches violently."
|
||||
feedback_saycode_type = SAYCODE_TYPE_VISIBLE
|
||||
111
code/datums/emote/types/standard/basic/machine_noise.dm
Normal file
111
code/datums/emote/types/standard/basic/machine_noise.dm
Normal file
@@ -0,0 +1,111 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/machine_noise
|
||||
abstract_type = /datum/emote/standard/basic/machine_noise
|
||||
emote_require = EMOTE_REQUIRE_SYNTHETIC_SPEAKER
|
||||
target_allowed = TRUE
|
||||
// TODO: parameter to enable this / set frequency
|
||||
sfx_vary = FALSE
|
||||
|
||||
/datum/emote/standard/basic/machine_noise/beep
|
||||
name = "Machine - Beep"
|
||||
desc = "Emit a beep."
|
||||
bindings = list(
|
||||
"beep",
|
||||
"synth-beep",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> beeps."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> beeps at %%TARGET%%."
|
||||
sfx = 'sound/machines/twobeep.ogg'
|
||||
|
||||
// todo: name, targeted
|
||||
/datum/emote/standard/basic/machine_noise/buzz
|
||||
bindings = list(
|
||||
"buzz",
|
||||
"synth-buzz",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> buzzes."
|
||||
sfx = 'sound/machines/buzz-sigh.ogg'
|
||||
|
||||
// todo: name, targeted
|
||||
/datum/emote/standard/basic/machine_noise/buzz2
|
||||
bindings = list(
|
||||
"buzz2",
|
||||
"synth-buzz2",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> buzzes twice."
|
||||
sfx = 'sound/machines/buzz-two.ogg'
|
||||
|
||||
// todo: name, targeted
|
||||
/datum/emote/standard/basic/machine_noise/chime
|
||||
bindings = list(
|
||||
"chime",
|
||||
"synth-chime",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> chimes."
|
||||
sfx = 'sound/machines/chime.ogg'
|
||||
|
||||
// todo: name, targeted
|
||||
/datum/emote/standard/basic/machine_noise/dwoop
|
||||
bindings = list(
|
||||
"dwoop",
|
||||
"synth-dwoop",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> chirps happily."
|
||||
sfx = 'sound/machines/dwoop.ogg'
|
||||
|
||||
// todo: name, targeted
|
||||
/datum/emote/standard/basic/machine_noise/warn
|
||||
bindings = list(
|
||||
"warn",
|
||||
"synth-warn",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> blares an alarm."
|
||||
sfx = 'sound/machines/warning-buzzer.ogg'
|
||||
|
||||
// todo: name, targeted
|
||||
/datum/emote/standard/basic/machine_noise/ping
|
||||
bindings = list(
|
||||
"ping",
|
||||
"synth-ping",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> pings."
|
||||
sfx = 'sound/machines/ping.ogg'
|
||||
|
||||
// todo: name, targeted
|
||||
/datum/emote/standard/basic/machine_noise/yes
|
||||
bindings = list(
|
||||
"yes",
|
||||
"synth-yes",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> emits an affirmative blip."
|
||||
sfx = 'sound/machines/synth_yes.ogg'
|
||||
|
||||
// todo: name, targeted
|
||||
/datum/emote/standard/basic/machine_noise/no
|
||||
bindings = list(
|
||||
"no",
|
||||
"synth-no",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> emits a negative blip."
|
||||
sfx = 'sound/machines/synth_no.ogg'
|
||||
|
||||
// todo: name, targeted
|
||||
/datum/emote/standard/basic/machine_noise/scary
|
||||
bindings = list(
|
||||
"scary",
|
||||
"synth-scary",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> emits a disconcerting tone."
|
||||
sfx = 'sound/machines/synth_scary.ogg'
|
||||
|
||||
// todo: name, targeted
|
||||
/datum/emote/standard/basic/machine_noise/steam
|
||||
bindings = list(
|
||||
"steam",
|
||||
"synth-steam",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> lets off some steam."
|
||||
sfx = 'sound/machines/clockcult/steam_whoosh.ogg'
|
||||
sfx_volume = 30
|
||||
37
code/datums/emote/types/standard/basic/species.dm
Normal file
37
code/datums/emote/types/standard/basic/species.dm
Normal file
@@ -0,0 +1,37 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/species
|
||||
abstract_type = /datum/emote/standard/basic/species
|
||||
emote_class = EMOTE_CLASS_IS_HUMANOID
|
||||
/// required species id or list of ids
|
||||
///
|
||||
/// * these are ids, not uids.
|
||||
var/required_species_id
|
||||
|
||||
/datum/emote/standard/basic/species/can_potentially_use(datum/event_args/actor/actor, use_emote_class)
|
||||
if(!check_species(actor.performer))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/emote/standard/basic/species/can_use_special(datum/event_args/actor/actor, list/arbitrary, list/out_reasons_fail)
|
||||
if(!required_species_id)
|
||||
return ..()
|
||||
if(!actor?.performer)
|
||||
return ..()
|
||||
if(!check_species(actor.performer))
|
||||
out_reasons_fail?.Add("incorrect species")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/emote/standard/basic/species/proc/check_species(mob/actor)
|
||||
var/mob/living/carbon/human/human = actor
|
||||
if(!istype(human))
|
||||
return FALSE
|
||||
if(islist(required_species_id))
|
||||
if(!(human.species.id in required_species_id))
|
||||
return FALSE
|
||||
else
|
||||
if(!(human.species.id == required_species_id))
|
||||
return FALSE
|
||||
return TRUE
|
||||
15
code/datums/emote/types/standard/basic/species/adherent.dm
Normal file
15
code/datums/emote/types/standard/basic/species/adherent.dm
Normal file
@@ -0,0 +1,15 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/species/adherent
|
||||
abstract_type = /datum/emote/standard/basic/species/adherent
|
||||
required_species_id = /datum/species/adherent::id
|
||||
|
||||
/datum/emote/standard/basic/species/adherent/chime
|
||||
bindings = list(
|
||||
"achime",
|
||||
"adherent-chime",
|
||||
)
|
||||
sfx = 'sound/machines/achime.ogg'
|
||||
sfx_volume = 50
|
||||
feedback_default = "<b>%%USER%%</b> chimes!"
|
||||
21
code/datums/emote/types/standard/basic/species/promethean.dm
Normal file
21
code/datums/emote/types/standard/basic/species/promethean.dm
Normal file
@@ -0,0 +1,21 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/species/promethean
|
||||
abstract_type = /datum/emote/standard/basic/species/promethean
|
||||
required_species_id = /datum/species/shapeshifter/promethean::id
|
||||
|
||||
/datum/emote/standard/basic/species/promethean/check_species(mob/actor)
|
||||
if(istype(actor, /mob/living/simple_mob/slime))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/datum/emote/standard/basic/species/promethean/squish
|
||||
bindings = list(
|
||||
"squish",
|
||||
"slime-squish",
|
||||
)
|
||||
feedback_saycode_type = SAYCODE_TYPE_VISIBLE
|
||||
feedback_default = "<b>%%USER%%</b> squishes."
|
||||
sfx = 'sound/effects/slime_squish.ogg'
|
||||
sfx_volume = 50
|
||||
26
code/datums/emote/types/standard/basic/species/vox.dm
Normal file
26
code/datums/emote/types/standard/basic/species/vox.dm
Normal file
@@ -0,0 +1,26 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/species/vox
|
||||
abstract_type = /datum/emote/standard/basic/species/vox
|
||||
required_species_id = /datum/species/vox::id
|
||||
|
||||
/datum/emote/standard/basic/species/vox/shriek_loud
|
||||
bindings = list(
|
||||
"shriekloud",
|
||||
"vox-shriek-loud",
|
||||
)
|
||||
sfx = 'sound/voice/shrieksneeze.ogg'
|
||||
sfx_volume = 50
|
||||
feedback_default = "<b>%%USER%%</b> gives a short sharp shriek!"
|
||||
|
||||
/datum/emote/standard/basic/species/vox/shriek_quiet
|
||||
bindings = list(
|
||||
"shrieksoft",
|
||||
"vox-shriek-soft",
|
||||
)
|
||||
sfx = 'sound/voice/shriekcough.ogg'
|
||||
sfx_volume = 50
|
||||
feedback_default = "<b>%%USER%%</b> gives a short, quieter shriek!"
|
||||
|
||||
|
||||
149
code/datums/emote/types/standard/basic/species/xenomorph.dm
Normal file
149
code/datums/emote/types/standard/basic/species/xenomorph.dm
Normal file
@@ -0,0 +1,149 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph
|
||||
abstract_type = /datum/emote/standard/basic/species/xenomorph
|
||||
required_species_id = list(
|
||||
/datum/species/xenos::id,
|
||||
/datum/species/xenohybrid::id,
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/promethean/check_species(mob/actor)
|
||||
if(istype(actor, /mob/living/simple_mob/animal/space/xenomorph))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xhiss
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/alien_hiss3.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xhiss",
|
||||
"xeno-hiss",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xroar
|
||||
feedback_default = "<b>%%USER%%</b> roars!"
|
||||
sfx = 'sound/voice/xenos/alien_roar1.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xroar",
|
||||
"xeno-roar",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xhiss2
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/xhiss2.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xhiss2",
|
||||
"xeno-hiss2",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xhiss3
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/xhiss3.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xhiss3",
|
||||
"xeno-hiss3",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xhiss4
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/xhiss4.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xhiss4",
|
||||
"xeno-hiss4",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xhiss5
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/xhiss5.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xhiss5",
|
||||
"xeno-hiss5",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xhiss6
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/xhiss6.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xhiss6",
|
||||
"xeno-hiss6",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xroar1
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/xroar1.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xroar1",
|
||||
"xeno-roar1",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xroar2
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/xroar2.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xroar2",
|
||||
"xeno-roar2",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xroar3
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/xroar3.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xroar3",
|
||||
"xeno-roar3",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xtalk1
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/xtalk1.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xtalk1",
|
||||
"xeno-talk1",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xtalk2
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/xtalk2.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xtalk2",
|
||||
"xeno-talk2",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xtalk3
|
||||
feedback_default = "<b>%%USER%%</b> hisses!"
|
||||
sfx = 'sound/voice/xenos/xtalk3.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xtalk3",
|
||||
"xeno-talk3",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xroar
|
||||
feedback_default = "<b>%%USER%%</b> roars!"
|
||||
sfx = 'sound/voice/xenos/alien_roar1.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xroar",
|
||||
"xeno-roar",
|
||||
)
|
||||
|
||||
/datum/emote/standard/basic/species/xenomorph/xgrowl
|
||||
feedback_default = "<b>%%USER%%</b> growls!"
|
||||
sfx = 'sound/voice/xenos/alien_growl1.ogg'
|
||||
sfx_volume = 50
|
||||
bindings = list(
|
||||
"xgrowl",
|
||||
"xeno-growl",
|
||||
)
|
||||
62
code/datums/emote/types/standard/basic/synth_sfx.dm
Normal file
62
code/datums/emote/types/standard/basic/synth_sfx.dm
Normal file
@@ -0,0 +1,62 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/datum/emote/standard/basic/synth_sfx
|
||||
abstract_type = /datum/emote/standard/basic/synth_sfx
|
||||
|
||||
emote_require = EMOTE_REQUIRE_SYNTHETIC_SPEAKER
|
||||
required_mobility_flags = MOBILITY_IS_CONSCIOUS
|
||||
// TODO: parameter to enable this / set frequency
|
||||
sfx_vary = FALSE
|
||||
|
||||
/datum/emote/standard/basic/synth_sfx/honk
|
||||
name = "Machine - Bike Horn"
|
||||
desc = "Emit a bike horn's honk."
|
||||
bindings = list(
|
||||
"honk",
|
||||
"synth-honk",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> honks."
|
||||
feedback_default_targeted = "<b>%%USER%%</b> honks at %%TARGET%%."
|
||||
sfx = 'sound/items/bikehorn.ogg'
|
||||
target_allowed = TRUE
|
||||
|
||||
// todo; name
|
||||
/datum/emote/standard/basic/synth_sfx/gameover
|
||||
name = "Machine - Game Over"
|
||||
bindings = list(
|
||||
"gameover",
|
||||
"synth-gameover",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> crumples, their chassis colder and more lifeless than usual."
|
||||
sfx = 'sound/machines/synth_gameover.ogg'
|
||||
|
||||
// todo; name
|
||||
/datum/emote/standard/basic/synth_sfx/xp_startup
|
||||
name = "Machine - Startup (XP)"
|
||||
bindings = list(
|
||||
"startup",
|
||||
"synth-startup",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> chimes to life."
|
||||
sfx = 'sound/machines/synth_startup.ogg'
|
||||
|
||||
// todo; name
|
||||
/datum/emote/standard/basic/synth_sfx/xp_shutdown
|
||||
name = "Machine - Shutdown (XP)"
|
||||
bindings = list(
|
||||
"shutdown",
|
||||
"synth-shutdown",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> emits a nostalgic tone as they fall silent."
|
||||
sfx = 'sound/machines/synth_shutdown.ogg'
|
||||
|
||||
// todo; name, targeting
|
||||
/datum/emote/standard/basic/synth_sfx/xp_error
|
||||
name = "Machine - Error (XP)"
|
||||
bindings = list(
|
||||
"error",
|
||||
"synth-error",
|
||||
)
|
||||
feedback_default = "<b>%%USER%%</b> experiences a system error."
|
||||
sfx = 'sound/machines/synth_error.ogg'
|
||||
@@ -1,3 +1,6 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
/datum/soundbyte/clicker
|
||||
name = "Clicker A"
|
||||
id = "clicker-1"
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
/datum/soundbyte/explosion
|
||||
name = "Explosion A"
|
||||
id = "explosion-1"
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
/datum/soundbyte/sparks
|
||||
name = "Sparks A"
|
||||
id = "sparks-1"
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
/datum/soundbyte/spray
|
||||
abstract_type = /datum/soundbyte/spray
|
||||
is_sfx = TRUE
|
||||
|
||||
55
code/datums/soundbytes/defs/talksound.dm
Normal file
55
code/datums/soundbytes/defs/talksound.dm
Normal file
@@ -0,0 +1,55 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
/datum/soundbyte/talksound
|
||||
abstract_type = /datum/soundbyte/talksound
|
||||
is_sfx = TRUE
|
||||
|
||||
/datum/soundbyte/talksound/goon_say
|
||||
name = "Talksound - Goon Say"
|
||||
id = "talksound-goon-say"
|
||||
path = list(
|
||||
'sound/soundbytes/talksounds/goon/speak_1.ogg',
|
||||
'sound/soundbytes/talksounds/goon/speak_2.ogg',
|
||||
'sound/soundbytes/talksounds/goon/speak_3.ogg',
|
||||
'sound/soundbytes/talksounds/goon/speak_4.ogg',
|
||||
)
|
||||
|
||||
/datum/soundbyte/talksound/goon_ask
|
||||
name = "Talksound - Goon Ask"
|
||||
id = "talksound-goon-ask"
|
||||
path = list(
|
||||
'sound/soundbytes/talksounds/goon/speak_1_ask.ogg',
|
||||
'sound/soundbytes/talksounds/goon/speak_2_ask.ogg',
|
||||
'sound/soundbytes/talksounds/goon/speak_3_ask.ogg',
|
||||
'sound/soundbytes/talksounds/goon/speak_4_ask.ogg',
|
||||
)
|
||||
|
||||
/datum/soundbyte/talksound/goon_exclaim
|
||||
name = "Talksound - Goon Exclaim"
|
||||
id = "talksound-goon-exclaim"
|
||||
path = list(
|
||||
'sound/soundbytes/talksounds/goon/speak_1_exclaim.ogg',
|
||||
'sound/soundbytes/talksounds/goon/speak_2_exclaim.ogg',
|
||||
'sound/soundbytes/talksounds/goon/speak_3_exclaim.ogg',
|
||||
'sound/soundbytes/talksounds/goon/speak_4_exclaim.ogg',
|
||||
)
|
||||
|
||||
/datum/soundbyte/talksound/generic_emote_1
|
||||
name = "Talksound - Generic Emote 1"
|
||||
id = "talksound-generic-emote-1"
|
||||
path = list(
|
||||
'sound/soundbytes/talksounds/generic/me_a.ogg',
|
||||
'sound/soundbytes/talksounds/generic/me_b.ogg',
|
||||
'sound/soundbytes/talksounds/generic/me_c.ogg',
|
||||
'sound/soundbytes/talksounds/generic/me_d.ogg',
|
||||
'sound/soundbytes/talksounds/generic/me_e.ogg',
|
||||
'sound/soundbytes/talksounds/generic/me_f.ogg',
|
||||
)
|
||||
|
||||
/datum/soundbyte/talksound/generic_subtle_emote_1
|
||||
name = "Talksound - Generic Subtle Emote 1"
|
||||
id = "talksound-generic-subtle-emote-1"
|
||||
path = list(
|
||||
'sound/soundbytes/talksounds/generic/subtle_sound.ogg',
|
||||
)
|
||||
@@ -1,3 +1,6 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
/datum/soundbyte/terminal_keyboard
|
||||
name = "Terminal Click"
|
||||
id = "terminal-1"
|
||||
|
||||
@@ -24,13 +24,17 @@
|
||||
INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, animate_chat), message, null, FALSE, speech_bubble_hearers, 3 SECONDS)
|
||||
|
||||
/atom/proc/say_overhead(var/message, whispering, message_range = 7, var/datum/prototype/language/speaking = null, var/list/passed_hearing_list)
|
||||
var/list/speech_bubble_hearers = list()
|
||||
var/italics
|
||||
if(whispering)
|
||||
italics = TRUE
|
||||
for(var/mob/M in get_mobs_in_view(message_range, src))
|
||||
if(M.client)
|
||||
speech_bubble_hearers += M.client
|
||||
var/list/speech_bubble_hearers
|
||||
if(passed_hearing_list)
|
||||
speech_bubble_hearers = passed_hearing_list
|
||||
else
|
||||
speech_bubble_hearers = list()
|
||||
for(var/mob/M in get_mobs_in_view(message_range, src))
|
||||
if(M.client)
|
||||
speech_bubble_hearers += M.client
|
||||
if(length(speech_bubble_hearers))
|
||||
INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, animate_chat), message, speaking, italics, speech_bubble_hearers, 30)
|
||||
|
||||
|
||||
@@ -24,23 +24,23 @@
|
||||
/// * automatic message emit will not happen if this isn't set, even if self/audible are.
|
||||
///
|
||||
/// accepted vars:
|
||||
/// * "$ATTACKER" - the person attacking
|
||||
/// * "$ATTACKER_P_THEIR" - pronoun for 'their' for attacker
|
||||
/// * "$TARGET" - the target
|
||||
/// * "%%ATTACKER%%" - the person attacking
|
||||
/// * "%%ATTACKER_P_THEIR%%" - pronoun for 'their' for attacker
|
||||
/// * "%%TARGET%%" - the target
|
||||
var/default_feedback_message
|
||||
/// templateable message
|
||||
///
|
||||
/// accepted vars:
|
||||
/// * "$ATTACKER" - the person attacking
|
||||
/// * "$ATTACKER_P_THEIR" - pronoun for 'their' for attacker
|
||||
/// * "$TARGET" - the target
|
||||
/// * "%%ATTACKER%%" - the person attacking
|
||||
/// * "%%ATTACKER_P_THEIR%%" - pronoun for 'their' for attacker
|
||||
/// * "%%TARGET%%" - the target
|
||||
var/default_feedback_message_self
|
||||
/// templateable message
|
||||
///
|
||||
/// accepted vars:
|
||||
/// * "$ATTACKER" - the person attacking
|
||||
/// * "$ATTACKER_P_THEIR" - pronoun for 'their' for attacker
|
||||
/// * "$TARGET" - the target
|
||||
/// * "%%ATTACKER%%" - the person attacking
|
||||
/// * "%%ATTACKER_P_THEIR%%" - pronoun for 'their' for attacker
|
||||
/// * "%%TARGET%%" - the target
|
||||
var/default_feedback_message_audible
|
||||
|
||||
/datum/combo/melee/New()
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
else
|
||||
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a>"
|
||||
|
||||
else if ((maybe_bitfield = fetch_bitfield(D?.type, name)))
|
||||
else if (istype(D) && (maybe_bitfield = fetch_bitfield(D.type, name)))
|
||||
var/list/flags = list()
|
||||
for(var/i in 1 to maybe_bitfield.get_declared_count())
|
||||
var/bit = maybe_bitfield.bits[i]
|
||||
|
||||
@@ -302,7 +302,7 @@ datumrefresh=[refid];[HrefToken()]'>Refresh</a>
|
||||
</body>
|
||||
</html>
|
||||
"}
|
||||
src << browse(html, "window=variables[refid];size=475x650")
|
||||
src << browse(html, "window=variables[refid];size=525x725")
|
||||
|
||||
/client/proc/vv_update_display(datum/D, span, content)
|
||||
src << output("[span]:[content]", "variables[REF(D)].browser:replace_span")
|
||||
|
||||
@@ -106,6 +106,11 @@
|
||||
key = "mob_tooltips"
|
||||
legacy_key = "MOB_TOOLTIPS"
|
||||
|
||||
/datum/game_preference_toggle/game/vocal_cues
|
||||
name = "Vocal Cues on Chat"
|
||||
key = "vocal_cues"
|
||||
description = "Enables playing a sound on hearing someone speak / act."
|
||||
|
||||
/datum/game_preference_toggle/game/overhead_chat
|
||||
name = "Overhead Chat"
|
||||
key = "runechat"
|
||||
|
||||
@@ -53,6 +53,9 @@ GLOBAL_VAR_INIT(game_view_y, 15)
|
||||
// minimum size viewports can be
|
||||
GLOBAL_VAR_INIT(min_client_view_x, 15)
|
||||
GLOBAL_VAR_INIT(min_client_view_y, 15)
|
||||
// the radius that things like saycode operates on
|
||||
// todo: update this as needed
|
||||
GLOBAL_VAR_INIT(game_view_radius, 9)
|
||||
// these two variables, if set, lock all clients to a certain viewsize no matter what
|
||||
GLOBAL_VAR(lock_client_view_x)
|
||||
GLOBAL_VAR(lock_client_view_y)
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
description = "Does a subtle emote that's invisible to ghosts."
|
||||
|
||||
/datum/keybinding/mob/subtler/down(client/user)
|
||||
user.mob.subtler_wrapper()
|
||||
user.mob.subtle_wrapper()
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/mob/drop_item
|
||||
|
||||
@@ -31,7 +31,7 @@ GLOBAL_DATUM_INIT(kinetic_gauntlet_melee_combo, /datum/combo_set/melee, new /dat
|
||||
INTENT_DISARM,
|
||||
INTENT_HARM,
|
||||
)
|
||||
default_feedback_message = SPAN_DANGER_CONST("$ATTACKER rapidly strikes $TARGET and sends them flying!")
|
||||
default_feedback_message = SPAN_DANGER_CONST("%%ATTACKER%% rapidly strikes %%TARGET%% and sends them flying!")
|
||||
damage_force = 36
|
||||
|
||||
/datum/combo/melee/intent_based/kinetic_gauntlets/slam/inflict_on(atom/target, target_zone, mob/attacker, datum/event_args/actor/clickchain/clickchain)
|
||||
@@ -65,7 +65,7 @@ GLOBAL_DATUM_INIT(kinetic_gauntlet_melee_combo, /datum/combo_set/melee, new /dat
|
||||
|
||||
damage_force = 36
|
||||
default_feedback_sfx = 'sound/weapons/resonator_blast.ogg'
|
||||
default_feedback_message = SPAN_DANGER_CONST("$ATTACKER places three precision strikes $TARGET, causing their destabilization field to collapse into a concussive blast!")
|
||||
default_feedback_message = SPAN_DANGER_CONST("%%ATTACKER%% places three precision strikes %%TARGET%%, causing their destabilization field to collapse into a concussive blast!")
|
||||
|
||||
/datum/combo/melee/intent_based/kinetic_gauntlets/concuss/inflict_on(atom/target, target_zone, mob/attacker, datum/event_args/actor/clickchain/clickchain)
|
||||
. = ..()
|
||||
@@ -89,4 +89,4 @@ GLOBAL_DATUM_INIT(kinetic_gauntlet_melee_combo, /datum/combo_set/melee, new /dat
|
||||
)
|
||||
|
||||
damage_force = 72
|
||||
default_feedback_message = SPAN_DANGER_CONST("$ATTACKER slams $ATTACKER_P_THEIR gauntlet into $TARGET, violently detonating their destabilization field!")
|
||||
default_feedback_message = SPAN_DANGER_CONST("%%ATTACKER%% slams %%ATTACKER_P_THEIR%% gauntlet into %%TARGET%%, violently detonating their destabilization field!")
|
||||
|
||||
@@ -1,99 +1,38 @@
|
||||
// All mobs should have custom emote, really..
|
||||
//m_type == 1 --> visual.
|
||||
//m_type == 2 --> audible
|
||||
/mob/proc/custom_emote(var/m_type=1,var/message = null,var/range=world.view)
|
||||
if(stat || !use_me && usr == src)
|
||||
to_chat(src, "You are unable to emote.")
|
||||
return
|
||||
|
||||
var/muzzled = is_muzzled()
|
||||
if(m_type == 2 && muzzled)
|
||||
return
|
||||
/**
|
||||
* Legacy below
|
||||
*/
|
||||
|
||||
var/input
|
||||
if(!message)
|
||||
input = sanitize_or_reflect(input(src,"Choose an emote to display.") as text|null, src) // Reflect too long messages, within reason.
|
||||
/mob/proc/emote(var/act, var/type, var/message)
|
||||
act = trim(act)
|
||||
var/spacer = findtext_char(act, " ")
|
||||
var/raw_key
|
||||
var/raw_params
|
||||
if(spacer != 0)
|
||||
raw_key = copytext_char(act, 1, spacer)
|
||||
raw_params = copytext_char(act, spacer + 1)
|
||||
else
|
||||
input = message
|
||||
if(input)
|
||||
log_emote(message,src) //Log before we add junk
|
||||
//If the message starts with a comma or apostrophe, no space after the name.
|
||||
//We have to account for sanitization so we take the whole first word to see if it's a character code.
|
||||
var/nospace = GLOB.valid_starting_punctuation.Find(input)
|
||||
message = "<span class='emote'><B>[src]</B>[nospace ? "" : " "][input]</span>"
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
if (message)
|
||||
message = say_emphasis(message)
|
||||
var/overhead_message = ("** [message] **")
|
||||
say_overhead(overhead_message, FALSE, range)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_CUSTOM_EMOTE, src, message)
|
||||
|
||||
// Hearing gasp and such every five seconds is not good emotes were not global for a reason.
|
||||
// Maybe some people are okay with that.
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T) return
|
||||
var/list/in_range = get_mobs_and_objs_in_view_fast(T,range,2,remote_ghosts = client ? TRUE : FALSE)
|
||||
var/list/m_viewers = in_range["mobs"]
|
||||
var/list/o_viewers = in_range["objs"]
|
||||
|
||||
for(var/mob in m_viewers)
|
||||
var/mob/M = mob
|
||||
spawn(0) // It's possible that it could be deleted in the meantime, or that it runtimes.
|
||||
if(M)
|
||||
if(istype(M, /mob/observer/dead/))
|
||||
var/mob/observer/dead/D = M
|
||||
if(ckey || (src in view(D)))
|
||||
M.show_message(message, m_type)
|
||||
else
|
||||
M.show_message(message, m_type)
|
||||
|
||||
for(var/obj in o_viewers)
|
||||
var/obj/O = obj
|
||||
spawn(0)
|
||||
if(O)
|
||||
O.see_emote(src, message, m_type)
|
||||
|
||||
// Shortcuts for above proc
|
||||
/mob/proc/visible_emote(var/act_desc)
|
||||
custom_emote(1, act_desc)
|
||||
|
||||
/mob/proc/audible_emote(var/act_desc)
|
||||
custom_emote(2, act_desc)
|
||||
|
||||
/mob/proc/emote_dead(var/message)
|
||||
|
||||
if(client.prefs.muted & MUTE_DEADCHAT)
|
||||
to_chat(src, "<span class='danger'>You cannot send deadchat emotes (muted).</span>")
|
||||
return
|
||||
|
||||
if(!get_preference_toggle(/datum/game_preference_toggle/chat/dsay))
|
||||
to_chat(src, "<span class='danger'>You have deadchat muted.</span>")
|
||||
return
|
||||
|
||||
if(!src.client.holder)
|
||||
if(!config_legacy.dsay_allowed)
|
||||
to_chat(src, "<span class='danger'>Deadchat is globally muted.</span>")
|
||||
raw_key = act
|
||||
raw_params = ""
|
||||
var/results = invoke_emote(raw_key, raw_params, new /datum/event_args/actor(src))
|
||||
switch(results)
|
||||
if(EMOTE_INVOKE_INVALID)
|
||||
return
|
||||
|
||||
if(SSbans.t_is_role_banned_ckey(ckey, role = BAN_ROLE_OOC))
|
||||
to_chat(src, SPAN_WARNING("You are banned from OOC and deadchat."))
|
||||
return
|
||||
|
||||
var/input
|
||||
if(!message)
|
||||
input = sanitize_or_reflect(input(src, "Choose an emote to display.") as text|null, src) // Reflect too long messages, within reason
|
||||
else
|
||||
input = message
|
||||
|
||||
input = emoji_parse(say_emphasis(input))
|
||||
|
||||
if(input)
|
||||
log_ghostemote(input, src)
|
||||
if(!invisibility) //If the ghost is made visible by admins or cult. And to see if the ghost has toggled its own visibility, as well. -Mech
|
||||
visible_message(SPAN_DEADSAY("<B>[src]</B> [input]"))
|
||||
else
|
||||
say_dead_direct(input, src)
|
||||
return "stop"
|
||||
|
||||
/// Deprecated.
|
||||
/mob/proc/visible_emote(var/act_desc)
|
||||
run_custom_emote(act_desc, saycode_type = SAYCODE_TYPE_VISIBLE)
|
||||
|
||||
/// Deprecated.
|
||||
/mob/proc/audible_emote(var/act_desc)
|
||||
run_custom_emote(act_desc, saycode_type = SAYCODE_TYPE_AUDIBLE)
|
||||
|
||||
/// Deprecated
|
||||
/mob/proc/custom_emote(m_type, message)
|
||||
switch(m_type)
|
||||
if(2)
|
||||
audible_emote(message)
|
||||
else
|
||||
visible_emote(message)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/mob/living/carbon/alien/emote(var/act,var/m_type=1,var/message = null)
|
||||
|
||||
. = ..()
|
||||
if(. == "stop")
|
||||
return
|
||||
var/param = null
|
||||
if (findtext(act, "-", 1, null))
|
||||
var/t1 = findtext(act, "-", 1, null)
|
||||
@@ -11,21 +13,6 @@
|
||||
var/muzzled = is_muzzled()
|
||||
|
||||
switch(act)
|
||||
if ("me")
|
||||
if(silent)
|
||||
return
|
||||
if (src.client)
|
||||
if (client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "<font color='red'>You cannot send IC messages (muted).</font>")
|
||||
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 = "<B>The alien</B> signs[(text2num(param) ? " the number [text2num(param)]" : null)]."
|
||||
@@ -70,21 +57,12 @@
|
||||
if("nod")
|
||||
message = "<B>The [src.name]</B> nods its head."
|
||||
m_type = 1
|
||||
// if("sit")
|
||||
// message = "<B>The [src.name]</B> sits down." //Larvan can't sit down, /N
|
||||
// m_type = 1
|
||||
if("sway")
|
||||
message = "<B>The [src.name]</B> sways around dizzily."
|
||||
m_type = 1
|
||||
if("sulk")
|
||||
message = "<B>The [src.name]</B> sulks down sadly."
|
||||
m_type = 1
|
||||
if("twitch")
|
||||
message = "<B>The [src.name]</B> twitches."
|
||||
m_type = 1
|
||||
if("twitch_v")
|
||||
message = "<B>The [src.name]</B> twitches violently."
|
||||
m_type = 1
|
||||
if("dance")
|
||||
if (!src.restrained())
|
||||
message = "<B>The [src.name]</B> dances around happily."
|
||||
@@ -103,9 +81,6 @@
|
||||
if("jump")
|
||||
message = "<B>The [src.name]</B> jumps!"
|
||||
m_type = 1
|
||||
if("hiss_")
|
||||
message = "<B>The [src.name]</B> hisses softly."
|
||||
m_type = 1
|
||||
if("collapse")
|
||||
afflict_unconscious(20 * 2)
|
||||
message = "<B>[src]</B> collapses!"
|
||||
@@ -115,7 +90,7 @@
|
||||
playsound(src.loc, 'sound/misc/nymphchirp.ogg', 50, 0)
|
||||
m_type = 2
|
||||
if("help")
|
||||
to_chat(src, "burp, chirp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, twitch, whimper")
|
||||
to_chat(src, "burp, chirp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, whimper")
|
||||
else
|
||||
to_chat(src, "Invalid Emote: [act]")
|
||||
if ((message && src.stat == 0))
|
||||
@@ -128,4 +103,3 @@
|
||||
for(var/mob/O in hearers(src, null))
|
||||
O.show_message(message, m_type)
|
||||
//Foreach goto(746)
|
||||
return
|
||||
|
||||
7
code/modules/mob/living/carbon/brain/brain-emote.dm
Normal file
7
code/modules/mob/living/carbon/brain/brain-emote.dm
Normal file
@@ -0,0 +1,7 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/mob/living/carbon/brain/get_usable_emote_require()
|
||||
. = ..()
|
||||
// if we can use emotes at all we probably can do these.
|
||||
. |= EMOTE_REQUIRE_COHERENT_SPEECH | EMOTE_REQUIRE_SYNTHETIC_SPEAKER | EMOTE_REQUIRE_VOCALIZATION
|
||||
@@ -39,10 +39,10 @@
|
||||
var/timeofhostdeath = 0
|
||||
var/emp_damage = 0//Handles a type of MMI damage
|
||||
var/alert = null
|
||||
use_me = 0 //Can't use the me verb, it's a freaking immobile brain
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
icon_state = "brain1"
|
||||
no_vore = TRUE
|
||||
emote_class = NONE
|
||||
catalogue_data = list(/datum/category_item/catalogue/fauna/brain/organic)
|
||||
|
||||
/mob/living/carbon/brain/Initialize(mapload)
|
||||
@@ -66,7 +66,6 @@
|
||||
. = ..(blocked, forced)
|
||||
else
|
||||
. = ..(MOBILITY_FLAGS_REAL, forced)
|
||||
use_me = !!(. & MOBILITY_IS_CONSCIOUS)
|
||||
|
||||
/mob/living/carbon/brain/isSynthetic()
|
||||
return istype(loc, /obj/item/mmi)
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/mob/living/carbon/brain/emote(var/act,var/m_type=1,var/message = null)
|
||||
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
|
||||
switch(act)
|
||||
if ("me")
|
||||
if(silent)
|
||||
return
|
||||
if (src.client)
|
||||
if (client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "<font color='red'>You cannot send IC messages (muted).</font>")
|
||||
return
|
||||
if (stat)
|
||||
return
|
||||
if(!(message))
|
||||
return
|
||||
return custom_emote(m_type, message)
|
||||
|
||||
if ("custom")
|
||||
return custom_emote(m_type, message)
|
||||
if ("alarm")
|
||||
to_chat(src, "You sound an alarm.")
|
||||
message = "<B>[src]</B> sounds an alarm."
|
||||
m_type = 2
|
||||
if ("alert")
|
||||
to_chat(src, "You let out a distressed noise.")
|
||||
message = "<B>[src]</B> lets out a distressed noise."
|
||||
m_type = 2
|
||||
if ("notice")
|
||||
to_chat(src, "You play a loud tone.")
|
||||
message = "<B>[src]</B> plays a loud tone."
|
||||
m_type = 2
|
||||
if ("flash")
|
||||
message = "The lights on <B>[src]</B> flash quickly."
|
||||
m_type = 1
|
||||
if ("blink")
|
||||
message = "<B>[src]</B> blinks."
|
||||
m_type = 1
|
||||
if ("whistle")
|
||||
to_chat(src, "You whistle.")
|
||||
message = "<B>[src]</B> whistles."
|
||||
m_type = 2
|
||||
if ("beep")
|
||||
to_chat(src, "You beep.")
|
||||
message = "<B>[src]</B> beeps."
|
||||
m_type = 2
|
||||
if ("boop")
|
||||
to_chat(src, "You boop.")
|
||||
message = "<B>[src]</B> boops."
|
||||
m_type = 2
|
||||
if ("help")
|
||||
to_chat(src, "alarm,alert,notice,flash,blink,whistle,beep,boop")
|
||||
else
|
||||
to_chat(src, "<font color=#4F49AF>Unusable emote '[act]'. Say *help for a list.</font>")
|
||||
|
||||
if (message)
|
||||
log_emote(message, src)
|
||||
|
||||
for(var/mob/M in dead_mob_list)
|
||||
if (!M.client || istype(M, /mob/new_player))
|
||||
continue //skip monkeys, leavers, and new_players
|
||||
if(M.stat == DEAD && M.get_preference_toggle(/datum/game_preference_toggle/observer/ghost_sight) && !(M in viewers(src,null)))
|
||||
M.show_message(message)
|
||||
|
||||
|
||||
if (m_type & 1)
|
||||
for (var/mob/O in viewers(src, null))
|
||||
O.show_message(message, m_type)
|
||||
else if (m_type & 2)
|
||||
for (var/mob/O in hearers(src.loc, null))
|
||||
O.show_message(message, m_type)
|
||||
8
code/modules/mob/living/carbon/carbon-emote.dm
Normal file
8
code/modules/mob/living/carbon/carbon-emote.dm
Normal file
@@ -0,0 +1,8 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
/mob/living/carbon/get_usable_emote_require()
|
||||
. = ..()
|
||||
var/obj/item/organ/internal/maybe_voicebox = organs_by_name[O_VOICE]
|
||||
if(maybe_voicebox?.robotic >= ORGAN_ROBOT)
|
||||
. |= EMOTE_REQUIRE_SYNTHETIC_SPEAKER
|
||||
@@ -1,6 +1,7 @@
|
||||
/mob/living/carbon
|
||||
//* Organs, Reagents, Biologies *//
|
||||
emote_class = EMOTE_CLASS_IS_BODY | EMOTE_CLASS_IS_HUMANOID
|
||||
|
||||
//* Organs, Reagents, Biologies *//
|
||||
/// Our blood holder.
|
||||
var/datum/blood_holder/blood_holder
|
||||
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
set waitfor = FALSE
|
||||
emote(arglist(args))
|
||||
|
||||
// New emotes in here are no longer allowed.
|
||||
/mob/living/carbon/human/emote(var/act,var/m_type=1,var/message = null)
|
||||
. = ..()
|
||||
if(. == "stop")
|
||||
return
|
||||
var/param = null
|
||||
var/datum/gender/T = GLOB.gender_datums[get_visible_gender()]
|
||||
if(istype(src, /mob/living/carbon/human/dummy))
|
||||
@@ -13,269 +17,20 @@
|
||||
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()
|
||||
//var/m_type = 1
|
||||
var/dangerous_pass_through_without_sanitizing = FALSE
|
||||
|
||||
for(var/obj/item/organ/O in src.organs)
|
||||
for (var/obj/item/implant/I in O)
|
||||
if (I.implanted)
|
||||
I.trigger(act, src)
|
||||
|
||||
if(src.stat == 2.0 && (act != "deathgasp"))
|
||||
if(src.stat == DEAD && (act != "deathgasp"))
|
||||
return
|
||||
if(attempt_vr(src,"handle_emote_vr",list(act,m_type,message)))
|
||||
return // Custom Emote Handler
|
||||
switch(act)
|
||||
|
||||
if ("airguitar")
|
||||
if (!src.restrained())
|
||||
message = "is strumming the air and headbanging like a safari chimp."
|
||||
m_type = 1
|
||||
|
||||
//Machine-only emotes
|
||||
if("beep", "buzz", "buzz2", "chime", "die", "dwoop", "error", "honk", "no", "ping", "rcough", "rsneeze", "scary", "shutdown","startup", "warn", "ye", "yes")
|
||||
|
||||
var/obj/item/organ/o = internal_organs_by_name[O_VOICE]
|
||||
if(!isSynthetic() && (!o || !(o.robotic >= ORGAN_ASSISTED)))
|
||||
to_chat(src, "<span class='warning'>You are not a synthetic.</span>")
|
||||
return
|
||||
|
||||
var/M = null
|
||||
if(param)
|
||||
for (var/mob/A in view(null, null))
|
||||
if (param == A.name)
|
||||
M = A
|
||||
break
|
||||
if(!M)
|
||||
param = null
|
||||
|
||||
var/display_msg = "beeps"
|
||||
var/use_sound = 'sound/machines/twobeep.ogg'
|
||||
if(act == "buzz")
|
||||
display_msg = "buzzes"
|
||||
use_sound = 'sound/machines/buzz-sigh.ogg'
|
||||
else if(act == "chime")
|
||||
display_msg = "chimes"
|
||||
use_sound = 'sound/machines/chime.ogg'
|
||||
else if(act == "buzz2")
|
||||
display_msg = "buzzes twice"
|
||||
use_sound = 'sound/machines/buzz-two.ogg'
|
||||
else if(act == "warn")
|
||||
display_msg = "blares an alarm"
|
||||
use_sound = 'sound/machines/warning-buzzer.ogg'
|
||||
else if(act == "honk")
|
||||
display_msg = "honks"
|
||||
use_sound = 'sound/items/bikehorn.ogg'
|
||||
else if(act == "ping")
|
||||
display_msg = "pings"
|
||||
use_sound = 'sound/machines/ping.ogg'
|
||||
else if(act == "yes" || act == "ye")
|
||||
display_msg = "emits an affirmative blip"
|
||||
use_sound = 'sound/machines/synth_yes.ogg'
|
||||
else if(act == "no")
|
||||
display_msg = "emits a negative blip"
|
||||
use_sound = 'sound/machines/synth_no.ogg'
|
||||
else if(act == "dwoop")
|
||||
display_msg = "chirps happily"
|
||||
use_sound = 'sound/machines/dwoop.ogg'
|
||||
else if(act == "scary")
|
||||
display_msg = "emits a disconcerting tone"
|
||||
use_sound = 'sound/machines/synth_scary.ogg'
|
||||
else if(act == "startup")
|
||||
display_msg = "chimes to life"
|
||||
use_sound = 'sound/machines/synth_startup.ogg'
|
||||
else if(act == "shutdown")
|
||||
display_msg = "emits a nostalgic tone as they fall silent"
|
||||
use_sound = 'sound/machines/synth_shutdown.ogg'
|
||||
else if(act == "error")
|
||||
display_msg = "experiences a system error"
|
||||
use_sound = 'sound/machines/synth_error.ogg'
|
||||
else if(act == "die")
|
||||
display_msg = "crumples, their chassis colder and more lifeless than usual"
|
||||
use_sound = 'sound/machines/synth_gameover.ogg'
|
||||
else if(act == "rcough")
|
||||
display_msg = "emits a robotic cough"
|
||||
if(get_gender() == FEMALE)
|
||||
use_sound = pick('sound/effects/mob_effects/f_machine_cougha.ogg','sound/effects/mob_effects/f_machine_coughb.ogg')
|
||||
else
|
||||
use_sound = pick('sound/effects/mob_effects/m_machine_cougha.ogg','sound/effects/mob_effects/m_machine_coughb.ogg', 'sound/effects/mob_effects/m_machine_coughc.ogg')
|
||||
else if(act == "rsneeze")
|
||||
display_msg = "emits a robotic sneeze"
|
||||
if(get_gender() == FEMALE)
|
||||
use_sound = 'sound/effects/mob_effects/machine_sneeze.ogg'
|
||||
else
|
||||
use_sound = 'sound/effects/mob_effects/f_machine_sneeze.ogg'
|
||||
|
||||
if (param)
|
||||
message = "[display_msg] at [param]."
|
||||
else
|
||||
message = "[display_msg]."
|
||||
playsound(src.loc, use_sound, 50, 0)
|
||||
m_type = 1
|
||||
|
||||
//Promethean-only emotes
|
||||
if("squish")
|
||||
if(species.bump_flag != SLIME) //This should definitely do it.
|
||||
to_chat(src, "<span class='warning'>You are not a slime thing!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/effects/slime_squish.ogg', 50, 0) //Credit to DrMinky (freesound.org) for the sound.
|
||||
message = "squishes."
|
||||
m_type = 1
|
||||
|
||||
// SHRIEK VOXXY ONLY
|
||||
if ("shriekloud")
|
||||
if(src.species.get_species_id() != SPECIES_ID_VOX)
|
||||
to_chat(src, "<span class='warning'>You aren't ear piercingly vocal enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/shrieksneeze.ogg', 50, 0)
|
||||
message = "gives a short sharp shriek!"
|
||||
m_type = 1
|
||||
|
||||
if ("shriekshort")
|
||||
if(src.species.get_species_id() != SPECIES_ID_VOX)
|
||||
to_chat(src, "<span class='warning'>You aren't noisy enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/shriekcough.ogg', 50, 0)
|
||||
message = "gives a short, quieter shriek!"
|
||||
m_type = 1
|
||||
|
||||
// SQUID GAMES
|
||||
if ("achime")
|
||||
if(src.species.get_species_id() != SPECIES_ID_ADHERENT)
|
||||
to_chat(src, "<span class='warning'>You aren't floaty enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/machines/achime.ogg', 50, 0)
|
||||
message = "chimes!"
|
||||
m_type = 1
|
||||
|
||||
//Xenomorph Hybrid
|
||||
if("xhiss")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/alien_hiss3.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xroar")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/alien_roar1.ogg', 50, 0)
|
||||
message = "roars!"
|
||||
m_type = 2
|
||||
|
||||
if("xhiss2")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/xhiss2.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xhiss3")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/xhiss3.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xhiss4")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/xhiss4.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xhiss5")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/xhiss5.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xhiss6")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/xhiss6.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xroar1")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/xroar1.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xroar2")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/xroar2.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xroar3")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/xroar3.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xtalk1")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/xtalk1.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xtalk2")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/xtalk2.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xtalk3")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/xtalk3.ogg', 50, 0)
|
||||
message = "hisses!"
|
||||
m_type = 2
|
||||
|
||||
if("xroar")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/alien_roar1.ogg', 50, 0)
|
||||
message = "roars!"
|
||||
m_type = 2
|
||||
|
||||
if("xgrowl")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
playsound(src.loc, 'sound/voice/xenos/alien_growl1.ogg', 50, 0)
|
||||
message = "growls!"
|
||||
m_type = 2
|
||||
|
||||
if("xkiss")
|
||||
if(src.species.get_species_id() != SPECIES_ID_XENOHYBRID)
|
||||
to_chat(src, "<span class='warning'>You aren't alien enough!</span>")
|
||||
return
|
||||
var/M = null
|
||||
if (param)
|
||||
for (var/mob/A in view(1,src.loc))
|
||||
@@ -309,113 +64,8 @@
|
||||
message = "makes a kissing mouth."
|
||||
m_type = 1
|
||||
|
||||
if("smooch")
|
||||
if (param)
|
||||
var/M = null
|
||||
for (var/mob/A in view(1,src.loc))
|
||||
if (param == A.name)
|
||||
M = A
|
||||
break
|
||||
if (!M)
|
||||
param = null
|
||||
|
||||
if (param)
|
||||
message = "smooches [param]."
|
||||
m_type = 1
|
||||
|
||||
if ("blink")
|
||||
message = "blinks."
|
||||
m_type = 1
|
||||
|
||||
if ("blink_r")
|
||||
message = "blinks rapidly."
|
||||
m_type = 1
|
||||
|
||||
if ("bow")
|
||||
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 = "bows to [param]."
|
||||
else
|
||||
message = "bows."
|
||||
m_type = 1
|
||||
|
||||
if ("custom")
|
||||
var/input = sanitize(input("Choose an emote to display.") as text|null)
|
||||
if (!input)
|
||||
return
|
||||
var/input2 = input("Is this a visible or hearable emote?") in list("Visible","Hearable")
|
||||
if (input2 == "Visible")
|
||||
m_type = 1
|
||||
else if (input2 == "Hearable")
|
||||
if HAS_TRAIT_FROM(src, TRAIT_MUTE, MIME_TRAIT)
|
||||
return
|
||||
m_type = 2
|
||||
else
|
||||
alert("Unable to use this emote, must be either hearable or visible.")
|
||||
return
|
||||
return custom_emote(m_type, message)
|
||||
|
||||
if ("me")
|
||||
|
||||
//if(silent && silent > 0 && findtext(message,"\"",1, null) > 0)
|
||||
// return //This check does not work and I have no idea why, I'm leaving it in for reference.
|
||||
|
||||
if (src.client)
|
||||
if (client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "<font color='red'>You cannot send IC messages (muted).</font>")
|
||||
return
|
||||
if (stat)
|
||||
return
|
||||
if(!(message))
|
||||
return
|
||||
return custom_emote(m_type, message)
|
||||
|
||||
if ("salute")
|
||||
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 = "salutes to [param]."
|
||||
else
|
||||
message = "salutes."
|
||||
m_type = 1
|
||||
|
||||
if ("fullsalute")
|
||||
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 = "salutes to [param]."
|
||||
else
|
||||
message = "salutes."
|
||||
|
||||
playsound(src.loc, 'sound/misc/salute.ogg', 30, 0)
|
||||
m_type = 1
|
||||
|
||||
|
||||
if ("choke")
|
||||
if HAS_TRAIT_FROM(src, TRAIT_MUTE, MIME_TRAIT)
|
||||
message = "clutches [T.his] throat desperately!"
|
||||
@@ -428,18 +78,6 @@
|
||||
message = "makes a strong noise."
|
||||
m_type = 2
|
||||
|
||||
if ("clap")
|
||||
if (!src.restrained())
|
||||
message = "claps."
|
||||
var/use_sound
|
||||
use_sound = pick('sound/misc/clapping.ogg','sound/voice/clap2.ogg','sound/voice/clap3.ogg','sound/voice/clap4.ogg')
|
||||
playsound(src.loc, use_sound, 50, 0)
|
||||
|
||||
if("golfclap")
|
||||
if (!src.restrained())
|
||||
message = "claps very slowly."
|
||||
playsound(src.loc, 'sound/voice/golfclap.ogg', 50, 0)
|
||||
|
||||
if ("flap")
|
||||
if (!src.restrained())
|
||||
message = "flaps [T.his] wings."
|
||||
@@ -454,16 +92,6 @@
|
||||
if(HAS_TRAIT_FROM(src, TRAIT_MUTE, MIME_TRAIT))
|
||||
m_type = 1
|
||||
|
||||
if("ara")
|
||||
message = "aras."
|
||||
var/use_sound
|
||||
use_sound = pick('sound/voice/ara_ara1.ogg','sound/voice/ara_ara2.ogg')
|
||||
playsound(src.loc, use_sound, 50, 0)
|
||||
|
||||
if("uwu")
|
||||
message = "lets out a devious noise."
|
||||
playsound(src.loc, 'sound/voice/uwu.ogg', 50, 0)
|
||||
|
||||
if ("drool")
|
||||
message = "drools."
|
||||
m_type = 1
|
||||
@@ -484,14 +112,6 @@
|
||||
message = "makes a noise."
|
||||
m_type = 2
|
||||
|
||||
if ("twitch")
|
||||
message = "twitches."
|
||||
m_type = 1
|
||||
|
||||
if ("twitch_v")
|
||||
message = "twitches violently."
|
||||
m_type = 1
|
||||
|
||||
if ("faint")
|
||||
message = "faints."
|
||||
if(!IS_CONSCIOUS(src))
|
||||
@@ -499,38 +119,6 @@
|
||||
afflict_sleeping(20 * 10) //Short-short nap
|
||||
m_type = 1
|
||||
|
||||
if("cough", "coughs")
|
||||
if HAS_TRAIT_FROM(src, TRAIT_MUTE, MIME_TRAIT)
|
||||
message = "appears to cough!"
|
||||
m_type = 1
|
||||
else
|
||||
if(!muzzled)
|
||||
var/robotic = 0
|
||||
m_type = 2
|
||||
if(should_have_organ(O_LUNGS))
|
||||
var/obj/item/organ/internal/lungs/L = internal_organs_by_name[O_LUNGS]
|
||||
if(L && L.robotic == 2) //Hard-coded to 2, incase we add lifelike robotic lungs
|
||||
robotic = 1
|
||||
if(!robotic)
|
||||
message = "coughs!"
|
||||
if(get_gender() == FEMALE)
|
||||
if(species.female_cough_sounds)
|
||||
playsound(src, pick(species.female_cough_sounds), 120)
|
||||
else
|
||||
if(species.male_cough_sounds)
|
||||
playsound(src, pick(species.male_cough_sounds), 120)
|
||||
else
|
||||
message = "emits a robotic cough"
|
||||
var/use_sound
|
||||
if(get_gender() == FEMALE)
|
||||
use_sound = pick('sound/effects/mob_effects/f_machine_cougha.ogg','sound/effects/mob_effects/f_machine_coughb.ogg')
|
||||
else
|
||||
use_sound = pick('sound/effects/mob_effects/m_machine_cougha.ogg','sound/effects/mob_effects/m_machine_coughb.ogg', 'sound/effects/mob_effects/m_machine_coughc.ogg')
|
||||
playsound(src.loc, use_sound, 50, 0)
|
||||
else
|
||||
message = "makes a strong noise."
|
||||
m_type = 2
|
||||
|
||||
if("bcough")
|
||||
if HAS_TRAIT_FROM(src, TRAIT_MUTE, MIME_TRAIT)
|
||||
message = "appears to cough up blood!"
|
||||
@@ -554,22 +142,6 @@
|
||||
if(species.male_cough_sounds)
|
||||
playsound(src, pick(species.male_cough_sounds), 120)
|
||||
|
||||
if ("frown")
|
||||
message = "frowns."
|
||||
m_type = 1
|
||||
|
||||
if ("nod")
|
||||
message = "nods."
|
||||
m_type = 1
|
||||
|
||||
if ("blush")
|
||||
message = "blushes."
|
||||
m_type = 1
|
||||
|
||||
if ("wave")
|
||||
message = "waves."
|
||||
m_type = 1
|
||||
|
||||
if ("gasp")
|
||||
if HAS_TRAIT_FROM(src, TRAIT_MUTE, MIME_TRAIT)
|
||||
message = "appears to be gasping!"
|
||||
@@ -747,44 +319,16 @@
|
||||
message = "says, \"[M], please. He had a family.\" [src.name] takes a drag from a cigarette and blows his name out in smoke."
|
||||
m_type = 2
|
||||
|
||||
if ("point")
|
||||
if (!src.restrained())
|
||||
var/mob/M = null
|
||||
if (param)
|
||||
for (var/atom/A as mob|obj|turf|area in view(null, null))
|
||||
if (param == A.name)
|
||||
M = A
|
||||
break
|
||||
|
||||
if (!M)
|
||||
message = "points."
|
||||
else
|
||||
pointed(M)
|
||||
|
||||
if (M)
|
||||
message = "points to [M]."
|
||||
else
|
||||
m_type = 1
|
||||
|
||||
if("crack")
|
||||
if(!restrained())
|
||||
message = "cracks [T.his] knuckles."
|
||||
playsound(src, 'sound/voice/knuckles.ogg', 50, 1,)
|
||||
m_type = 1
|
||||
|
||||
if ("raise")
|
||||
if (!src.restrained())
|
||||
message = "raises a hand."
|
||||
m_type = 1
|
||||
|
||||
if("shake")
|
||||
message = "shakes [T.his] head."
|
||||
m_type = 1
|
||||
|
||||
if ("shrug")
|
||||
message = "shrugs."
|
||||
m_type = 1
|
||||
|
||||
if ("signal")
|
||||
if (!src.restrained())
|
||||
var/t1 = round(text2num(param))
|
||||
@@ -792,16 +336,6 @@
|
||||
message = "raises [t1] finger\s."
|
||||
m_type = 1
|
||||
|
||||
if ("smile")
|
||||
message = "smiles."
|
||||
m_type = 1
|
||||
|
||||
if ("shiver")
|
||||
message = "shivers."
|
||||
m_type = 2
|
||||
if HAS_TRAIT_FROM(src, TRAIT_MUTE, MIME_TRAIT)
|
||||
m_type = 1
|
||||
|
||||
if ("pale")
|
||||
message = "goes pale for a second."
|
||||
m_type = 1
|
||||
@@ -810,37 +344,6 @@
|
||||
message = "trembles in fear!"
|
||||
m_type = 1
|
||||
|
||||
if("sneeze", "sneezes")
|
||||
if HAS_TRAIT_FROM(src, TRAIT_MUTE, MIME_TRAIT)
|
||||
message = "sneezes."
|
||||
m_type = 1
|
||||
else
|
||||
if(!muzzled)
|
||||
var/robotic = 0
|
||||
m_type = 2
|
||||
if(should_have_organ(O_LUNGS))
|
||||
var/obj/item/organ/internal/lungs/L = internal_organs_by_name[O_LUNGS]
|
||||
if(L && L.robotic == 2) //Hard-coded to 2, incase we add lifelike robotic lungs
|
||||
robotic = 1
|
||||
if(!robotic)
|
||||
message = "sneezes."
|
||||
if(get_gender() == FEMALE)
|
||||
playsound(src, species.female_sneeze_sound, 70)
|
||||
else
|
||||
playsound(src, species.male_sneeze_sound, 70)
|
||||
m_type = 2
|
||||
else
|
||||
message = "emits a robotic sneeze"
|
||||
var/use_sound
|
||||
if(get_gender() == FEMALE)
|
||||
use_sound = 'sound/effects/mob_effects/machine_sneeze.ogg'
|
||||
else
|
||||
use_sound = 'sound/effects/mob_effects/f_machine_sneeze.ogg'
|
||||
playsound(src.loc, use_sound, 50, 0)
|
||||
else
|
||||
message = "makes a strange noise."
|
||||
m_type = 2
|
||||
|
||||
if ("sniff")
|
||||
message = "sniffs."
|
||||
m_type = 2
|
||||
@@ -871,10 +374,6 @@
|
||||
message = "makes a weak noise."
|
||||
m_type = 2
|
||||
|
||||
if ("wink")
|
||||
message = "winks."
|
||||
m_type = 1
|
||||
|
||||
if ("yawn")
|
||||
if (!muzzled)
|
||||
message = "yawns."
|
||||
@@ -965,6 +464,7 @@
|
||||
|
||||
if("aslap", "aslaps")
|
||||
m_type = 1
|
||||
dangerous_pass_through_without_sanitizing = TRUE
|
||||
var/mob/living/carbon/human/H = src
|
||||
var/obj/item/organ/external/L = H.get_organ("l_hand")
|
||||
var/obj/item/organ/external/R = H.get_organ("r_hand")
|
||||
@@ -1017,25 +517,6 @@
|
||||
else
|
||||
message = "makes a very loud noise."
|
||||
m_type = 2
|
||||
if("squeak","squeaks")
|
||||
if HAS_TRAIT_FROM(src, TRAIT_MUTE, MIME_TRAIT)
|
||||
message = "acts out a soft squeak."
|
||||
m_type = 1
|
||||
else
|
||||
if(!muzzled)
|
||||
message = "squeaks!"
|
||||
m_type = 2
|
||||
playsound(loc, "sound/effects/mouse_squeak.ogg", 50, 1)
|
||||
|
||||
if("meow", "meows")
|
||||
if HAS_TRAIT_FROM(src, TRAIT_MUTE, MIME_TRAIT)
|
||||
message = "acts out a soft mrowl."
|
||||
m_type = 1
|
||||
else
|
||||
if(!muzzled)
|
||||
message = "mrowls!"
|
||||
m_type = 2
|
||||
playsound(loc, 'sound/voice/meow1.ogg', 50, 1)
|
||||
|
||||
if("snap", "snaps")
|
||||
m_type = 2
|
||||
@@ -1096,6 +577,7 @@
|
||||
if(!param)
|
||||
to_chat(src, usage)
|
||||
return
|
||||
dangerous_pass_through_without_sanitizing = TRUE
|
||||
|
||||
var/t1 = findtext(param, "+", 1, null)
|
||||
var/t2 = findtext(param, "-", 1, null)
|
||||
@@ -1136,20 +618,22 @@
|
||||
return
|
||||
|
||||
if ("help")
|
||||
to_chat(src, "ara, awoo, bark, bleat, blink, blink_r, blush, bow-(none)/mob, burp, chirp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, echoping, eyebrow, fastsway/qwag, \
|
||||
flip, frown, gasp, giggle, glare-(none)/mob, grin, groan, grumble, growl, handshake, hiss, howl, hug-(none)/mob, laugh, look-(none)/mob, mar, merp, moan, mrrp, mumble, nod, nya, nyaha, pale, peep, point-atom, prbt, \
|
||||
raise, roll, salute, fullsalute, scream, sneeze, shake, shiver, shrug, sigh, signal-#1-10, slap-(none)/mob, smile, sneeze, sniff, snore, stare-(none)/mob, stopsway/swag, squeak, sway/wag, swish, tremble, twitch, \
|
||||
twitch_v, uwu, vomit, weh, whimper, wink, yawn, ycackle. Moth: mchitter, mlaugh, mscream, msqueak. Synthetics: airhorn, beep, buzz, buzz2, chime, die, dwoop, error, honk, no, ping, rcough, rsneeze, scary, \
|
||||
shutdown, startup, steam, warn, ye, yes. Vox: shriekshort, shriekloud")
|
||||
to_chat(src, "bark, bleat, blush, bow-(none)/mob, burp, chirp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, echoping, eyebrow, fastsway/qwag, \
|
||||
flip, frown, gasp, giggle, glare-(none)/mob, grin, groan, grumble, growl, handshake, hiss, howl, hug-(none)/mob, laugh, look-(none)/mob, mar, merp, moan, mrrp, mumble, nod, nya, nyaha, pale, prbt, \
|
||||
raise, roll, scream, sneeze, shake, shiver, shrug, sigh, signal-#1-10, slap-(none)/mob, smile, sneeze, sniff, snore, stare-(none)/mob, stopsway/swag, squeak, sway/wag, swish, tremble, \
|
||||
vomit, weh, whimper, wink, yawn, ycackle. Moth: mchitter, mlaugh, mscream, msqueak. Synthetics: airhorn, die, error, rcough, rsneeze, \
|
||||
ye.")
|
||||
|
||||
else
|
||||
to_chat(src, "<font color=#4F49AF>Unusable emote '[act]'. Say *help for a list.</font>")
|
||||
return
|
||||
|
||||
if (message)
|
||||
custom_emote(m_type,message)
|
||||
|
||||
|
||||
// RAAAAGH I HATE YOU *ROLL
|
||||
if(!dangerous_pass_through_without_sanitizing)
|
||||
message = html_encode(message)
|
||||
for(var/mob/nearby in saycode_view_query(world_view_max_number(), TRUE))
|
||||
nearby.show_message("<b>[src]</b> [message]", SAYCODE_TYPE_ALWAYS)
|
||||
|
||||
/mob/living/carbon/human/proc/set_pose(new_pose)
|
||||
pose = sanitize(new_pose)
|
||||
@@ -1241,6 +725,7 @@
|
||||
HTML += "<tt>"
|
||||
src << browse(HTML, "window=flavor_changes;size=430x300")
|
||||
|
||||
// New emotes in here are no longer allowed.
|
||||
/mob/living/carbon/human/proc/handle_emote_vr(var/act,var/m_type=1,var/message = null)
|
||||
|
||||
switch(act)
|
||||
@@ -1265,17 +750,6 @@
|
||||
if ("mlem")
|
||||
message = "mlems [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] tongue up over [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] nose. Mlem."
|
||||
m_type = 1
|
||||
///////////////////////// EMOTES PORTED FROM MAIN START
|
||||
if ("awoo")
|
||||
m_type = 2
|
||||
message = "lets out an awoo."
|
||||
playsound(loc, 'sound/voice/awoo.ogg', 50, 1, -1)
|
||||
if ("nya")
|
||||
message = "lets out a nya."
|
||||
m_type = 2
|
||||
var/use_sound
|
||||
use_sound = pick('sound/voice/nya.ogg')
|
||||
playsound(src.loc, use_sound, 50, 0)
|
||||
if ("nyaha")
|
||||
if(!spam_flag)
|
||||
var/list/catlaugh = list('sound/voice/catpeople/nyaha.ogg', 'sound/voice/catpeople/nyahaha1.ogg', 'sound/voice/catpeople/nyahaha2.ogg', 'sound/voice/catpeople/nyahehe.ogg')
|
||||
@@ -1285,10 +759,6 @@
|
||||
var/list/laughs = list("laughs deviously.", "lets out a catty laugh.", "nya ha ha's.")
|
||||
message = "[pick(laughs)]"
|
||||
m_type = 2
|
||||
if ("peep")
|
||||
message = "peeps like a bird."
|
||||
m_type = 2
|
||||
playsound(loc, 'sound/voice/peep.ogg', 50, 1, -1)
|
||||
if("chirp")
|
||||
message = "chirps!"
|
||||
playsound(src.loc, 'sound/misc/nymphchirp.ogg', 50, 0)
|
||||
@@ -1321,10 +791,6 @@
|
||||
message = "lets out a hiss."
|
||||
m_type = 2
|
||||
playsound(loc, 'sound/voice/hiss.ogg', 50, 1, -1)
|
||||
if ("squeak")
|
||||
message = "lets out a squeak."
|
||||
m_type = 2
|
||||
playsound(loc, 'sound/effects/mouse_squeak.ogg', 50, 1, -1)
|
||||
if("mar")
|
||||
message = "lets out a mar."
|
||||
m_type = 2
|
||||
@@ -1383,14 +849,6 @@
|
||||
message = "purrs softly."
|
||||
m_type = 2
|
||||
playsound(loc, 'sound/voice/purr.ogg', 50, 1, -1)
|
||||
if ("clak")
|
||||
if(!spam_flag)
|
||||
var/msg = list("<font color='grey' size='2'>CLAKS!</font>", "claks!")
|
||||
message = "[pick(msg)]"
|
||||
playsound(loc, 'sound/spooky/boneclak.ogg', 50, 1, 1)
|
||||
spam_flag = TRUE
|
||||
addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), 18)
|
||||
m_type = 2
|
||||
if ("ycackle")
|
||||
message = "cackles maniacally!"
|
||||
m_type = 2
|
||||
@@ -1421,16 +879,6 @@
|
||||
playsound(loc, 'sound/items/airhorn2.ogg', 20, 1, 1)
|
||||
spam_flag = TRUE
|
||||
addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), 18)
|
||||
if ("steam")
|
||||
var/obj/item/organ/o = internal_organs_by_name[O_VOICE]
|
||||
if(!isSynthetic() && (!o || !(o.robotic >= ORGAN_ASSISTED)))
|
||||
to_chat(src, "<span class='warning'>You are not a synthetic.</span>")
|
||||
return
|
||||
message = "lets off some steam."
|
||||
m_type = 2
|
||||
playsound(loc, 'sound/machines/clockcult/steam_whoosh.ogg', 30, 1, 1)
|
||||
spam_flag = TRUE
|
||||
addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), 18)
|
||||
|
||||
if (message)
|
||||
custom_emote(m_type,message)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/mob/living/carbon/human/say(var/message,var/whispering=0)
|
||||
var/alt_name = ""
|
||||
/mob/living/carbon/human/say(var/message, var/datum/prototype/language/speaking = null, var/verb="says", var/alt_name="", var/whispering = 0)
|
||||
if(name != GetVoice())
|
||||
alt_name = "(as [get_id_name("Unknown")])"
|
||||
|
||||
message = sanitize_or_reflect(message,src) // Reflect too-long messages, within reason
|
||||
..(message, alt_name = alt_name, whispering = whispering)
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/speech_bubble_appearance()
|
||||
if(isSynthetic())
|
||||
|
||||
12
code/modules/mob/living/living-emote.dm
Normal file
12
code/modules/mob/living/living-emote.dm
Normal file
@@ -0,0 +1,12 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
/mob/living/get_usable_emote_require()
|
||||
. = NONE
|
||||
if(silent || is_muzzled())
|
||||
else
|
||||
. |= EMOTE_REQUIRE_COHERENT_SPEECH | EMOTE_REQUIRE_VOCALIZATION
|
||||
if(isSynthetic())
|
||||
. |= EMOTE_REQUIRE_SYNTHETIC_SPEAKER
|
||||
if(inventory.get_empty_hand_indices())
|
||||
. |= EMOTE_REQUIRE_FREE_HAND
|
||||
@@ -1,3 +1,6 @@
|
||||
/mob/living
|
||||
emote_class = EMOTE_CLASS_IS_BODY
|
||||
|
||||
TYPE_REGISTER_SPATIAL_GRID(/mob/living, SSspatial_grids.living)
|
||||
/mob/living/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
@@ -168,8 +168,12 @@ var/list/channel_to_radio_key = new
|
||||
|
||||
//Maybe they are using say/whisper to do a quick emote, so do those
|
||||
switch(copytext_char(message,1,2))
|
||||
if("*") return emote(copytext_char(message,2))
|
||||
if("^") return custom_emote(1, copytext_char(message,2))
|
||||
// TODO: hey see this decode?
|
||||
// this is because emote system handles its own sanitization
|
||||
// this is to trample any *potential* sanitiziation that happened,
|
||||
// as otherwise quotes won't be properly parsed by the tokenizer.
|
||||
if("*") return emote(html_decode(copytext_char(message,2)))
|
||||
if("^") return custom_emote(1, html_decode(copytext_char(message,2)))
|
||||
|
||||
//Parse the radio code and consume it
|
||||
if (message_mode)
|
||||
@@ -244,7 +248,7 @@ var/list/channel_to_radio_key = new
|
||||
|
||||
message = message_args["message"]
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_MUTE))
|
||||
if(HAS_TRAIT(src, TRAIT_MUTE) && !(speaking && (speaking.language_flags & LANGUAGE_SIGNLANG)))
|
||||
to_chat(src, "<span class='danger'>You are not capable of speech!</span>")
|
||||
return
|
||||
|
||||
@@ -399,6 +403,9 @@ var/list/channel_to_radio_key = new
|
||||
|
||||
|
||||
//Main 'say' and 'whisper' message delivery
|
||||
var/turf/our_turf = get_turf(src)
|
||||
// todo: cache this or maybe just have a distinction between regular hear and 'observer heard us from far away'?
|
||||
var/max_vocal_cue_dist = world_view_max_number()
|
||||
for(var/mob/M in listening)
|
||||
spawn(0) //Using spawns to queue all the messages for AFTER this proc is done, and stop runtimes
|
||||
|
||||
@@ -410,6 +417,8 @@ var/list/channel_to_radio_key = new
|
||||
var/image/I1 = listening[M] || speech_bubble
|
||||
images_to_clients[I1] |= M.client
|
||||
SEND_IMAGE(M, I1)
|
||||
if(M.get_preference_toggle(/datum/game_preference_toggle/game/vocal_cues) && get_dist(M, src) <= max_vocal_cue_dist)
|
||||
M.playsound_local(our_turf, /datum/soundbyte/talksound/goon_say, 75, TRUE)
|
||||
M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol)
|
||||
else if(whispering) //Don't even bother with these unless whispering
|
||||
if(dst > message_range && dst <= w_scramble_range) //Inside whisper scramble range
|
||||
|
||||
8
code/modules/mob/living/silicon/ai/ai-custom_emote.dm
Normal file
8
code/modules/mob/living/silicon/ai/ai-custom_emote.dm
Normal file
@@ -0,0 +1,8 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/mob/living/silicon/ai/emit_custom_emote(emote_text)
|
||||
if(holopad)
|
||||
holopad_emote(emote_text)
|
||||
else
|
||||
..()
|
||||
@@ -45,9 +45,3 @@
|
||||
to_chat(src, "No holopad connected.")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/ai/emote(var/act, var/type, var/message)
|
||||
if(holopad)
|
||||
holopad_emote(message)
|
||||
else //Emote normally, then.
|
||||
..()
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
/mob/living/silicon/emote(var/act,var/m_type=1,var/message = null)
|
||||
. = ..()
|
||||
if(. == "stop")
|
||||
return
|
||||
var/param = null
|
||||
if (findtext(act, "-", 1, null))
|
||||
var/t1 = findtext(act, "-", 1, null)
|
||||
@@ -20,40 +23,6 @@
|
||||
break
|
||||
|
||||
switch(act)
|
||||
if ("me")
|
||||
if (src.client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "You cannot send IC messages (muted).")
|
||||
return
|
||||
if (stat)
|
||||
return
|
||||
if(!(message))
|
||||
return
|
||||
else
|
||||
return custom_emote(m_type, message)
|
||||
|
||||
if ("custom")
|
||||
return custom_emote(m_type, message)
|
||||
|
||||
if ("salute")
|
||||
if (!src.buckled)
|
||||
if (emote_target)
|
||||
message = "salutes to [emote_target]."
|
||||
else
|
||||
message = "salutes."
|
||||
m_type = 1
|
||||
if ("bow")
|
||||
if (!src.buckled)
|
||||
if (emote_target)
|
||||
message = "bows to [emote_target]."
|
||||
else
|
||||
message = "bows."
|
||||
m_type = 1
|
||||
|
||||
if ("clap")
|
||||
if (!src.restrained())
|
||||
message = "claps."
|
||||
m_type = 2
|
||||
if ("flap")
|
||||
if (!src.restrained())
|
||||
message = "flaps its wings."
|
||||
@@ -64,65 +33,10 @@
|
||||
message = "flaps its wings ANGRILY!"
|
||||
m_type = 2
|
||||
|
||||
if ("twitch")
|
||||
message = "twitches."
|
||||
m_type = 1
|
||||
|
||||
if ("twitch_v")
|
||||
message = "twitches violently."
|
||||
m_type = 1
|
||||
|
||||
if ("nod")
|
||||
message = "nods."
|
||||
m_type = 1
|
||||
|
||||
if ("deathgasp")
|
||||
message = "shudders violently for a moment, then becomes motionless, its eyes slowly darkening."
|
||||
m_type = 1
|
||||
|
||||
if ("glare")
|
||||
if (emote_target)
|
||||
message = "glares at [emote_target]."
|
||||
else
|
||||
message = "glares."
|
||||
|
||||
if ("stare")
|
||||
if (emote_target)
|
||||
message = "stares at [emote_target]."
|
||||
else
|
||||
message = "stares."
|
||||
|
||||
if ("look")
|
||||
if (emote_target)
|
||||
message = "looks at [emote_target]."
|
||||
else
|
||||
message = "looks."
|
||||
m_type = 1
|
||||
|
||||
if("beep")
|
||||
if (emote_target)
|
||||
message = "beeps at [emote_target]."
|
||||
else
|
||||
message = "beeps."
|
||||
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
|
||||
m_type = 1
|
||||
|
||||
if("ping")
|
||||
if (emote_target)
|
||||
message = "pings at [emote_target]."
|
||||
else
|
||||
message = "pings."
|
||||
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
m_type = 1
|
||||
|
||||
if("buzz")
|
||||
if (emote_target)
|
||||
message = "buzzes at [emote_target]."
|
||||
else
|
||||
message = "buzzes."
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
m_type = 1
|
||||
|
||||
if("spin")
|
||||
message = "spins!"
|
||||
m_type = 1
|
||||
@@ -132,59 +46,6 @@
|
||||
unbuckle_mob(L, BUCKLE_OP_FORCE)
|
||||
L.throw_at(get_edge_target_turf(get_turf(src), dir), 7, 1, THROW_AT_IS_GENTLE, src)
|
||||
spin(15, 1)
|
||||
|
||||
if("yes", "ye")
|
||||
if (emote_target)
|
||||
message = "emits an affirmative blip at [emote_target]."
|
||||
else
|
||||
message = "emits an affirmative blip."
|
||||
playsound(src, 'sound/machines/synth_yes.ogg', 50, 0)
|
||||
m_type = 1
|
||||
|
||||
if("no")
|
||||
if (emote_target)
|
||||
message = "emits a negative blip at [emote_target]."
|
||||
else
|
||||
message = "emits a negative blip."
|
||||
playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0)
|
||||
m_type = 1
|
||||
|
||||
if("scary")
|
||||
if (emote_target)
|
||||
message = "emits a disconcerting tone at [emote_target]."
|
||||
else
|
||||
message = "emits a disconcerting tone."
|
||||
playsound(src.loc, 'sound/machines/synth_scary.ogg', 50, 0)
|
||||
m_type = 1
|
||||
|
||||
if("dwoop")
|
||||
if (emote_target)
|
||||
message = "chirps happily at [emote_target]."
|
||||
else
|
||||
message = "chirps happily."
|
||||
playsound(src.loc, 'sound/machines/dwoop.ogg', 50, 0)
|
||||
m_type = 1
|
||||
|
||||
if("startup")
|
||||
message = "chimes to life."
|
||||
playsound(src.loc, 'sound/machines/synth_startup.ogg', 50)
|
||||
m_type = 1
|
||||
|
||||
if("shutdown")
|
||||
message = "emits a nostalgic tone as they fall silent."
|
||||
playsound(src.loc, 'sound/machines/synth_shutdown.ogg', 50)
|
||||
m_type = 1
|
||||
|
||||
if("error")
|
||||
message = "experiences a system error."
|
||||
playsound(src.loc, 'sound/machines/synth_error.ogg', 50)
|
||||
m_type = 1
|
||||
|
||||
if("die")
|
||||
message = "crumples, their chassis colder and more lifeless than usual."
|
||||
playsound(src.loc, 'sound/machines/synth_gameover.ogg', 50)
|
||||
m_type = 1
|
||||
|
||||
if("flip")
|
||||
if(!CHECK_ALL_MOBILITY(src, MOBILITY_CAN_MOVE | MOBILITY_CAN_USE))
|
||||
to_chat(src, "<span class='warning'>You can't *flip in your current state!</span>")
|
||||
@@ -243,16 +104,6 @@
|
||||
playsound(src.loc, 'sound/machines/gonk.ogg', 50, 0)
|
||||
m_type = 1
|
||||
|
||||
if("nya")
|
||||
var/mob/living/silicon/robot/R = src
|
||||
if (istype(R) && R.module.is_cat())
|
||||
message = "lets out a nya."
|
||||
|
||||
playsound(loc, 'sound/voice/nya.ogg', 50, 1, -1)
|
||||
m_type = 2
|
||||
else
|
||||
to_chat(src, "You're not a cat!")
|
||||
|
||||
if("mrrp")
|
||||
var/mob/living/silicon/robot/R = src
|
||||
if (istype(R) && R.module.is_cat())
|
||||
@@ -273,16 +124,6 @@
|
||||
else
|
||||
to_chat(src, "You're not a cat!")
|
||||
|
||||
if("meow", "meows")
|
||||
var/mob/living/silicon/robot/R = src
|
||||
if (istype(R) && R.module.is_cat())
|
||||
message = "prbts."
|
||||
|
||||
playsound(loc, 'sound/voice/meow1.ogg', 50, 1, -1)
|
||||
m_type = 2
|
||||
else
|
||||
to_chat(src, "You're not a cat!")
|
||||
|
||||
if("hiss")
|
||||
var/mob/living/silicon/robot/R = src
|
||||
if (istype(R) && R.module.is_cat())
|
||||
@@ -307,8 +148,3 @@
|
||||
to_chat(src, "salute, bow-(none)/mob, clap, flap, aflap, twitch, twitch_s, nod, deathgasp, glare-(none)/mob, stare-(none)/mob, look, beep, ping, \nbuzz, law, halt, yes, no")
|
||||
else
|
||||
to_chat(src, "<font color=#4F49AF>Unusable emote '[act]'. Say *help for a list.</font>")
|
||||
|
||||
if ((message && src.stat == 0))
|
||||
custom_emote(m_type,message)
|
||||
|
||||
return
|
||||
|
||||
@@ -324,18 +324,11 @@
|
||||
update_icon()
|
||||
..()
|
||||
|
||||
|
||||
//Client attached
|
||||
/mob/living/simple_mob/Login()
|
||||
. = ..()
|
||||
to_chat(src,"<b>You are \the [src].</b> [player_msg]")
|
||||
|
||||
|
||||
/mob/living/simple_mob/emote(var/act, var/type, var/desc)
|
||||
if(act)
|
||||
..(act, type, desc)
|
||||
|
||||
|
||||
/mob/living/simple_mob/SelfMove(turf/n, direct)
|
||||
var/turf/old_turf = get_turf(src)
|
||||
var/old_dir = dir
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
else if(M.stat == DEAD && M.get_preference_toggle(/datum/game_preference_toggle/observer/ghost_ears))
|
||||
to_chat(M, "The captive mind of [src] whispers, \"[message]\"")
|
||||
|
||||
/mob/living/captive_brain/emote(var/message)
|
||||
return
|
||||
/mob/living/captive_brain/process_emote(datum/emote/emote, raw_parameter_string, datum/event_args/actor/actor, used_binding)
|
||||
return FALSE
|
||||
|
||||
/mob/living/captive_brain/process_resist()
|
||||
//Resisting control by an alien mind.
|
||||
|
||||
@@ -136,7 +136,3 @@
|
||||
if (istype(other, /mob/living/carbon/brain))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/mob/living/voice/custom_emote(var/m_type=1,var/message = null,var/range=world.view)
|
||||
if(!comm) return
|
||||
..(m_type,message,comm.video_range)
|
||||
|
||||
130
code/modules/mob/mob-emote.dm
Normal file
130
code/modules/mob/mob-emote.dm
Normal file
@@ -0,0 +1,130 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
/**
|
||||
* Specifically for invoking /datum/emote
|
||||
*
|
||||
* 'custom emotes' aka 'say'd actions' are not handled by this system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Description WIP
|
||||
* * Blocking.
|
||||
* @return TRUE if invoked, FALSE otherwise
|
||||
*/
|
||||
/mob/proc/invoke_emote(key, parameter_string, datum/event_args/actor/actor)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
if(isnull(actor))
|
||||
actor = new(src)
|
||||
ASSERT(actor.performer == src)
|
||||
|
||||
// always apply anti-spam
|
||||
if(HAS_TRAIT(src, TRAIT_EMOTE_GLOBAL_COOLDOWN))
|
||||
return EMOTE_INVOKE_ERRORED
|
||||
ADD_TRAIT(src, TRAIT_EMOTE_GLOBAL_COOLDOWN, "__EMOTE__")
|
||||
REMOVE_TRAIT_IN(src, TRAIT_EMOTE_GLOBAL_COOLDOWN, "__EMOTE__", 0.25 SECONDS)
|
||||
|
||||
var/special_result = process_emote_special(key, parameter_string, actor)
|
||||
if(!isnull(special_result))
|
||||
return special_result
|
||||
|
||||
var/datum/emote/resolved = fetch_emote(key)
|
||||
if(!resolved)
|
||||
return EMOTE_INVOKE_INVALID
|
||||
if(HAS_TRAIT(src, TRAIT_EMOTE_COOLDOWN(resolved.type)))
|
||||
return EMOTE_INVOKE_ERRORED
|
||||
var/result = process_emote(resolved, parameter_string, actor, used_binding = key)
|
||||
if(result)
|
||||
return EMOTE_INVOKE_FINISHED
|
||||
else
|
||||
return EMOTE_INVOKE_ERRORED
|
||||
|
||||
/**
|
||||
* Description WIP
|
||||
*/
|
||||
/mob/proc/invoke_emote_async(key, parameter_string, datum/event_args/actor/actor)
|
||||
set waitfor = FALSE
|
||||
. = EMOTE_INVOKE_SLEEPING
|
||||
return invoke_emote(key, parameter_string, actor)
|
||||
|
||||
/**
|
||||
* Runs an emote.
|
||||
* * Blocking
|
||||
* * `raw_params` may be a list or a text string.
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
/mob/proc/process_emote(datum/emote/emote, parameter_string, datum/event_args/actor/actor, used_binding)
|
||||
var/list/arbitrary = emote.process_parameters(parameter_string, actor)
|
||||
// only continue if parameter parsing worked
|
||||
if(arbitrary == null)
|
||||
return
|
||||
// apply specific emote cooldown but only after it's done executing; checked in invoke_emote()
|
||||
ADD_TRAIT(src, TRAIT_EMOTE_COOLDOWN(emote.type), "__EMOTE__")
|
||||
. = emote.try_run_emote(actor, arbitrary, used_binding = used_binding)
|
||||
REMOVE_TRAIT_IN(src, TRAIT_EMOTE_COOLDOWN(emote.type), "__EMOTE__", emote.self_cooldown)
|
||||
|
||||
/**
|
||||
* Process special overrides
|
||||
* * Blocking
|
||||
* * `raw_params` may be a list or a text string.
|
||||
* @return EMOTE_INVOKE_* or null if not handled
|
||||
*/
|
||||
/mob/proc/process_emote_special(key, raw_params, datum/event_args/actor/actor)
|
||||
switch(key)
|
||||
if("me")
|
||||
if(!length(raw_params))
|
||||
actor.chat_feedback(
|
||||
SPAN_WARNING("You can't custom emote an empty string!"),
|
||||
target = src,
|
||||
)
|
||||
return EMOTE_INVOKE_ERRORED
|
||||
run_custom_emote(raw_params, actor = actor, with_overhead = TRUE)
|
||||
return EMOTE_INVOKE_FINISHED
|
||||
if("help")
|
||||
var/list/datum/emote/can_run_emotes = query_emote()
|
||||
var/list/assembled_html = list()
|
||||
for(var/datum/emote/emote as anything in can_run_emotes)
|
||||
if((islist(emote.bindings) && !length(emote.bindings)) || !emote.bindings)
|
||||
continue
|
||||
var/rendered_bindings = islist(emote.bindings) ? jointext(emote.bindings, "/") : emote.bindings
|
||||
var/rendered_first_binding = islist(emote.bindings) ? emote.bindings[1] : emote.bindings
|
||||
assembled_html += SPAN_TOOLTIP_DANGEROUS_HTML("[rendered_bindings][emote.parameter_description ? " [emote.parameter_description]" : ""]", rendered_first_binding)
|
||||
to_chat(src, "Usable emotes: [english_list(assembled_html)]")
|
||||
// TODO: should be FINISHED but we need to route to legacy *help too!
|
||||
return null
|
||||
return null
|
||||
|
||||
/**
|
||||
* Return a list of /datum/emote's we can **potentially** use
|
||||
*/
|
||||
/mob/proc/query_emote()
|
||||
RETURN_TYPE(/list)
|
||||
. = list()
|
||||
var/our_emote_class = get_usable_emote_class()
|
||||
var/datum/event_args/actor/actor = new(src)
|
||||
for(var/datum/emote/emote as anything in GLOB.emotes)
|
||||
if(!emote.can_potentially_use(actor, our_emote_class))
|
||||
continue
|
||||
. += emote
|
||||
|
||||
/**
|
||||
* Return a list of legacy emotes associated to descriptions or null
|
||||
*/
|
||||
/mob/proc/query_emote_special()
|
||||
RETURN_TYPE(/list)
|
||||
return list(
|
||||
"me" = "Input a custom emote for your character to perform.",
|
||||
"help" = "Get a list of usable emotes.",
|
||||
)
|
||||
|
||||
/**
|
||||
* Return emote classes we support.
|
||||
*/
|
||||
/mob/proc/get_usable_emote_class()
|
||||
return emote_class
|
||||
|
||||
/**
|
||||
* Return remote require flags we support
|
||||
*/
|
||||
/mob/proc/get_usable_emote_require()
|
||||
. = NONE
|
||||
97
code/modules/mob/mob-emote_custom.dm
Normal file
97
code/modules/mob/mob-emote_custom.dm
Normal file
@@ -0,0 +1,97 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/**
|
||||
* This module is used for processing custom emotes.
|
||||
*
|
||||
* Eventually, they'll be used with a proper saycode call-chain and tokenzier
|
||||
* to enable language fragment support and more.
|
||||
*
|
||||
* * Unlike saycode, there's no custom_emote() default wrapper, because custom emotes have so many things to customize.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Relay a raw incoming custom emote
|
||||
*
|
||||
* * Logging happens here.
|
||||
* * THE INPUT EMOTE TEXT IS NOT SANITIZED AT THIS STAGE.
|
||||
*/
|
||||
/mob/proc/run_custom_emote(emote_text, subtle, anti_ghost, saycode_type = SAYCODE_TYPE_VISIBLE, datum/event_args/actor/actor, with_overhead)
|
||||
if(stat)
|
||||
// TODO: tooltip with copy link.
|
||||
to_chat(src, SPAN_WARNING("You are unable to emote."))
|
||||
return
|
||||
if(isnull(actor))
|
||||
actor = new(src)
|
||||
|
||||
// raw preprocessed text is used
|
||||
// var/log_string = "[key_name(src)] ([AREACOORD(src)])[actor?.initiator != src ? " (initiated by [key_name(actor.initiator)] at [AREACOORD(actor.initiator)])" : ""]: [emote_text]"
|
||||
var/log_string = "[actor?.initiator != src ? " (initiated by [key_name(actor.initiator)] at [AREACOORD(actor.initiator)]) " : ""][emote_text]"
|
||||
|
||||
if(anti_ghost)
|
||||
// implicit
|
||||
subtle = TRUE
|
||||
|
||||
if(subtle)
|
||||
if(anti_ghost)
|
||||
log_subtle_anti_ghost(log_string, src)
|
||||
else
|
||||
log_subtle(log_string, src)
|
||||
else
|
||||
log_emote(log_string, src)
|
||||
|
||||
var/raw_html = process_custom_emote(emote_text, subtle, anti_ghost, saycode_type, with_overhead)
|
||||
if(!raw_html)
|
||||
return
|
||||
emit_custom_emote(raw_html, subtle, anti_ghost, saycode_type, with_overhead)
|
||||
|
||||
/**
|
||||
* Perform special preprocessing on an incoming custom emote
|
||||
* * The base level will html_encode().
|
||||
* * THE INPUT EMOTE TEXT IS NOT SANITIZED AT THIS STAGE.
|
||||
*
|
||||
* @return raw HTML
|
||||
*/
|
||||
/mob/proc/process_custom_emote(emote_text, subtle, anti_ghost, saycode_type, with_overhead)
|
||||
. = emote_text
|
||||
. = html_encode(.)
|
||||
. = say_emphasis(.)
|
||||
. = "<b>[src]</b> " + .
|
||||
if(subtle)
|
||||
if(anti_ghost)
|
||||
. = SPAN_SINGING(.)
|
||||
else
|
||||
. = "<i>[.]</i>"
|
||||
|
||||
/**
|
||||
* Emit a custom emote
|
||||
*/
|
||||
/mob/proc/emit_custom_emote(raw_html, subtle, anti_ghost, saycode_type, with_overhead)
|
||||
var/list/atom/movable/heard = saycode_view_query(subtle ? 1 : GLOB.game_view_radius, TRUE, anti_ghost)
|
||||
// TODO: centralized observer pref check in saycode_view_query
|
||||
var/optimize_this_later_max_number = world_view_max_number() + 2
|
||||
var/mob/filtered_mobs = list()
|
||||
// todo: legacy code
|
||||
for(var/atom/movable/hearing in heard)
|
||||
if(ismob(hearing))
|
||||
var/mob/hearing_mob = hearing
|
||||
if(isobserver(hearing_mob))
|
||||
if((get_dist(hearing_mob, src) > optimize_this_later_max_number) && !hearing_mob.get_preference_toggle(/datum/game_preference_toggle/observer/ghost_sight))
|
||||
continue
|
||||
if(subtle && !hearing_mob.get_preference_toggle(/datum/game_preference_toggle/observer/ghost_subtle))
|
||||
continue
|
||||
SEND_SIGNAL(hearing_mob, COMSIG_MOB_ON_RECEIVE_CUSTOM_EMOTE, src, raw_html, subtle, anti_ghost, saycode_type)
|
||||
hearing_mob.show_message(raw_html, saycode_type)
|
||||
filtered_mobs += hearing
|
||||
else if(isobj(hearing))
|
||||
var/obj/hearing_obj = hearing
|
||||
hearing_obj.see_emote(src, raw_html, 2)
|
||||
var/turf/our_loc = get_turf(src)
|
||||
var/use_sfx = subtle ? /datum/soundbyte/talksound/generic_subtle_emote_1 : /datum/soundbyte/talksound/generic_emote_1
|
||||
// todo: cache this or maybe just have a distinction between regular hear and 'observer heard us from far away'?
|
||||
var/max_vocal_cue_dist = world_view_max_number()
|
||||
for(var/mob/M as anything in filtered_mobs)
|
||||
if(M.get_preference_toggle(/datum/game_preference_toggle/game/vocal_cues) && get_dist(M, src) <= max_vocal_cue_dist)
|
||||
M.playsound_local(our_loc, use_sfx, 50, TRUE)
|
||||
if(with_overhead)
|
||||
say_overhead(raw_html, FALSE, GLOB.game_view_radius, passed_hearing_list = filtered_mobs)
|
||||
@@ -1,48 +1,8 @@
|
||||
/mob/proc/say(var/message, var/datum/prototype/language/speaking = null, var/verb="says", var/alt_name="", var/whispering = 0)
|
||||
return
|
||||
|
||||
|
||||
/mob/proc/whisper_wrapper()
|
||||
var/message = input("","whisper (text)") as text|null
|
||||
if(message)
|
||||
whisper(message)
|
||||
|
||||
/mob/proc/subtle_wrapper()
|
||||
var/message = input("","subtle (text)") as message|null
|
||||
if(message)
|
||||
me_verb_subtle(message)
|
||||
|
||||
/mob/proc/subtler_wrapper()
|
||||
var/message = input("","subtler (text)") as message|null
|
||||
if(message)
|
||||
subtler_anti_ghost(message)
|
||||
|
||||
/mob/verb/whisper(message as text)
|
||||
set name = "Whisper"
|
||||
set category = VERB_CATEGORY_IC
|
||||
|
||||
usr.say(message,whispering=1)
|
||||
|
||||
/mob/verb/say_verb(message as text)
|
||||
set name = "Say"
|
||||
set category = VERB_CATEGORY_IC
|
||||
|
||||
set_typing_indicator(FALSE)
|
||||
usr.say(message)
|
||||
|
||||
/mob/verb/me_verb(message as message)
|
||||
set name = "Me"
|
||||
set category = VERB_CATEGORY_IC
|
||||
|
||||
if(muffled)
|
||||
return me_verb_subtle(message)
|
||||
message = sanitize_or_reflect(message,src) // Reflect too-long messages (within reason)
|
||||
|
||||
set_typing_indicator(FALSE)
|
||||
if(use_me)
|
||||
usr.emote("me",SAYCODE_TYPE_ALWAYS,message)
|
||||
else
|
||||
usr.emote(message)
|
||||
/mob/proc/whisper(var/message, var/datum/prototype/language/speaking = null, var/verb="says", var/alt_name="")
|
||||
say(message, speaking, verb, alt_name, TRUE)
|
||||
|
||||
/mob/proc/say_dead(var/message)
|
||||
if(!client)
|
||||
@@ -119,10 +79,6 @@
|
||||
verb="asks"
|
||||
return verb
|
||||
|
||||
/mob/proc/emote(var/act, var/type, var/message)
|
||||
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
|
||||
156
code/modules/mob/mob-say-triggers.dm
Normal file
156
code/modules/mob/mob-say-triggers.dm
Normal file
@@ -0,0 +1,156 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
//* Say *//
|
||||
|
||||
/**
|
||||
* Prompts for a say
|
||||
*/
|
||||
/mob/verb/say_wrapper()
|
||||
set name = "say-indicator"
|
||||
set category = null
|
||||
set hidden = TRUE
|
||||
|
||||
set_typing_indicator(TRUE)
|
||||
var/message = input(src, "", "say (text)") as text|null
|
||||
set_typing_indicator(FALSE)
|
||||
if(!message)
|
||||
return
|
||||
|
||||
say_verb(message)
|
||||
|
||||
/mob/verb/say_verb(message as text)
|
||||
set name = "Say"
|
||||
set desc = "Say something to people who you can see."
|
||||
set category = VERB_CATEGORY_IC
|
||||
|
||||
// ensure length isn't too high
|
||||
message = sanitize_or_reflect(message, src, encode = FALSE)
|
||||
if(!message)
|
||||
return
|
||||
// clear typing indicator
|
||||
set_typing_indicator(FALSE)
|
||||
// perform say
|
||||
say(message)
|
||||
|
||||
//* Whisper *//
|
||||
|
||||
/**
|
||||
* Prompts for a whisper
|
||||
*/
|
||||
/mob/verb/whisper_wrapper()
|
||||
set name = "whisper-indicator"
|
||||
set category = null
|
||||
set hidden = TRUE
|
||||
|
||||
var/message = input(src, "", "whisper (text)") as text|null
|
||||
if(!message)
|
||||
return
|
||||
|
||||
whisper_verb(message)
|
||||
|
||||
/mob/verb/whisper_verb(message as text)
|
||||
set name = "Whisper"
|
||||
set desc = "Whisper something to people next to you."
|
||||
set category = VERB_CATEGORY_IC
|
||||
|
||||
// ensure length isn't too high
|
||||
message = sanitize_or_reflect(message, src, encode = FALSE)
|
||||
if(!message)
|
||||
return
|
||||
// clear typing indicator
|
||||
set_typing_indicator(FALSE)
|
||||
// perform say
|
||||
whisper(message)
|
||||
|
||||
//* Emote *//
|
||||
|
||||
/**
|
||||
* Prompts for a custom emote; uses typing indicator
|
||||
*/
|
||||
/mob/verb/me_wrapper()
|
||||
set name = "me-indicator"
|
||||
set category = null
|
||||
set hidden = TRUE
|
||||
|
||||
set_typing_indicator(TRUE)
|
||||
var/message = input(src, "", "me (text)") as message|null
|
||||
set_typing_indicator(FALSE)
|
||||
if(!message)
|
||||
return
|
||||
|
||||
me_verb(message)
|
||||
|
||||
/mob/verb/me_verb(message as message)
|
||||
set name = "Me"
|
||||
set desc = "Emote to people in view."
|
||||
set category = VERB_CATEGORY_IC
|
||||
|
||||
// ensure length isn't too high
|
||||
message = sanitize_or_reflect(message, src, encode = FALSE)
|
||||
if(!message)
|
||||
return
|
||||
// clear typing indicator
|
||||
set_typing_indicator(FALSE)
|
||||
// perform emote
|
||||
run_custom_emote(message, FALSE, FALSE, SAYCODE_TYPE_ALWAYS, with_overhead = TRUE)
|
||||
|
||||
//* Subtle Emote *//
|
||||
|
||||
/**
|
||||
* Prompts for a subtle
|
||||
*/
|
||||
/mob/verb/subtle_wrapper()
|
||||
set name = "subtle-wrapper"
|
||||
set category = null
|
||||
set hidden = TRUE
|
||||
|
||||
var/message = input(src, "", "subtle (text)") as message|null
|
||||
if(!message)
|
||||
return
|
||||
|
||||
subtle_verb(message)
|
||||
|
||||
/mob/verb/subtle_verb(message as message)
|
||||
set name = "Subtle"
|
||||
set desc = "Emote to people within 1 tile (3x3) of (or inside) yourself."
|
||||
set category = VERB_CATEGORY_IC
|
||||
|
||||
// ensure length isn't too high
|
||||
message = sanitize_or_reflect(message, src, encode = FALSE)
|
||||
if(!message)
|
||||
return
|
||||
// clear typing indicator
|
||||
set_typing_indicator(FALSE)
|
||||
// perform emote
|
||||
run_custom_emote(message, TRUE, FALSE, SAYCODE_TYPE_ALWAYS)
|
||||
|
||||
//* Subtler Anti Ghost Emote *//
|
||||
|
||||
/**
|
||||
* Prompts for a subtle
|
||||
*/
|
||||
/mob/verb/subtler_anti_ghost_wrapper()
|
||||
set name = "subtle-anti-ghost-wrapper"
|
||||
set category = null
|
||||
set hidden = TRUE
|
||||
|
||||
var/message = input(src, "", "subtler-anti-ghost (text)") as message|null
|
||||
if(!message)
|
||||
return
|
||||
|
||||
subtler_anti_ghost_verb(message)
|
||||
|
||||
/mob/verb/subtler_anti_ghost_verb(message as message)
|
||||
set name = "Subtler Anti-Ghost"
|
||||
set desc = "Emote to people within 1 tile (3x3) of (or inside) yourself. Ghosts cannot see this."
|
||||
set category = VERB_CATEGORY_IC
|
||||
|
||||
// ensure length isn't too high
|
||||
message = sanitize_or_reflect(message, src, encode = FALSE)
|
||||
if(!message)
|
||||
return
|
||||
// clear typing indicator
|
||||
set_typing_indicator(FALSE)
|
||||
// perform emote
|
||||
run_custom_emote(message, TRUE, TRUE, SAYCODE_TYPE_ALWAYS)
|
||||
33
code/modules/mob/mob-say.dm
Normal file
33
code/modules/mob/mob-say.dm
Normal file
@@ -0,0 +1,33 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/**
|
||||
* The transmission end of saycode.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets everyone (and everything) in a given range that can hear our say / emote.
|
||||
*
|
||||
* * Does not check if they are blind / deaf / whatever
|
||||
* * Not specifying global or exclude observers means observers can only hear if they're in range.
|
||||
* * This does **not** check ghost ears/sight prefs.
|
||||
*
|
||||
* @params
|
||||
* * range - tile radius; 0 is 1x1 on yourself, 1 is 3x3, ...
|
||||
* * global_observers - all observers are included
|
||||
* * exclude_observers - prevent **any** observer from being included. overrides `global_observers`.
|
||||
*/
|
||||
/mob/proc/saycode_view_query(range, global_observers, exclude_observers)
|
||||
. = get_hearers_in_view(range, src)
|
||||
|
||||
if(exclude_observers)
|
||||
for(var/mob/observer/observer in .)
|
||||
. -= observer
|
||||
else if(global_observers)
|
||||
var/list/already_gotten = list()
|
||||
for(var/mob/observer/observer in .)
|
||||
already_gotten[observer] = TRUE
|
||||
for(var/mob/observer/observer in GLOB.ghost_list)
|
||||
if(already_gotten[observer])
|
||||
continue
|
||||
. += observer
|
||||
@@ -7,6 +7,23 @@
|
||||
/// * Lazy list, see mob_movespeed.dm
|
||||
var/list/actionspeed_modifier_immunities
|
||||
|
||||
//* HUD (Atom) *//
|
||||
/// HUDs to initialize, typepaths
|
||||
var/list/atom_huds_to_initialize
|
||||
|
||||
//* Buckling *//
|
||||
/// Atom we're buckled to
|
||||
var/atom/movable/buckled
|
||||
/// Atom we're buckl**ing** to. Used to stop stuff like lava from incinerating those who are mid buckle.
|
||||
// todo: can this be put in an existing bitfield somewhere else?
|
||||
var/atom/movable/buckling
|
||||
|
||||
//* Emotes *//
|
||||
/// running emotes, associated to context the emote can set
|
||||
var/list/datum/emote/emotes_running
|
||||
/// our default emote classes
|
||||
var/emote_class = EMOTE_CLASS_IS_BODY
|
||||
|
||||
//* Impairments *//
|
||||
/// active feign_impairment types
|
||||
/// * lazy list
|
||||
|
||||
@@ -58,17 +58,6 @@
|
||||
/// current datum that's entirely intercepting our movements. only can have one - this is usually used with perspective.
|
||||
var/datum/movement_intercept
|
||||
|
||||
//* Buckling *//
|
||||
/// Atom we're buckled to
|
||||
var/atom/movable/buckled
|
||||
/// Atom we're buckl**ing** to. Used to stop stuff like lava from incinerating those who are mid buckle.
|
||||
// todo: can this be put in an existing bitfield somewhere else?
|
||||
var/atom/movable/buckling
|
||||
|
||||
//* HUD (Atom) *//
|
||||
/// HUDs to initialize, typepaths
|
||||
var/list/atom_huds_to_initialize
|
||||
|
||||
//* HUD *//
|
||||
/// active, opened storage
|
||||
// todo: doesn't clear from clients properly on logout, relies on login clearing screne.
|
||||
@@ -201,8 +190,6 @@
|
||||
*/
|
||||
var/atom/movable/screen/zone_sel/zone_sel = null
|
||||
|
||||
/// Allows all mobs to use the me verb by default, will have to manually specify they cannot.
|
||||
var/use_me = 1
|
||||
var/damageoverlaytemp = 0
|
||||
var/computer_id = null
|
||||
var/obj/machinery/machine = null
|
||||
|
||||
9
code/modules/mob/observer/dead/dead-emote.dm
Normal file
9
code/modules/mob/observer/dead/dead-emote.dm
Normal file
@@ -0,0 +1,9 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/mob/observer/dead/process_emote(datum/emote/emote, raw_parameter_string, datum/event_args/actor/actor, used_binding)
|
||||
actor.chat_feedback(
|
||||
SPAN_WARNING("Ghosts can't send normal emotes!"),
|
||||
target = src,
|
||||
)
|
||||
return FALSE
|
||||
54
code/modules/mob/observer/dead/dead-emote_custom.dm
Normal file
54
code/modules/mob/observer/dead/dead-emote_custom.dm
Normal file
@@ -0,0 +1,54 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2024 Citadel Station Developers *//
|
||||
|
||||
/mob/observer/dead/saycode_view_query(range, global_observers, exclude_observers)
|
||||
if(global_observers)
|
||||
return GLOB.ghost_list.Copy()
|
||||
. = list()
|
||||
for(var/mob/observer/observer as anything in GLOB.ghost_list)
|
||||
if(get_dist(src, observer) <= range)
|
||||
. += observer
|
||||
|
||||
/mob/observer/dead/run_custom_emote(emote_text, subtle, anti_ghost, saycode_type, datum/event_args/actor/actor, with_overhead)
|
||||
// Now watch, as I violate a codebase best practice for shits and giggles.
|
||||
if(!usr)
|
||||
return FALSE
|
||||
if(usr != src)
|
||||
to_chat(usr, SPAN_DANGER("How did you just try to emote as another player's ghost?"))
|
||||
return FALSE
|
||||
// Validated to be 'self' at this point.
|
||||
if(!client)
|
||||
return FALSE
|
||||
if(client.prefs.muted & MUTE_DEADCHAT)
|
||||
to_chat(src, SPAN_DANGER("You cannot send deadchat emotes (muted)."))
|
||||
return FALSE
|
||||
if(!get_preference_toggle(/datum/game_preference_toggle/chat/dsay))
|
||||
to_chat(src, SPAN_DANGER("You have deadchat muted."))
|
||||
return FALSE
|
||||
if(!config_legacy.dsay_allowed && !check_rights(show_msg = FALSE, C = client))
|
||||
to_chat(src, SPAN_DANGER("Deadchat is globally muted."))
|
||||
return FALSE
|
||||
if(SSbans.t_is_role_banned_ckey(ckey, role = BAN_ROLE_OOC))
|
||||
to_chat(src, SPAN_DANGER("You are banned from OOC and deadchat."))
|
||||
return FALSE
|
||||
if(subtle)
|
||||
to_chat(src, SPAN_DANGER("Why are you trying to subtle emote as a ghost?"))
|
||||
return FALSE
|
||||
if(anti_ghost)
|
||||
to_chat(src, SPAN_DANGER("Why are you trying to anti-ghost emote as a ghost?"))
|
||||
return FALSE
|
||||
|
||||
log_ghostemote(emote_text, src)
|
||||
var/raw_html = process_custom_emote(emote_text, subtle, anti_ghost, saycode_type, with_overhead)
|
||||
if(!raw_html)
|
||||
return
|
||||
emit_custom_emote(raw_html, subtle, anti_ghost, saycode_type, with_overhead)
|
||||
|
||||
/mob/observer/dead/process_custom_emote(emote_text, subtle, anti_ghost, saycode_type, with_overhead)
|
||||
. = emote_text
|
||||
. = html_encode(emote_text)
|
||||
. = say_emphasis(.)
|
||||
. = SPAN_DEADSAY(emoji_parse(.))
|
||||
|
||||
/mob/observer/dead/emit_custom_emote(raw_html, subtle, anti_ghost, saycode_type, with_overhead)
|
||||
say_dead_direct(raw_html, src)
|
||||
@@ -1,5 +1,5 @@
|
||||
/// all player ghosts
|
||||
GLOBAL_LIST_EMPTY(observer_list)
|
||||
GLOBAL_LIST_EMPTY(ghost_list)
|
||||
|
||||
/mob/observer/dead
|
||||
name = "ghost"
|
||||
@@ -101,15 +101,15 @@ GLOBAL_LIST_EMPTY(observer_list)
|
||||
//For a better follow selection:
|
||||
|
||||
/mob/observer/dead/Initialize(mapload)
|
||||
GLOB.observer_list += src
|
||||
GLOB.ghost_list += src
|
||||
var/mob/body = loc
|
||||
see_invisible = SEE_INVISIBLE_OBSERVER
|
||||
see_in_dark = world.view //I mean. I don't even know if byond has occlusion culling... but...
|
||||
plane = OBSERVER_PLANE //Why doesn't the var above work...???
|
||||
add_verb(src, /mob/observer/dead/proc/dead_tele)
|
||||
|
||||
var/turf/T
|
||||
if(ismob(body))
|
||||
var/turf/T
|
||||
T = get_turf(body) //Where is the body located?
|
||||
attack_log = body.attack_log //preserve our attack logs by copying them to our ghost
|
||||
|
||||
@@ -142,11 +142,11 @@ GLOBAL_LIST_EMPTY(observer_list)
|
||||
|
||||
mind = body.mind //we don't transfer the mind but we keep a reference to it.
|
||||
|
||||
if(!T)
|
||||
T = SSjob.get_latejoin_spawnpoint()
|
||||
if(!T)
|
||||
T = locate(1,1,1)
|
||||
forceMove(T)
|
||||
if(!T)
|
||||
T = SSjob.get_latejoin_spawnpoint()
|
||||
if(!T)
|
||||
T = locate(1,1,1)
|
||||
forceMove(T)
|
||||
|
||||
if(!name) //To prevent nameless ghosts
|
||||
name = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
|
||||
@@ -154,7 +154,7 @@ GLOBAL_LIST_EMPTY(observer_list)
|
||||
return ..()
|
||||
|
||||
/mob/observer/dead/Destroy()
|
||||
GLOB.observer_list -= src
|
||||
GLOB.ghost_list -= src
|
||||
return ..()
|
||||
|
||||
/mob/observer/dead/Topic(href, href_list)
|
||||
@@ -790,7 +790,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
if(sound)
|
||||
SEND_SOUND(src, sound(sound))
|
||||
|
||||
/mob/dead/observer/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE)
|
||||
/mob/observer/dead/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE)
|
||||
return isAdminGhostAI(usr)
|
||||
|
||||
/mob/observer/dead/verb/nifjoin()
|
||||
|
||||
@@ -14,50 +14,3 @@
|
||||
return
|
||||
|
||||
. = src.say_dead(message)
|
||||
|
||||
|
||||
/mob/observer/dead/emote(var/act, var/type, var/message)
|
||||
//message = sanitize(message) - already sanitized in verb/me_verb()
|
||||
|
||||
if(!message)
|
||||
return
|
||||
|
||||
if(act != "me")
|
||||
return
|
||||
|
||||
log_ghostemote(message, src)
|
||||
|
||||
if(src.client)
|
||||
if(message)
|
||||
client.handle_spam_prevention(MUTE_DEADCHAT)
|
||||
if(src.client.prefs.muted & MUTE_DEADCHAT)
|
||||
to_chat(src, "<font color='red'>You cannot emote in deadchat (muted).</font>")
|
||||
return
|
||||
|
||||
. = src.emote_dead(message)
|
||||
|
||||
/*
|
||||
for (var/mob/M in hearers(null, null))
|
||||
if (!M.stat)
|
||||
if(M.job == "Chaplain")
|
||||
if (prob (49))
|
||||
M.show_message("<span class='game'><i>You hear muffled speech... but nothing is there...</i></span>", 2)
|
||||
if(prob(20))
|
||||
playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1)
|
||||
else
|
||||
M.show_message("<span class='game'><i>You hear muffled speech... you can almost make out some words...</i></span>", 2)
|
||||
// M.show_message("<span class='game'><i>[stutter(message)]</i></span>", 2)
|
||||
if(prob(30))
|
||||
playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1)
|
||||
else
|
||||
if (prob(50))
|
||||
return
|
||||
else if (prob (95))
|
||||
M.show_message("<span class='game'><i>You hear muffled speech... but nothing is there...</i></span>", 2)
|
||||
if(prob(20))
|
||||
playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1)
|
||||
else
|
||||
M.show_message("<span class='game'><i>You hear muffled speech... you can almost make out some words...</i></span>", 2)
|
||||
// M.show_message("<span class='game'><i>[stutter(message)]</i></span>", 2)
|
||||
playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1)
|
||||
*/
|
||||
|
||||
@@ -252,4 +252,4 @@
|
||||
* TODO: this doesn't work on client global planes like admin plane.
|
||||
*/
|
||||
/mob/proc/can_see_plane(val)
|
||||
return val <= BYOND_PLANE || val >= HUD_PLANE || self_perspective.is_plane_visible(val)
|
||||
return val <= BYOND_PLANE || val >= HUD_PLANE || self_perspective?.is_plane_visible(val)
|
||||
|
||||
@@ -1,134 +1,3 @@
|
||||
//////////////////////////////////////////////////////
|
||||
////////////////////SUBTLE COMMAND////////////////////
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
/mob/verb/me_verb_subtle(message as message) //This would normally go in say.dm
|
||||
set name = "Subtle"
|
||||
set category = VERB_CATEGORY_IC
|
||||
set desc = "Emote to nearby people (and your pred/prey)"
|
||||
|
||||
message = sanitize_or_reflect(message,src) // Reflect too-long messages (within reason)
|
||||
if(!message)
|
||||
return
|
||||
|
||||
set_typing_indicator(FALSE)
|
||||
if(use_me)
|
||||
usr.emote_vr("me",4,message)
|
||||
else
|
||||
usr.emote_vr(message)
|
||||
|
||||
/mob/proc/custom_emote_vr(var/m_type=1,var/message = null) //This would normally go in emote.dm
|
||||
if(stat || !use_me && usr == src)
|
||||
to_chat(src, "You are unable to emote.")
|
||||
return
|
||||
|
||||
var/muzzled = is_muzzled()
|
||||
if(m_type == 2 && muzzled) return
|
||||
|
||||
var/input
|
||||
if(!message)
|
||||
input = sanitize_or_reflect(input(src,"Choose an emote to display.") as text|null, src)
|
||||
else
|
||||
input = message
|
||||
|
||||
if(input)
|
||||
log_subtle(message,src)
|
||||
message = "<B>[src]</B> <I>[input]</I>"
|
||||
else
|
||||
return
|
||||
|
||||
if (message)
|
||||
message = say_emphasis(message)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_SUBTLE_EMOTE, src, message)
|
||||
|
||||
var/list/vis = get_mobs_and_objs_in_view_fast(get_turf(src),1,2) //Turf, Range, and type 2 is emote
|
||||
var/list/vis_mobs = vis["mobs"]
|
||||
var/list/vis_objs = vis["objs"]
|
||||
|
||||
for(var/vismob in vis_mobs)
|
||||
var/mob/M = vismob
|
||||
if(istype(vismob, /mob/observer))
|
||||
if(M.client && !M.client.get_preference_toggle(/datum/game_preference_toggle/observer/ghost_subtle))
|
||||
continue
|
||||
spawn(0)
|
||||
M.show_message(message, SAYCODE_TYPE_ALWAYS)
|
||||
|
||||
for(var/visobj in vis_objs)
|
||||
var/obj/O = visobj
|
||||
spawn(0)
|
||||
O.see_emote(src, message, 2)
|
||||
|
||||
var/list/other_viewers = get_hearers_in_view(3, source = src)
|
||||
for(var/mob/M in other_viewers - vis_mobs)
|
||||
M.show_message(SPAN_SMALL("<i>[src] does something [pick("subtly", "discreetly", "hidden", "obscured")].</i>"), SAYCODE_TYPE_VISIBLE)
|
||||
|
||||
/mob/proc/emote_vr(var/act, var/type, var/message) //This would normally go in say.dm
|
||||
if(act == "me")
|
||||
return custom_emote_vr(type, message)
|
||||
|
||||
//////// SHIT COPYPASTE CODE FOR SUBTLER ANTI GHOST
|
||||
|
||||
/mob/verb/subtler_anti_ghost(message as message) //This would normally go in say.dm
|
||||
set name = "Subtler Anti Ghost"
|
||||
set category = VERB_CATEGORY_IC
|
||||
set desc = "Emote to nearby people (and your pred/prey), but ghosts can't see it."
|
||||
|
||||
message = sanitize_or_reflect(message,src) // Reflect too-long messages (within reason)
|
||||
if(!message)
|
||||
return
|
||||
|
||||
set_typing_indicator(FALSE)
|
||||
run_subtler(message)
|
||||
|
||||
/mob/proc/run_subtler(message)
|
||||
if(stat || !use_me && usr == src)
|
||||
to_chat(src, "You are unable to emote.")
|
||||
return
|
||||
|
||||
var/input
|
||||
if(!message)
|
||||
input = sanitize_or_reflect(input(src,"Choose an emote to display.") as text|null, src)
|
||||
else
|
||||
input = message
|
||||
|
||||
if(input)
|
||||
log_subtle_anti_ghost(message,src)
|
||||
message = "<B>[src]</B> " + SPAN_SINGING(input)
|
||||
else
|
||||
return
|
||||
|
||||
if (message)
|
||||
message = say_emphasis(message)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_SUBTLE_EMOTE, src, message)
|
||||
var/turf_origin = get_turf(src)
|
||||
|
||||
var/list/vis = get_mobs_and_objs_in_view_fast(turf_origin,1,2) //Turf, Range, and type 2 is emote
|
||||
var/list/vis_mobs = vis["mobs"]
|
||||
var/list/vis_objs = vis["objs"]
|
||||
|
||||
for(var/vismob in vis_mobs)
|
||||
var/mob/M = vismob
|
||||
if(istype(vismob, /mob/observer))
|
||||
continue
|
||||
if(M.stat == DEAD)
|
||||
continue // get mobs and objs in view fast is shitty; say refactor will deal with that
|
||||
if(M != src)
|
||||
M.playsound_local(turf_origin, 'sound/effects/subtle_emote.ogg', 100)
|
||||
M.show_message(message, SAYCODE_TYPE_ALWAYS)
|
||||
|
||||
for(var/visobj in vis_objs)
|
||||
var/obj/O = visobj
|
||||
O.see_emote(src, message, 2)
|
||||
|
||||
var/list/other_viewers = get_hearers_in_view(3, source = src)
|
||||
for(var/mob/M in (other_viewers - vis_mobs))
|
||||
if(istype(M, /mob/observer))
|
||||
continue
|
||||
M.show_message(SPAN_SMALL("<i>[src] does something [pick("subtly", "discreetly", "hidden", "obscured")].</i>"), SAYCODE_TYPE_VISIBLE)
|
||||
|
||||
/////// END
|
||||
|
||||
//////// SHITTIER COPYPASTE CODE FOR VORE SUBTLE
|
||||
/mob/living/verb/subtle_vore(message as message)
|
||||
set name = "Subtle Vore"
|
||||
set category = "Vore"
|
||||
@@ -142,7 +11,7 @@
|
||||
run_subtle_vore(message)
|
||||
|
||||
/mob/living/proc/run_subtle_vore(message)
|
||||
if(stat || !use_me && usr == src)
|
||||
if(stat)
|
||||
to_chat(src, "You are unable to emote.")
|
||||
return
|
||||
|
||||
@@ -160,7 +29,6 @@
|
||||
|
||||
if (message)
|
||||
message = say_emphasis(message)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_SUBTLE_EMOTE, src, message)
|
||||
|
||||
var/list/vis_mobs = new()
|
||||
var/list/vis_objs = new()
|
||||
@@ -199,17 +67,16 @@
|
||||
var/obj/O = visobj
|
||||
O.see_emote(src, message, 2)
|
||||
|
||||
//////// END
|
||||
|
||||
#define MAX_HUGE_MESSAGE_LEN 8192
|
||||
#define POST_DELIMITER_STR "\<\>"
|
||||
/proc/sanitize_or_reflect(message,user)
|
||||
// TODO: NUKE THIS PROC!!
|
||||
/proc/sanitize_or_reflect(message, user, encode)
|
||||
//Way too long to send
|
||||
if(length_char(message) > MAX_HUGE_MESSAGE_LEN)
|
||||
fail_to_chat(user, null)
|
||||
return
|
||||
|
||||
message = sanitize(message, max_length = MAX_HUGE_MESSAGE_LEN)
|
||||
message = sanitize(message, max_length = MAX_HUGE_MESSAGE_LEN, encode = encode)
|
||||
|
||||
//Came back still too long to send
|
||||
if(length_char(message) > MAX_MESSAGE_LEN)
|
||||
|
||||
@@ -20,25 +20,3 @@
|
||||
init_typing_indicator()
|
||||
add_overlay(typing_indicator, TRUE)
|
||||
typing = TRUE
|
||||
|
||||
/mob/verb/say_wrapper()
|
||||
set name = ".Say"
|
||||
set hidden = 1
|
||||
|
||||
set_typing_indicator(TRUE)
|
||||
var/message = input("","say (text)") as text|null
|
||||
set_typing_indicator(FALSE)
|
||||
|
||||
if(message)
|
||||
say_verb(message)
|
||||
|
||||
/mob/verb/me_wrapper()
|
||||
set name = ".Me"
|
||||
set hidden = 1
|
||||
|
||||
set_typing_indicator(TRUE)
|
||||
var/message = input("","me (text)") as message|null
|
||||
set_typing_indicator(FALSE)
|
||||
|
||||
if(message)
|
||||
me_verb(message)
|
||||
|
||||
@@ -129,12 +129,13 @@
|
||||
|
||||
log_nsay(message,nif.human.real_name,sender)
|
||||
|
||||
/datum/nifsoft/soulcatcher/proc/emote_into(var/message, var/mob/living/sender, var/mob/eyeobj)
|
||||
/datum/nifsoft/soulcatcher/proc/emote_into(var/message, var/mob/living/sender, var/mob/eyeobj, skip_name)
|
||||
message = trim(message)
|
||||
if(!length(message))
|
||||
return
|
||||
message = say_emphasis(message)
|
||||
var/sender_name = eyeobj ? eyeobj.name : sender.name
|
||||
var/maybe_sender_name = skip_name ? "" : "<b>[sender_name]</b> "
|
||||
|
||||
//AR Projecting
|
||||
if(eyeobj)
|
||||
@@ -142,9 +143,9 @@
|
||||
|
||||
//Not AR Projecting
|
||||
else
|
||||
to_chat(nif.human,"<span class='emote nif'><b>\[[icon2html(thing = nif.big_icon, target = nif.human)]NIF\]</b> <b>[sender_name]</b> [message]</span>")
|
||||
to_chat(nif.human,"<span class='emote nif'><b>\[[icon2html(thing = nif.big_icon, target = nif.human)]NIF\]</b> [maybe_sender_name][message]</span>")
|
||||
for(var/mob/living/carbon/brain/caught_soul/CS as anything in brainmobs)
|
||||
to_chat(CS,"<span class='emote nif'><b>\[[icon2html(thing = nif.big_icon, target = CS)]NIF\]</b> <b>[sender_name]</b> [message]</span>")
|
||||
to_chat(CS,"<span class='emote nif'><b>\[[icon2html(thing = nif.big_icon, target = CS)]NIF\]</b> [maybe_sender_name][message]</span>")
|
||||
|
||||
log_nme(message,nif.human.real_name,sender)
|
||||
|
||||
@@ -346,7 +347,6 @@
|
||||
/mob/living/carbon/brain/caught_soul
|
||||
name = "recorded mind"
|
||||
desc = "A mind recorded and being played on digital hardware."
|
||||
use_me = 1
|
||||
var/ext_deaf = FALSE //Forbidden from 'ear' access on host
|
||||
var/ext_blind = FALSE //Forbidden from 'eye' access on host
|
||||
var/parent_mob = FALSE //If we've captured our owner
|
||||
@@ -431,14 +431,12 @@
|
||||
return FALSE
|
||||
..()
|
||||
|
||||
/mob/living/carbon/brain/caught_soul/me_verb_subtle()
|
||||
/mob/living/carbon/brain/caught_soul/subtle_verb()
|
||||
set hidden = TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/brain/caught_soul/whisper()
|
||||
set hidden = TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/brain/caught_soul/face_atom(var/atom/A)
|
||||
@@ -474,6 +472,9 @@
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/brain/caught_soul/emote(var/act,var/m_type=1,var/message = null)
|
||||
. = ..()
|
||||
if(. == "stop")
|
||||
return
|
||||
if(silent)
|
||||
return FALSE
|
||||
if (act == "me")
|
||||
@@ -491,10 +492,11 @@
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/brain/caught_soul/custom_emote(var/m_type, var/message)
|
||||
if(silent)
|
||||
return FALSE
|
||||
soulcatcher.emote_into(message,src,eyeobj)
|
||||
/mob/living/carbon/brain/caught_soul/emit_custom_emote(raw_html, subtle, anti_ghost, saycode_type, with_overhead)
|
||||
if(subtle || anti_ghost)
|
||||
to_chat(src, SPAN_BOLDANNOUNCE("Your [SPAN_TOOLTIP(raw_html, "message")] was not sent. Soulcatchers do not currently support subtle or subtler-anti-ghost."))
|
||||
return
|
||||
soulcatcher.emote_into(raw_html, src, eyeobj, skip_name = TRUE)
|
||||
|
||||
/mob/living/carbon/brain/caught_soul/resist()
|
||||
set name = "Resist"
|
||||
|
||||
@@ -70,6 +70,9 @@
|
||||
buckle_allowed = TRUE
|
||||
buckle_flags = BUCKLING_GROUND_HOIST //blobsurfing
|
||||
|
||||
/mob/living/simple_mob/protean_blob/isSynthetic()
|
||||
return TRUE
|
||||
|
||||
/datum/say_list/protean_blob
|
||||
speak = list("Blrb?","Sqrsh.","Glrsh!")
|
||||
emote_hear = list("squishes softly","spluts quietly","makes wet noises")
|
||||
@@ -432,7 +435,7 @@
|
||||
if(back)
|
||||
H.equip_to_slot_if_possible(prig,SLOT_ID_BACK, INV_OP_FORCE | INV_OP_DIRECTLY_EQUIPPING | INV_OP_SHOULD_NOT_INTERCEPT | INV_OP_SILENT)
|
||||
return
|
||||
|
||||
|
||||
|
||||
if(isturf(loc))
|
||||
var/obj/item/hardsuit/protean/prig
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "characteristics.dm"
|
||||
#include "inventory.dm"
|
||||
#include "sprite_accessories.dm"
|
||||
#include "subtler_anti_ghost.dm"
|
||||
|
||||
93
code/unit_tests/mob/subtler_anti_ghost.dm
Normal file
93
code/unit_tests/mob/subtler_anti_ghost.dm
Normal file
@@ -0,0 +1,93 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2025 Citadel Station Developers *//
|
||||
|
||||
/datum/unit_test/subtler_anti_ghost_still_works
|
||||
var/intended_recipient_heard_subtler = FALSE
|
||||
var/unintended_recipient_heard_subtler = FALSE
|
||||
var/intended_recipient_heard_normal = FALSE
|
||||
var/unintended_recipient_heard_normal = FALSE
|
||||
var/send_str_subtler = "isnt-there-someone-you-forgot-to-ask"
|
||||
var/send_str_normal = "kynde-did-nothing-wrong"
|
||||
|
||||
var/mob/speaker
|
||||
|
||||
/datum/unit_test/subtler_anti_ghost_still_works/Destroy()
|
||||
if(!QDELETED(speaker))
|
||||
qdel(speaker)
|
||||
speaker = null
|
||||
return ..()
|
||||
|
||||
/datum/unit_test/subtler_anti_ghost_still_works/Run()
|
||||
var/mob/living/carbon/human/speaker = allocate(/mob/living/carbon/human)
|
||||
var/mob/living/carbon/human/listener = allocate(/mob/living/carbon/human)
|
||||
var/mob/observer/dead/the_myth_of_consensual_handholding = allocate(/mob/observer/dead)
|
||||
|
||||
src.speaker = speaker
|
||||
RegisterSignal(listener, COMSIG_MOB_ON_RECEIVE_CUSTOM_EMOTE, PROC_REF(on_intended_hear))
|
||||
RegisterSignal(the_myth_of_consensual_handholding, COMSIG_MOB_ON_RECEIVE_CUSTOM_EMOTE, PROC_REF(on_unintended_hear))
|
||||
|
||||
speaker.forceMove(run_loc_floor_bottom_left)
|
||||
|
||||
the_myth_of_consensual_handholding.forceMove(run_loc_floor_bottom_left)
|
||||
intended_recipient_heard_normal = intended_recipient_heard_subtler = FALSE
|
||||
unintended_recipient_heard_normal = unintended_recipient_heard_subtler = FALSE
|
||||
speaker.subtler_anti_ghost_verb(send_str_subtler)
|
||||
speaker.me_verb(send_str_normal)
|
||||
|
||||
if(!intended_recipient_heard_subtler)
|
||||
Fail("A person next to the couldn't hear the subtler emote")
|
||||
if(!intended_recipient_heard_normal)
|
||||
Fail("A person next to the speaker couldn't hear the normal emote")
|
||||
if(unintended_recipient_heard_subtler)
|
||||
Fail("A ghost next to the speaker could hear the subtler emote")
|
||||
if(!unintended_recipient_heard_normal)
|
||||
Fail("A ghost next to the speaker couldn't hear the normal emote")
|
||||
|
||||
var/distance = world_view_max_number() + 2
|
||||
var/turf/some_distance_away = locate(the_myth_of_consensual_handholding.x + distance, the_myth_of_consensual_handholding.y + distance, the_myth_of_consensual_handholding.z)
|
||||
if(!some_distance_away)
|
||||
Fail("some_distance_away wasn't found")
|
||||
the_myth_of_consensual_handholding.forceMove(some_distance_away)
|
||||
intended_recipient_heard_normal = intended_recipient_heard_subtler = FALSE
|
||||
unintended_recipient_heard_normal = unintended_recipient_heard_subtler = FALSE
|
||||
speaker.me_verb(send_str_normal)
|
||||
speaker.subtler_anti_ghost_verb(send_str_subtler)
|
||||
|
||||
if(unintended_recipient_heard_subtler)
|
||||
Fail("A ghost [distance] tiles away from the speaker could hear the subtler emote")
|
||||
if(!unintended_recipient_heard_normal)
|
||||
Fail("A ghost [distance] tiles away from the speaker couldn't hear the normal emote")
|
||||
|
||||
var/turf/one_z_away = locate(the_myth_of_consensual_handholding.x, the_myth_of_consensual_handholding.y, the_myth_of_consensual_handholding.z - 1)
|
||||
if(!one_z_away)
|
||||
Fail("one_z_away wasn't found")
|
||||
the_myth_of_consensual_handholding.forceMove(one_z_away)
|
||||
intended_recipient_heard_normal = intended_recipient_heard_subtler = FALSE
|
||||
unintended_recipient_heard_normal = unintended_recipient_heard_subtler = FALSE
|
||||
speaker.me_verb(send_str_normal)
|
||||
speaker.subtler_anti_ghost_verb(send_str_subtler)
|
||||
|
||||
if(unintended_recipient_heard_subtler)
|
||||
Fail("A ghost a z-level from the speaker could hear the subtler emote")
|
||||
if(!unintended_recipient_heard_normal)
|
||||
Fail("A ghost a z-level from the speaker couldn't hear the normal emote")
|
||||
|
||||
/datum/unit_test/subtler_anti_ghost_still_works/proc/on_intended_hear(datum/source, mob/from_mob, raw_html, subtle, anti_ghost, saycode_type)
|
||||
if(from_mob != speaker)
|
||||
return
|
||||
if(findtext_char(raw_html, send_str_normal))
|
||||
intended_recipient_heard_normal = TRUE
|
||||
else if(findtext_char(raw_html, send_str_subtler))
|
||||
intended_recipient_heard_subtler = TRUE
|
||||
else
|
||||
Fail("Intended recipient heard something other than the predicted lines: [raw_html].")
|
||||
|
||||
/datum/unit_test/subtler_anti_ghost_still_works/proc/on_unintended_hear(datum/source, mob/from_mob, raw_html, subtle, anti_ghost, saycode_type)
|
||||
if(from_mob != speaker)
|
||||
return
|
||||
if(findtext_char(raw_html, send_str_normal))
|
||||
unintended_recipient_heard_normal = TRUE
|
||||
else if(findtext_char(raw_html, send_str_subtler))
|
||||
unintended_recipient_heard_subtler = TRUE
|
||||
else
|
||||
Fail("Unintended recipient heard something other than the predicted lines: [raw_html].")
|
||||
BIN
sound/soundbytes/talksounds/alien-1/lure_1.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/lure_1.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/lure_2.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/lure_2.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/lure_3.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/lure_3.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/lure_4.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/lure_4.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/lure_5.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/lure_5.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/lyst_1.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/lyst_1.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/lyst_2.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/lyst_2.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/lyst_3.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/lyst_3.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/lyst_4.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/lyst_4.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/lyst_5.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/lyst_5.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/lyst_6.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/lyst_6.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/void_1.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/void_1.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/void_2.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/void_2.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/void_3.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/void_3.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/vomva_1.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/vomva_1.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/vomva_2.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/vomva_2.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/vomva_3.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/vomva_3.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/alien-1/vomva_4.ogg
Normal file
BIN
sound/soundbytes/talksounds/alien-1/vomva_4.ogg
Normal file
Binary file not shown.
BIN
sound/soundbytes/talksounds/generic/a.ogg
Normal file
BIN
sound/soundbytes/talksounds/generic/a.ogg
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user