Datumized Emotes (#17544)

* Add raw tg emote datums

* Some more initial implementation

* First (big) commit

* More reworks, most emotes seem to work but cooldowns are weird

* Add the remaining emote species

* Add simple mobs

* Update defines, add more comments

* Remove unnecessary intentional calls

* Fix some bugs, add more functionality
- Silicon mobs/bots can't use all the living emotes
- Sound volume can now be specified for emotes
- Added a define for emotes to not go thru runechat
- Reorganized some emotes
- Some human emotes that need breath will gasp
- IPCs can beep boop
- Restore power warn for robits
- Sneezing and coughing have sound effects

* Fixes emote species separation not working in *help

* Reorganize emotes based on what's available on paradise

* mouthful mode

* Update implants to use emote signals

* Update species whitelist to use a typecache

* Cleanups

* More small changes
- Remove old extraneous typecache
- Reconfigure drask emotes
- Make all mime emotes visible (since they're silent)

* Remove old emote functions

* Update emote sounds, volume

* Rework more emotes into EMOTE_VISIBLE

* *rumble*

* More slight testing and cleanup
- Drop audio emote cooldown from 10 to 5 seconds
- Change clapping behaivor slightly, putting it into run_emote
- Update some emote flags here and there
- Fix up johnny, though remind me why this one exists?

* Fix indentation, missing typecast

* fix some returns

* More review

* Rename emote files

* Add'l review

* Even more emote fixes!

- Move defines out into an emote define file
- Integrate audio and general emote cooldowns
- change some 1 and 2 into visible/audible
- Try to fix monkey screech

* Add ability for admins to mute users' emotes.

* Rename cooldowns, add general mob emote cooldown.

* Fix flip not always geting the right message

* Add some emote target handling, docs

* Fix admin rights, indentation

* Update emote.dm

set default mode to ANY

* General implant fixes

- The way implant triggers are handled is now improved, with separate checks for death and emotes instead of just checking deathgasp.
- Implants can choose to be triggered for the first death or for every death.
- Voice of God play dead now activates sad trombone

read: voice of god can now no longer lowtiergod nukies

* Bunch of other changes and bugfixes

- Adds number flag for behavior
- Reworks how muzzling/vocalizing emotes works
- Breaks out sound effects
- Drops cooldown to 1.5s

* Fix people being able to snore/nightmare while awake.

* Bump paralysis on living emotes

* First review pass

* Clean up implants (while we're here) and fix compile errors

* in living error

* More outstanding review fixes

* use more isx() checks

* Add pre-emote signal, try_run_emote()

* Prevent silicons from playing their deathgasp multiple times

* Add emote postfix behavior for adding parameters to non-message params.

Also adds a signal to intercept emote actions.

* Fix linter complaints

* Remove new player checks on GLOB.dead_mob_list

* Fix species emotes not being distinguished, remove weird legacy code

* monkey ball

* better docs == better code

* Fix audio cooldown, silicon emotes

* Fix ghost emotes (don't worry they're staying)

* Restore spin to 2 seconds

* oh johnny boy

* Make fainting last two seconds instead of .2 seconds

* Remove extra highfive message

* Tick friendly emotes

* Fix up friendly emotes, ghost emotes

* Add some emote message safeguards, prevent flip from showing twice

* Fix ghost vision message format

* Fix hands_use_check on non-carbon mobs

* Bring emotes in line with say re. oxyloss

* Add option for death implants to not trigger on gib

* Try adding some unit testing

* Include emote unit tests

* More attempts at unit testing

* More attempts at unit testing?

* forget it this is fine

* Housekeeping

* Little bit more

* Remove extra bolding from ghostsight emotes

* More sanity checks, fix snore

* Remove stack trace when unintentional emote fails

* Update code/modules/mob/living/silicon/silicon_emote.dm

oops

Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>

* More implant cleanups

* Oh I missed this

* Silence wagging, more review fixes

* Oops 2

* ensure everything can swear

* High-five fixes and status effect stuff
- Adds new on_timeout() function that gets triggered when a status effect expires
- Fixes up passing arguments to status effects
- Ensures high-five explosions don't kill the wizards

* More review stuff
- Add a stat to text to make things easier
- Make it harder to delete emotes
- BIG DANGER
- pose can no longer be set while unconscious

* Remove extra high five logic, godmode changes

* forgor

* Fix gasp not working

* Update docs for good measure

* Some review and custom emote fixes

* Fixes death alarms being broken

* Better handle stat_allowed, more review comments.

* ..() conventions

* This is why unit tests are nice

* Remove drone snowflake emote stuff

* Linting

* No more flipping on the ground

* Snap doesn't require hands free

* Does it make complete sense? no, but it's Fun

* Apply suggestions from code review

Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>

* Fix revenant messages, power warning

* epic webedit fail, laugh at this user

Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>
This commit is contained in:
Luc
2022-06-14 15:06:24 -07:00
committed by GitHub
parent 9dc65f5cf0
commit 747d8111ca
82 changed files with 3035 additions and 2331 deletions
+1
View File
@@ -141,6 +141,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_PRAY]'><font color='[check_mute(M.client.ckey, MUTE_PRAY) ? "red" : "#6685f5"]'>PRAY</font></a> |
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_ADMINHELP]'><font color='[check_mute(M.client.ckey, MUTE_ADMINHELP) ? "red" : "#6685f5"]'>ADMINHELP</font></a> |
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_DEADCHAT]'><font color='[check_mute(M.client.ckey, MUTE_DEADCHAT) ?" red" : "#6685f5"]'>DEADCHAT</font></a>]
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_EMOTE]'><font color='[check_mute(M.client.ckey, MUTE_EMOTE) ?" red" : "#6685f5"]'>EMOTE</font></a>]
(<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_ALL]'><font color='[check_mute(M.client.ckey, MUTE_ALL) ? "red" : "#6685f5"]'>toggle all</font></a>)
"}
+16 -7
View File
@@ -222,13 +222,22 @@
var/mute_string
switch(mute_type)
if(MUTE_IC) mute_string = "IC (say and emote)"
if(MUTE_OOC) mute_string = "OOC"
if(MUTE_PRAY) mute_string = "pray"
if(MUTE_ADMINHELP) mute_string = "adminhelp, admin PM and ASAY"
if(MUTE_DEADCHAT) mute_string = "deadchat and DSAY"
if(MUTE_ALL) mute_string = "everything"
else return
if(MUTE_IC)
mute_string = "IC (say and emote)"
if(MUTE_OOC)
mute_string = "OOC"
if(MUTE_PRAY)
mute_string = "pray"
if(MUTE_ADMINHELP)
mute_string = "adminhelp, admin PM and ASAY"
if(MUTE_DEADCHAT)
mute_string = "deadchat and DSAY"
if(MUTE_EMOTE)
mute_string = "emote"
if(MUTE_ALL)
mute_string = "everything"
else
return
if(automute)
muteunmute = "auto-muted"
+1 -1
View File
@@ -5,7 +5,7 @@
name = "exile implant"
desc = "Prevents you from returning from away missions"
origin_tech = "materials=2;biotech=3;magnets=2;bluespace=3"
activated = 0
activated = IMPLANT_ACTIVATED_PASSIVE
/obj/item/implant/exile/get_data()
var/dat = {"<b>Implant Specifications:</b><BR>
+1 -2
View File
@@ -43,8 +43,7 @@
nightmare()
if(ishuman(src))
if(prob(10))
custom_emote(1,"writhes in [p_their()] sleep.")
dir = pick(GLOB.cardinal)
emote("nightmare")
/mob/living/carbon/proc/experience_dream(dream_image, isNightmare)
dreaming--
-22
View File
@@ -6,28 +6,6 @@
return say_dead(message)
/mob/dead/observer/emote(act, type, message, force)
message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN))
if(!message)
return
if(act != "me")
return
log_ghostemote(message, src)
if(src.client)
if(check_mute(client.ckey, MUTE_DEADCHAT))
to_chat(src, "<span class='warning'>You cannot emote in deadchat (muted).</span>")
return
if(src.client.handle_spam_prevention(message, MUTE_DEADCHAT))
return
. = src.emote_dead(message)
/mob/dead/observer/handle_track(message, verb = "says", mob/speaker = null, speaker_name, atom/follow_target, hard_to_hear)
return "[speaker_name] ([ghost_follow_link(follow_target, ghost=src)])"
-150
View File
@@ -1,150 +0,0 @@
#define EMOTE_COOLDOWN 20 //Time in deciseconds that the cooldown lasts
//Emote Cooldown System (it's so simple!)
/mob/proc/handle_emote_CD(cooldown = EMOTE_COOLDOWN)
if(emote_cd == 3) //Spam those emotes
return FALSE
if(emote_cd == 2) // Cooldown emotes were disabled by an admin, prevent use
return TRUE
if(emote_cd == 1) // Already on CD, prevent use
return TRUE
emote_cd = TRUE // Starting cooldown
spawn(cooldown)
if(emote_cd == 2)
return // Don't reset if cooldown emotes were disabled by an admin during the cooldown
emote_cd = FALSE // Cooldown complete, ready for more!
return FALSE // Proceed with emote
//--FalseIncarnate
/mob/proc/handle_emote_param(target, not_self, vicinity, return_mob) //Only returns not null if the target param is valid.
var/view_vicinity = vicinity ? vicinity : null //not_self means we'll only return if target is valid and not us
if(target) //vicinity is the distance passed to the view proc.
for(var/mob/A in view(view_vicinity, null)) //if set, return_mob will cause this proc to return the mob instead of just its name if the target is valid.
if(target == A.name && (!not_self || (not_self && target != name)))
if(return_mob)
return A
else
return target
// All mobs should have custom emote, really..
/mob/proc/custom_emote(m_type=EMOTE_VISUAL, message = null)
if(stat || !use_me && usr == src)
if(usr)
to_chat(usr, "You are unable to emote.")
return
var/muzzled = is_muzzled()
if(muzzled)
var/obj/item/clothing/mask/muzzle/M = wear_mask
if(m_type == EMOTE_SOUND && M.mute >= MUZZLE_MUTE_MUFFLE)
return //Not all muzzles block sound
if(m_type == EMOTE_SOUND && !can_speak())
return
var/input
if(!message)
input = sanitize(copytext(input(src,"Choose an emote to display.") as text|null,1,MAX_MESSAGE_LEN))
else
input = message
if(input)
message = "<B>[src]</B> [input]"
else
return
if(message)
log_emote(message, src)
if(isliving(src)) //isliving because these are defined on the mob/living level not mob
var/mob/living/L = src
L.say_log += "EMOTE: [input]" //say log too so it is easier on admins instead of having to merge the two with timestamps etc
L.emote_log += input //emote only log if an admin wants to search just for emotes they don't have to sift through the say
create_log(EMOTE_LOG, input) // TODO after #13047: Include the channel
// Hearing gasp and such every five seconds is not good emotes were not global for a reason.
// Maybe some people are okay with that.
for(var/mob/M in GLOB.player_list)
if(!M.client)
continue //skip monkeys and leavers
if(isnewplayer(M))
continue
if(findtext(message, " snores.")) //Because we have so many sleeping people.
break
if(isobserver(M) && M.get_preference(PREFTOGGLE_CHAT_GHOSTSIGHT) && !(M in viewers(src, null)) && client) // The client check makes sure people with ghost sight don't get spammed by simple mobs emoting.
M.show_message(message)
// Type 1 (Visual) emotes are sent to anyone in view of the item
if(m_type & EMOTE_VISUAL)
var/runechat_text = input
if(length(input) > 100)
runechat_text = "[copytext(input, 1, 101)]..."
var/list/can_see = get_mobs_in_view(1,src) //Allows silicon & mmi mobs carried around to see the emotes of the person carrying them around.
can_see |= viewers(src,null)
for(var/mob/O in can_see)
if(O.status_flags & PASSEMOTES)
for(var/obj/item/holder/H in O.contents)
H.show_message(message, m_type)
for(var/mob/living/M in O.contents)
M.show_message(message, m_type)
O.show_message(message, m_type)
if(O.client?.prefs.toggles2 & PREFTOGGLE_2_RUNECHAT)
O.create_chat_message(src, runechat_text, symbol = RUNECHAT_SYMBOL_EMOTE)
// Type 2 (Audible) emotes are sent to anyone in hear range
// of the *LOCATION* -- this is important for pAIs to be heard
else if(m_type & EMOTE_SOUND)
for(var/mob/O in get_mobs_in_view(7,src))
if(O.status_flags & PASSEMOTES)
for(var/obj/item/holder/H in O.contents)
H.show_message(message, m_type)
for(var/mob/living/M in O.contents)
M.show_message(message, m_type)
O.show_message(message, m_type)
/mob/proc/emote_dead(message)
if(check_mute(client.ckey, MUTE_DEADCHAT))
to_chat(src, "<span class='warning'>You cannot send deadchat emotes (muted).</span>")
return
if(!(client.prefs.toggles & PREFTOGGLE_CHAT_DEAD))
to_chat(src, "<span class='warning'>You have deadchat muted.</span>")
return
if(!src.client.holder)
if(!GLOB.dsay_enabled)
to_chat(src, "<span class='warning'>Deadchat is globally muted</span>")
return
var/input
if(!message)
input = sanitize(copytext(input(src, "Choose an emote to display.") as text|null, 1, MAX_MESSAGE_LEN))
else
input = message
if(input)
message = "<span class='game deadsay'><span class='prefix'>DEAD:</span> <b>[src]</b> [message]</span>"
else
return
if(message)
for(var/mob/M in GLOB.player_list)
if(isnewplayer(M))
continue
if(check_rights(R_ADMIN|R_MOD, 0, M) && M.get_preference(PREFTOGGLE_CHAT_DEAD)) // Show the emote to admins/mods
to_chat(M, message)
else if(M.stat == DEAD && M.get_preference(PREFTOGGLE_CHAT_DEAD)) // Show the emote to regular ghosts with deadchat toggled on
M.show_message(message, 2)
@@ -1,141 +0,0 @@
/mob/living/carbon/alien/humanoid/emote(act, m_type = 1, message = null, force)
var/param = null
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
// if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
// act = copytext(act,1,length(act)) //seriously who the fuck wrote this
var/muzzled = is_muzzled()
var/on_CD = 0
act = lowertext(act)
//cooldown system handled by /code/modules/mob/emotes.dm
switch(act)
if("roar")
on_CD = handle_emote_CD()
if("deathgasp")
on_CD = handle_emote_CD()
if("hiss")
on_CD = handle_emote_CD()
if("gnarl")
on_CD = handle_emote_CD()
if("flip")
on_CD = handle_emote_CD()
if(!force && on_CD == 1)
return
switch(act)
if("sign")
if(!restrained())
var/num = null
if(text2num(param))
num = "the number [text2num(param)]"
if(num)
message = "<B>\The [src]</B> signs [num]."
m_type = 1
if("burp")
if(!muzzled)
message = "<B>\The [src]</B> burps."
m_type = 2
if("deathgasp")
message = "<B>\The [src]</B> lets out a waning guttural screech, green blood bubbling from its maw..."
m_type = 2
if("scratch")
if(!restrained())
message = "<B>\The [src]</B> scratches."
m_type = 1
if("whimper")
if(!muzzled)
message = "<B>\The [src]</B> whimpers."
m_type = 2
if("roar")
if(!muzzled)
message = "<B>\The [src]</B> roars."
m_type = 2
if("hiss")
if(!muzzled)
message = "<B>\The [src]</B> hisses."
m_type = 2
if("tail")
message = "<B>\The [src]</B> waves its tail."
m_type = 1
if("gasp")
message = "<B>\The [src]</B> gasps."
m_type = 2
if("shiver")
message = "<B>\The [src]</B> shivers."
m_type = 2
if("drool")
message = "<B>\The [src]</B> drools."
m_type = 1
if("scretch")
if(!muzzled)
message = "<B>\The [src]</B> scretches."
m_type = 2
if("choke")
message = "<B>\The [src]</B> chokes."
m_type = 2
if("moan")
message = "<B>\The [src]</B> moans!"
m_type = 2
if("nod")
message = "<B>\The [src]</B> nods its head."
m_type = 1
if("sit")
message = "<B>\The [src]</B> sits down."
m_type = 1
if("sway")
message = "<B>\The [src]</B> sways around dizzily."
m_type = 1
if("sulk")
message = "<B>\The [src]</B> sulks down sadly."
m_type = 1
if("twitch")
message = "<B>\The [src]</B> twitches violently."
m_type = 1
if("dance")
if(!restrained())
message = "<B>\The [src]</B> dances around happily."
m_type = 1
if("roll")
if(!restrained())
message = "<B>\The [src]</B> rolls."
m_type = 1
if("shake")
message = "<B>\The [src]</B> shakes its head."
m_type = 1
if("gnarl")
if(!muzzled)
message = "<B>\The [src]</B> gnarls and shows its teeth.."
m_type = 2
if("jump")
message = "<B>\The [src]</B> jumps!"
m_type = 1
if("collapse")
Paralyse(4 SECONDS)
message = "<B>\The [src]</B> collapses!"
m_type = 2
if("flip")
m_type = 1
message = "<B>\The [src]</B> does a flip!"
SpinAnimation(5,1)
if("help")
to_chat(src, "burp, flip, deathgasp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roar, roll, scratch,\nscretch, shake, sign-#, sit, sulk, sway, tail, twitch, whimper")
if(!stat)
if(act == "roar")
playsound(src.loc, 'sound/voice/hiss5.ogg', 50, 1, 1)
if(act == "deathgasp")
playsound(src.loc, 'sound/voice/hiss6.ogg', 80, 1, 1)
if(act == "hiss")
playsound(src.loc, 'sound/voice/hiss1.ogg', 30, 1, 1)
if(act == "gnarl")
playsound(src.loc, 'sound/voice/hiss4.ogg', 30, 1, 1)
..()
@@ -0,0 +1,32 @@
/**
* Emotes usable by humanoid xenomorphs.
*/
/datum/emote/living/carbon/alien/humanoid
mob_type_allowed_typecache = list(/mob/living/carbon/alien/humanoid)
/datum/emote/living/carbon/alien/humanoid/roar
key = "roar"
key_third_person = "roars"
message = "roars!"
message_param = "roars at %t!"
emote_type = EMOTE_SOUND | EMOTE_MOUTH
sound = "sound/voice/hiss5.ogg"
volume = 80
/datum/emote/living/carbon/alien/humanoid/hiss
key = "hiss"
key_third_person = "hisses"
message = "hisses!"
message_param = "hisses at %t!"
emote_type = EMOTE_SOUND | EMOTE_MOUTH
sound = "sound/voice/hiss1.ogg"
volume = 30
/datum/emote/living/carbon/alien/humanoid/gnarl
key = "gnarl"
key_third_person = "gnarls"
message = "gnarls and shows its teeth."
message_param = "gnarls and flashes its teeth at %t."
sound = "sound/voice/hiss4.ogg"
emote_type = EMOTE_SOUND | EMOTE_MOUTH
volume = 30
@@ -1,126 +0,0 @@
/mob/living/carbon/alien/larva/emote(act, m_type = 1, message = null, force)
var/param = null
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
act = copytext(act,1,length(act))
var/muzzled = is_muzzled()
act = lowertext(act)
switch(act)
if("me")
if(HAS_TRAIT(src, TRAIT_MUTE))
return
if(src.client)
if(check_mute(client.ckey, MUTE_IC))
to_chat(src, "<span class='warning'>You cannot send IC messages (muted).</span>")
return
if(src.client.handle_spam_prevention(message, MUTE_IC))
return
if(stat)
return
if(!(message))
return
return custom_emote(m_type, message)
if("custom")
return custom_emote(m_type, message)
if("sign")
if(!src.restrained())
message = text("<B>The alien</B> signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null))
m_type = 1
if("burp")
if(!muzzled)
message = "<B>[src]</B> burps."
m_type = 2
if("scratch")
if(!src.restrained())
message = "<B>[src]</B> scratches."
m_type = 1
if("whimper")
if(!muzzled)
message = "<B>[src]</B> whimpers."
m_type = 2
// if("roar")
// if(!muzzled)
// message = "<B>[src]</B> roars." Commenting out since larva shouldn't roar /N
// m_type = 2
if("tail")
message = "<B>[src]</B> waves its tail."
m_type = 1
if("gasp")
message = "<B>[src]</B> gasps."
m_type = 2
if("shiver")
message = "<B>[src]</B> shivers."
m_type = 2
if("drool")
message = "<B>[src]</B> drools."
m_type = 1
if("scretch")
if(!muzzled)
message = "<B>[src]</B> scretches."
m_type = 2
if("choke")
message = "<B>[src]</B> chokes."
m_type = 2
if("moan")
message = "<B>[src]</B> moans!"
m_type = 2
if("nod")
message = "<B>[src]</B> nods its head."
m_type = 1
// if("sit")
// message = "<B>[src]</B> sits down." //Larvan can't sit down, /N
// m_type = 1
if("sway")
message = "<B>[src]</B> sways around dizzily."
m_type = 1
if("sulk")
message = "<B>[src]</B> sulks down sadly."
m_type = 1
if("twitch")
message = "<B>[src]</B> twitches violently."
m_type = 1
if("dance")
if(!src.restrained())
message = "<B>[src]</B> dances around happily."
m_type = 1
if("roll")
if(!src.restrained())
message = "<B>[src]</B> rolls."
m_type = 1
if("shake")
message = "<B>[src]</B> shakes its head."
m_type = 1
if("gnarl")
if(!muzzled)
message = "<B>[src]</B> gnarls and shows its teeth.."
m_type = 2
if("jump")
message = "<B>[src]</B> jumps!"
m_type = 1
if("hiss_")
message = "<B>[src]</B> hisses softly."
m_type = 1
if("collapse")
Paralyse(4 SECONDS)
message = text("<B>[]</B> collapses!", src)
m_type = 2
if("help")
to_chat(src, "burp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, twitch, whimper")
else
to_chat(src, text("Invalid Emote: []", act))
if((message && src.stat == 0))
log_emote(message, src)
if(m_type & 1)
for(var/mob/O in viewers(src, null))
O.show_message(message, m_type)
//Foreach goto(703)
else
for(var/mob/O in hearers(src, null))
O.show_message(message, m_type)
//Foreach goto(746)
return
@@ -0,0 +1,67 @@
/**
* Emotes usable by brains, but only while they're in MMIs.
*/
/datum/emote/living/carbon/brain
mob_type_allowed_typecache = list(/mob/living/carbon/brain)
mob_type_blacklist_typecache = null
/// The message that will be displayed to themselves, since brains can't really see their own emotes
var/self_message
/datum/emote/living/carbon/brain/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
if(self_message)
to_chat(user, self_message)
/datum/emote/living/carbon/brain/can_run_emote(mob/user, status_check, intentional)
. = ..()
if(!.)
return FALSE
var/mob/living/carbon/brain/B = user
if(!(B.container && istype(B.container, /obj/item/mmi))) // No MMI, no emotes
return FALSE
// So, brains can't really see their own emotes so we'll probably just want to send an extra message
/datum/emote/living/carbon/brain/alarm
key = "alarm"
key_third_person = "alarms"
message = "sounds an alarm."
self_message = "You sound an alarm."
/datum/emote/living/carbon/brain/alert
key = "alert"
key_third_person = "alerts"
message = "lets out a distressed noise."
self_message = "You let out a distressed noise."
/datum/emote/living/carbon/brain/notice
key = "notice"
message = "plays a loud tone."
self_message = "You play a loud tone."
/datum/emote/living/carbon/brain/flash
key = "flash"
message = "starts flashing its lights quickly!"
/datum/emote/living/carbon/brain/whistle
key = "whistle"
key_third_person = "whistles"
message = "whistles."
self_message = "You whistle."
/datum/emote/living/carbon/brain/beep
key = "beep"
key_third_person = "beeps"
message = "beeps."
self_message = "You beep."
/datum/emote/living/carbon/brain/boop
key = "boop"
key_third_person = "boops"
message = "boops."
self_message = "You boop."
@@ -1,51 +0,0 @@
/mob/living/carbon/brain/emote(act,m_type = 1, message = null, force)
if(!(container && istype(container, /obj/item/mmi)))//No MMI, no emotes
return
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
act = copytext(act, 1, t1)
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
act = copytext(act,1,length(act))
if(src.stat == DEAD)
return
act = lowertext(act)
switch(act)
if("alarm")
to_chat(src, "You sound an alarm.")
message = "<B>\The [src]</B> sounds an alarm."
m_type = 2
if("alert")
to_chat(src, "You let out a distressed noise.")
message = "<B>\The [src]</B> lets out a distressed noise."
m_type = 2
if("notice")
to_chat(src, "You play a loud tone.")
message = "<B>\The [src]</B> plays a loud tone."
m_type = 2
if("flash")
message = "The lights on <B>\the [src]</B> flash quickly."
m_type = 1
if("blink")
message = "<B>\The [src]</B> blinks."
m_type = 1
if("whistle")
to_chat(src, "You whistle.")
message = "<B>\The [src]</B> whistles."
m_type = 2
if("beep")
to_chat(src, "You beep.")
message = "<B>\The [src]</B> beeps."
m_type = 2
if("boop")
to_chat(src, "You boop.")
message = "<B>\The [src]</B> boops."
m_type = 2
if("help")
to_chat(src, "alarm, alert, notice, flash,blink, whistle, beep, boop")
if(message && !stat)
..()
@@ -0,0 +1,190 @@
/datum/emote/living/carbon
mob_type_allowed_typecache = list(/mob/living/carbon)
mob_type_blacklist_typecache = list(/mob/living/carbon/brain)
/datum/emote/living/carbon/blink
key = "blink"
key_third_person = "blinks"
message = "blinks."
/datum/emote/living/carbon/blink_r
key = "blink_r"
message = "blinks rapidly."
/datum/emote/living/carbon/clap
key = "clap"
key_third_person = "claps"
message = "claps."
message_mime = "claps silently."
message_param = "claps at %t."
emote_type = EMOTE_SOUND
vary = TRUE
/datum/emote/living/carbon/clap/run_emote(mob/user, params, type_override, intentional)
var/mob/living/carbon/human/H = user
if(!H.bodyparts_by_name[BODY_ZONE_L_ARM] || !H.bodyparts_by_name[BODY_ZONE_R_ARM])
if(!H.bodyparts_by_name[BODY_ZONE_L_ARM] && !H.bodyparts_by_name[BODY_ZONE_R_ARM])
// no arms...
to_chat(user, "<span class='warning'>You need arms to be able to clap.</span>")
else
// well, we've got at least one
user.visible_message("[user] makes the sound of one hand clapping.")
return TRUE
return ..()
/datum/emote/living/carbon/clap/get_sound(mob/living/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(!H?.mind.miming)
return pick(
'sound/misc/clap1.ogg',
'sound/misc/clap2.ogg',
'sound/misc/clap3.ogg',
'sound/misc/clap4.ogg')
/datum/emote/living/carbon/cross
key = "cross"
key_third_person = "crosses"
message = "crosses their arms."
hands_use_check = TRUE
/datum/emote/living/carbon/chuckle
key = "chuckle"
key_third_person = "chuckles"
message = "chuckles."
message_mime = "appears to chuckle."
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
muzzled_noises = list("joyful", "upbeat")
/datum/emote/living/carbon/cough
key = "cough"
key_third_person = "coughs"
message = "coughs!"
message_mime = "appears to cough!"
emote_type = EMOTE_SOUND | EMOTE_MOUTH
vary = TRUE
age_based = TRUE
volume = 120
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/carbon/cough/get_sound(mob/living/user)
. = ..()
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.gender == FEMALE)
if(H.dna.species.female_cough_sounds)
return pick(H.dna.species.female_cough_sounds)
else
if(H.dna.species.male_cough_sounds)
return pick(H.dna.species.male_cough_sounds)
/datum/emote/living/carbon/moan
key = "moan"
key_third_person = "moans"
message = "moans!"
message_mime = "appears to moan!"
muzzled_noises = list("pained")
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/carbon/giggle
key = "giggle"
key_third_person = "giggles"
message = "giggles."
message_mime = "giggles silently!"
muzzled_noises = list("bubbly")
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
/datum/emote/living/carbon/gurgle
key = "gurgle"
key_third_person = "gurgles"
message = "makes an uncomfortable gurgle."
muzzled_noises = list("unpleasant", "guttural")
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/carbon/inhale
key = "inhale"
key_third_person = "inhales"
message = "breathes in."
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
muzzled_noises = list("breathy")
/datum/emote/living/carbon/inhale/sharp
key = "inhale_s"
key_third_person = "inhales sharply!"
message = "takes a deep breath!"
/datum/emote/living/carbon/kiss
key = "kiss"
key_third_person = "kisses"
message = "blows a kiss."
message_param = "blows a kiss at %t!"
muzzled_noises = list("smooching")
/datum/emote/living/carbon/wave
key = "wave"
key_third_person = "waves"
message = "waves."
message_param = "waves at %t."
hands_use_check = TRUE
/datum/emote/living/carbon/yawn
key = "yawn"
key_third_person = "yawns"
message = "yawns."
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
muzzled_noises = list("tired", "lazy", "sleepy")
/datum/emote/living/carbon/exhale
key = "exhale"
key_third_person = "exhales"
message = "breathes out."
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
/datum/emote/living/carbon/laugh
key = "laugh"
key_third_person = "laughs"
message = "laughs."
message_mime = "laughs silently!"
message_param = "laughs at %t."
muzzled_noises = list("happy", "joyful")
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
/datum/emote/living/carbon/scowl
key = "scowl"
key_third_person = "scowls"
message = "scowls."
/datum/emote/living/groan
key = "groan"
key_third_person = "groans"
message = "groans!"
message_mime = "appears to groan!"
message_param = "groans at %t."
muzzled_noises = list("pained")
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/carbon/sign
key = "sign"
key_third_person = "signs"
message = "signs."
message_param = "signs the number %t."
param_desc = "number(0-10)"
// Humans get their own proc since they have fingers
mob_type_blacklist_typecache = list(/mob/living/carbon/human)
hands_use_check = TRUE
target_behavior = EMOTE_TARGET_BHVR_NUM
/datum/emote/living/carbon/faint
key = "faint"
key_third_person = "faints"
message = "faints."
/datum/emote/living/carbon/faint/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(. && isliving(user))
var/mob/living/L = user
L.SetSleeping(2 SECONDS)
@@ -86,8 +86,6 @@
return TRUE
/mob/living/carbon/human/death(gibbed)
if(can_die() && !gibbed && deathgasp_on_death)
emote("deathgasp", force = TRUE) //let the world KNOW WE ARE DEAD
// Only execute the below if we successfully died
. = ..(gibbed)
File diff suppressed because it is too large Load Diff
@@ -2015,3 +2015,21 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
to_chat(usr, "[src] does not have any stored infomation!")
else
to_chat(usr, "OOC Metadata is not supported by this server!")
/mob/living/carbon/human/verb/pose()
set name = "Set Pose"
set desc = "Sets a description which will be shown when someone examines you."
set category = "IC"
// no metagaming
if(stat)
return
pose = sanitize(copytext(input(usr, "This is [src]. [p_they(TRUE)] [p_are()]...", "Pose", null) as text, 1, MAX_MESSAGE_LEN))
/mob/living/carbon/human/verb/set_flavor()
set name = "Set Flavour Text"
set desc = "Sets an extended description of your character's features."
set category = "IC"
update_flavor_text()
@@ -0,0 +1,686 @@
/datum/emote/living/carbon/human
/// Custom messages that should be applied based on species
/// Should be an associative list of species name: message
var/species_custom_messages = list()
/// Custom messages applied to mimes of a particular species
var/species_custom_mime_messages = list()
mob_type_allowed_typecache = list(/mob/living/carbon/human)
/datum/emote/living/carbon/human/select_message_type(mob/user, msg, intentional)
. = ..()
var/mob/living/carbon/human/human_user = user
if(!species_custom_messages || (human_user.mind?.miming && !species_custom_mime_messages))
return .
var/custom_message
if(user.mind?.miming)
custom_message = species_custom_mime_messages[human_user.dna.species?.name]
else
custom_message = species_custom_messages[human_user.dna.species?.name]
if(custom_message)
return custom_message
/datum/emote/living/carbon/human/run_emote(mob/user, params, type_override, intentional)
var/mob/living/carbon/human/H = user
if((emote_type & EMOTE_MOUTH) && !H.mind?.miming)
if(H.getOxyLoss() > 10 || H.AmountLoseBreath() >= 8 SECONDS) // no screaming if you don't have enough breath to scream
H.emote("gasp")
return TRUE
return ..()
/datum/emote/living/carbon/human/airguitar
key = "airguitar"
message = "is strumming the air and headbanging like a safari chimp."
emote_type = EMOTE_VISIBLE
hands_use_check = TRUE
/datum/emote/living/carbon/human/cry
key = "cry"
key_third_person = "cries"
message = "cries."
muzzled_noises = list("weak", "pathetic", "sad")
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/dap
key = "dap"
key_third_person = "daps"
message = "sadly can't find anybody to give daps to, and daps themself. Shameful."
message_param = "give daps to %t."
emote_target_type = EMOTE_TARGET_MOB
hands_use_check = TRUE
/datum/emote/living/carbon/human/eyebrow
key = "eyebrow"
message = "raises an eyebrow."
message_param = "raises an eyebrow at %t."
/datum/emote/living/carbon/human/grumble
key = "grumble"
key_third_person = "grumbles"
message = "grumbles!"
message_mime = "seems to grumble!"
message_postfix = "at %t!"
muzzled_noises = list("bothered")
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
/datum/emote/living/carbon/human/hug
key = "hug"
key_third_person = "hugs"
message = "hugs themselves."
message_param = "hugs %t."
hands_use_check = TRUE
/datum/emote/living/carbon/human/mumble
key = "mumble"
key_third_person = "mumbles"
message = "mumbles!"
message_mime = "seems to be speaking sweet nothings!"
message_postfix = "at %t!"
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
/datum/emote/living/carbon/human/nod
key = "nod"
key_third_person = "nods"
message = "nods their head."
message_param = "nods their head at %t."
/datum/emote/living/carbon/human/scream
key = "scream"
key_third_person = "screams"
message = "screams!"
message_mime = "acts out a scream!"
message_postfix = "at %t!"
muzzled_noises = list("very loud")
emote_type = EMOTE_SOUND | EMOTE_MOUTH
only_forced_audio = FALSE
vary = TRUE
age_based = TRUE
cooldown = 5 SECONDS
mob_type_blacklist_typecache = list(
/mob/living/carbon/human/monkey, // screech instead
/mob/living/silicon // Robot sounds
)
/datum/emote/living/carbon/human/scream/select_message_type(mob/user, msg, intentional)
. = ..()
var/mob/living/carbon/human/H = user
if(H.dna.species?.scream_verb)
if(H.mind?.miming)
return "[H.dna.species?.scream_verb] silently!"
else
return "[H.dna.species?.scream_verb]!"
/datum/emote/living/carbon/human/scream/get_sound(mob/living/user)
var/mob/living/carbon/human/human = user
if(human.mind?.miming || !istype(human))
return
if(human.gender == FEMALE)
return human.dna.species.female_scream_sound
else
return human.dna.species.male_scream_sound
/datum/emote/living/carbon/human/gasp
key = "gasp"
key_third_person = "gasps"
message = "gasps!"
message_mime = "appears to be gasping!"
emote_type = EMOTE_SOUND // Don't make this one a mouth emote since we don't want it to be caught by nobreath
age_based = TRUE
unintentional_stat_allowed = UNCONSCIOUS
volume = 100
/datum/emote/living/carbon/human/gasp/get_sound(mob/user)
var/mob/living/carbon/human/H = user
if(H.is_muzzled())
// If you're muzzled you're not making noise
return
if(H.health > 0)
return H.dna.species.gasp_sound
if(H.gender == FEMALE)
return pick(H.dna.species.female_dying_gasp_sounds)
else
return pick(H.dna.species.male_dying_gasp_sounds)
/datum/emote/living/carbon/human/shake
key = "shake"
key_third_person = "shakes"
message = "shakes their head."
message_param = "shakes their head at %t."
/datum/emote/living/carbon/human/pale
key = "pale"
message = "goes pale for a second."
/datum/emote/living/carbon/human/raise
key = "raise"
key_third_person = "raises"
message = "raises a hand."
hands_use_check = TRUE
/datum/emote/living/carbon/human/salute
key = "salute"
key_third_person = "salutes"
message = "salutes."
message_param = "salutes to %t."
hands_use_check = TRUE
/datum/emote/living/carbon/human/shrug
key = "shrug"
key_third_person = "shrugs"
message = "shrugs."
/datum/emote/living/carbon/human/sniff
key = "sniff"
key_third_person = "sniff"
message = "sniffs."
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/johnny
key = "johnny"
message = "takes a drag from a cigarette and blows their own name out in smoke."
message_param = "dummy" // Gets handled in select_param
emote_type = EMOTE_AUDIBLE
target_behavior = EMOTE_TARGET_BHVR_DEFAULT_TO_BASE
emote_target_type = EMOTE_TARGET_MOB
/datum/emote/living/carbon/human/johnny/select_param(mob/user, params)
if(!params)
return message
var/mob/target = find_target(user, params, EMOTE_TARGET_MOB)
if(!target)
return message
var/msg = message
if(user.mind?.miming)
msg = "takes a drag from a cigarette and blows \"[target.name]\" out in smoke."
else
msg = "says, \"[target.name], please. They had a family.\" [user] takes a drag from a cigarette and blows [user.p_their()] name out in smoke."
return msg
/datum/emote/living/carbon/human/johnny/run_emote(mob/user, params, type_override, intentional)
var/mob/living/carbon/human/H = user
if(!istype(H.wear_mask, /obj/item/clothing/mask/cigarette))
to_chat(user, "<span class='warning'>You can't be that cool without a cigarette between your lips.</span>")
return TRUE
var/obj/item/clothing/mask/cigarette/cig = H.wear_mask
if(!cig.lit)
to_chat(user, "<span class='warning'>You have to light that [cig] first, cool cat.</span>")
return TRUE
if(H.getOxyLoss() > 30)
user.visible_message(
"<span class='warning'>[user] gasps for air and swallows their cigarette!</span>",
"<span class='warning'>You gasp for air and accidentally swallow your [cig]!</span>"
)
if(cig.lit)
to_chat(user, "<span class='userdanger'>The lit [cig] burns on the way down!")
user.unEquip(cig)
qdel(cig)
H.adjustFireLoss(5)
return TRUE
return ..()
/datum/emote/living/carbon/human/sneeze
key = "sneeze"
key_third_person = "sneezes"
message = "sneezes."
muzzled_noises = list("strange", "sharp")
emote_type = EMOTE_SOUND | EMOTE_MOUTH
volume = 70
/datum/emote/living/carbon/human/sneeze/get_sound(mob/user)
var/mob/living/carbon/human/H = user
if(H.gender == FEMALE)
return H.dna.species.female_sneeze_sound
else
return H.dna.species.male_sneeze_sound
/datum/emote/living/carbon/human/slap
key = "slap"
key_third_person = "slaps"
hands_use_check = TRUE
cooldown = 3 SECONDS // to prevent endless table slamming
/datum/emote/living/carbon/human/slap/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
var/obj/item/slapper/N = new(user)
if(user.put_in_hands(N))
to_chat(user, "<span class='notice'>You ready your slapping hand.</span>")
else
qdel(N)
to_chat(user, "<span class='warning'>You're incapable of slapping in your current state.</span>")
/datum/emote/living/carbon/human/wink
key = "wink"
key_third_person = "winks"
message = "winks."
/datum/emote/living/carbon/human/highfive
key = "highfive"
key_third_person = "highfives"
message = "requests a highfive."
hands_use_check = TRUE
cooldown = 3 SECONDS
/datum/emote/living/carbon/human/highfive/can_run_emote(mob/user, status_check, intentional)
. = ..()
var/mob/living/carbon/user_carbon = user
if(user_carbon.restrained())
return FALSE
/datum/emote/living/carbon/human/highfive/proc/wiz_cleanup(mob/user, mob/highfived)
user.status_flags &= ~GODMODE
highfived.status_flags &= ~GODMODE
/datum/emote/living/carbon/human/highfive/run_emote(mob/user, params, type_override, intentional)
var/mob/living/carbon/user_carbon = user
if(user_carbon.has_status_effect(STATUS_EFFECT_HIGHFIVE))
user.visible_message("[user.name] shakes [user.p_their()] hand around slightly, impatiently waiting for someone to high-five them.")
return TRUE
user_carbon.apply_status_effect(STATUS_EFFECT_HIGHFIVE)
for(var/mob/living/L in orange(1))
if(L.has_status_effect(STATUS_EFFECT_HIGHFIVE) && L != user)
if(iswizard(user) && iswizard(L))
user.visible_message("<span class='biggerdanger'><b>[user.name]</b> and <b>[L.name]</b> high-five EPICALLY!</span>")
user_carbon.status_flags |= GODMODE
L.status_flags |= GODMODE
explosion(get_turf(user), 5, 2, 1, 3)
// explosions have a spawn so this makes sure that we don't get gibbed
addtimer(CALLBACK(src, .proc/wiz_cleanup, user_carbon, L), 1)
user_carbon.remove_status_effect(STATUS_EFFECT_HIGHFIVE)
L.remove_status_effect(STATUS_EFFECT_HIGHFIVE)
return TRUE
user.visible_message("<b>[user.name]</b> and <b>[L.name]</b> high-five!")
playsound(user, 'sound/effects/snap.ogg', 50)
user_carbon.remove_status_effect(STATUS_EFFECT_HIGHFIVE)
L.remove_status_effect(STATUS_EFFECT_HIGHFIVE)
return TRUE
return ..()
/datum/emote/living/carbon/human/handshake
key = "handshake"
message = "holds out their hand."
hands_use_check = TRUE
emote_target_type = EMOTE_TARGET_MOB
target_behavior = EMOTE_TARGET_BHVR_DEFAULT_TO_BASE
/datum/emote/living/carbon/human/handshake/act_on_target(mob/user, target)
. = ..()
if(!target)
user.visible_message(
"[user] seems to shake hands with empty space.",
"You shake the air's hand."
)
return EMOTE_ACT_STOP_EXECUTION
if(!user.Adjacent(target) || !ishuman(target))
message_param = "extends a hand towards %t."
return TRUE
var/mob/living/carbon/human/human_target = target
if(human_target.canmove && !human_target.r_hand && !human_target.restrained())
message_param = "shakes hands with %t."
else
message_param = "holds out [user.p_their()] hand to %t."
/datum/emote/living/carbon/human/handshake/run_emote(mob/user, params, type_override, intentional)
var/mob/living/target
for(var/mob/living/A in oview(5, user))
if(params == A.name)
target = A
if(!target)
user.visible_message(
"[user] seems to shake hands with empty space.",
"You shake the air's hand."
)
return TRUE
if(target.canmove && !target.r_hand && !target.restrained())
message_param = "shakes hands with %t."
else
message_param = "holds out [user.p_their()] hand to %t."
return ..()
/datum/emote/living/carbon/human/snap
key = "snap"
key_third_person = "snaps"
message = "snaps their fingers."
message_param = "snaps their fingers at %t."
sound = "sound/effects/fingersnap.ogg"
emote_type = EMOTE_SOUND
/datum/emote/living/carbon/human/snap/run_emote(mob/user, params, type_override, intentional)
var/mob/living/carbon/human/H = user
var/obj/item/organ/external/LH = H.get_organ("l_hand")
var/obj/item/organ/external/RH = H.get_organ("r_hand")
var/left_hand_good = FALSE
var/right_hand_good = FALSE
if(LH && !(LH.status & ORGAN_SPLINTED) && !(LH.status & ORGAN_BROKEN))
left_hand_good = TRUE
if(RH && !(RH.status & ORGAN_SPLINTED) && !(RH.status & ORGAN_BROKEN))
right_hand_good = TRUE
if(!left_hand_good && !right_hand_good)
to_chat(user, "You need at least one hand in good working order to snap your fingers.")
return TRUE
if(prob(5))
user.visible_message("<span class='danger'><b>[user]</b> snaps [p_their()] fingers right off!</span>")
playsound(user.loc, 'sound/effects/snap.ogg', 50, 1)
return TRUE
return ..()
/datum/emote/living/carbon/human/fart
key = "fart"
key_third_person = "farts"
message = "farts."
message_param = "farts in %t's general direction."
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/fart/run_emote(mob/user, params, type_override, intentional)
var/farted_on_something = FALSE
for(var/atom/A in get_turf(user))
farted_on_something = A.fart_act(user) || farted_on_something
if(!farted_on_something)
return ..()
/datum/emote/living/carbon/sign/signal
key = "signal"
key_third_person = "signals"
message_param = "raises %t fingers."
param_desc = "number(0-10)"
mob_type_allowed_typecache = list(/mob/living/carbon/human)
hands_use_check = TRUE
/////////
// Species-specific emotes
/datum/emote/living/carbon/human/wag
key = "wag"
key_third_person = "wags"
message = "starts wagging their tail."
emote_type = EMOTE_VISIBLE | EMOTE_FORCE_NO_RUNECHAT
species_type_whitelist_typecache = list(
/datum/species/unathi,
/datum/species/vulpkanin,
/datum/species/tajaran,
/datum/species/vox
)
/datum/emote/living/carbon/human/proc/can_wag(mob/user)
var/mob/living/carbon/human/H = user
if(!(H.dna.species.bodyflags & TAIL_WAGGING))
return FALSE
var/obscured = H.wear_suit && (H.wear_suit.flags_inv & HIDETAIL)
if(!istype(H))
return FALSE
if(istype(H.body_accessory, /datum/body_accessory/tail))
if(!H.body_accessory.try_restrictions(user))
return FALSE
if(H.dna.species.bodyflags & TAIL_WAGGING && obscured)
return FALSE
return TRUE
/datum/emote/living/carbon/human/wag/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
var/mob/living/carbon/human/H = user
H.start_tail_wagging()
/datum/emote/living/carbon/human/wag/can_run_emote(mob/user, status_check = TRUE, intentional)
if(!..())
return FALSE
if(!can_wag(user))
return FALSE
return TRUE
/datum/emote/living/carbon/human/wag/stop
key = "swag" // B)
key_third_person = "swags"
message = "stops wagging their tail."
/datum/emote/living/carbon/human/wag/stop/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
var/mob/living/carbon/human/H = user
H.stop_tail_wagging()
///Snowflake emotes only for le epic chimp
/datum/emote/living/carbon/human/monkey
species_type_whitelist_typecache = list(/datum/species/monkey)
// Note: subtype of human scream, not monkey, so we need the overrides.
/datum/emote/living/carbon/human/scream/screech
key = "screech"
key_third_person = "screeches"
message = "screeches!"
message_param = "screeches at %t!"
vary = FALSE
mob_type_blacklist_typecache = list()
mob_type_allowed_typecache = list(/mob/living/carbon/human/monkey)
species_type_whitelist_typecache = list(/datum/species/monkey)
/datum/emote/living/carbon/human/scream/screech/roar
key = "roar"
key_third_person = "roars"
message = "roars!"
message_param = "roars at %t!"
/datum/emote/living/carbon/human/monkey/gnarl
key = "gnarl"
key_third_person = "gnarls"
message = "gnarls and shows their teeth!"
message_param = "gnarls and shows their teeth at %t."
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
/datum/emote/living/carbon/human/monkey/roll
key = "roll"
key_third_person = "rolls"
message = "rolls."
hands_use_check = TRUE
/datum/emote/living/carbon/human/monkey/roll/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(.)
user.SpinAnimation(10, 1)
/datum/emote/living/carbon/human/monkey/scratch
key = "scratch"
key_third_person = "scratches"
message = "scratches."
hands_use_check = TRUE
/datum/emote/living/carbon/human/monkey/tail
key = "tail"
message = "waves their tail."
///////
// More specific human species emotes
/datum/emote/living/carbon/human/flap
key = "flap"
key_third_person = "flaps"
message = "flaps their wings."
species_type_whitelist_typecache = list(/datum/species/moth)
/datum/emote/living/carbon/human/flap/angry
key = "aflap"
key_third_person = "aflaps"
message = "flaps their wings ANGRILY!"
/datum/emote/living/carbon/human/flutter
key = "flutter"
key_third_person = "flutters"
message = "flutters their wings."
species_type_whitelist_typecache = list(/datum/species/moth)
/datum/emote/living/carbon/human/quill
key = "quill"
key_third_person = "quills"
message = "rustles their quills."
message_param = "rustles their quills at %t."
emote_type = EMOTE_SOUND
age_based = TRUE
// Credit to sound-ideas (freesfx.co.uk) for the sound.
sound = "sound/effects/voxrustle.ogg"
species_type_whitelist_typecache = list(/datum/species/vox)
/datum/emote/living/carbon/human/warble
key = "warble"
key_third_person = "warbles"
message = "warbles."
message_param = "warbles at %t."
emote_type = EMOTE_SOUND
age_based = TRUE
// Copyright CC BY 3.0 alienistcog (freesound.org) for the sound.
sound = "sound/effects/warble.ogg"
species_type_whitelist_typecache = list(/datum/species/skrell)
/datum/emote/living/carbon/human/clack
key = "clack"
key_third_person = "clacks"
message = "clacks their mandibles."
message_param = "clacks their mandibles at %t."
species_type_whitelist_typecache = list(/datum/species/kidan)
emote_type = EMOTE_SOUND
audio_cooldown = 3 SECONDS
age_based = TRUE
// Credit to DrMinky (freesound.org) for the sound.
sound = "sound/effects/Kidanclack.ogg"
/datum/emote/living/carbon/human/clack/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
mineral_scan_pulse(get_turf(src), range = world.view)
/datum/emote/living/carbon/human/clack/click
key = "click"
key_third_person = "clicks"
message = "clicks their mandibles."
message_param = "clicks their mandibles at %t."
// Credit to DrMinky (freesound.org) for the sound.
sound = "sound/effects/Kidanclack2.ogg"
/datum/emote/living/carbon/human/drask_talk
species_type_whitelist_typecache = list(/datum/species/drask)
emote_type = EMOTE_SOUND
age_based = TRUE
sound = "sound/voice/drasktalk.ogg"
/datum/emote/living/carbon/human/drask_talk/drone
key = "drone"
key_third_person = "drones"
message = "drones."
message_param = "drones at %t."
/datum/emote/living/carbon/human/drask_talk/hum
key = "hum"
key_third_person = "hums"
message = "hums."
message_param = "hums at %t."
/datum/emote/living/carbon/human/drask_talk/rumble
key = "rumble"
key_third_person = "rumbles"
message = "rumbles."
message_param = "rumbles at %t."
/datum/emote/living/carbon/human/hiss
key = "hiss"
key_third_person = "hisses"
message = "hisses."
message_param = "hisses at %t."
species_type_whitelist_typecache = list(/datum/species/unathi)
emote_type = EMOTE_SOUND | EMOTE_MOUTH
age_based = TRUE
// Credit to Jamius (freesound.org) for the sound.
sound = "sound/effects/unathihiss.ogg"
muzzled_noises = list("weak hissing")
/datum/emote/living/carbon/human/creak
key = "creak"
key_third_person = "creaks"
message = "creaks."
message_param = "creaks at %t."
emote_type = EMOTE_SOUND
age_based = TRUE
species_type_whitelist_typecache = list(/datum/species/diona)
sound = "sound/voice/dionatalk1.ogg"
/datum/emote/living/carbon/human/squish
key = "squish"
key_third_person = "squishes"
message = "squishes."
message_param = "squishes at %t."
emote_type = EMOTE_SOUND
age_based = TRUE
// Credit to DrMinky (freesound.org) for the sound.
sound = "sound/effects/slime_squish.ogg"
/datum/emote/living/carbon/human/squish/can_run_emote(mob/user, status_check, intentional)
. = ..()
if(!.)
return FALSE
if(isslimeperson(src)) //Only Slime People can squish
return TRUE
else
var/mob/living/carbon/human/H = user
for(var/obj/item/organ/external/L in H.bodyparts) // if your limbs are squishy you can squish too!
if(istype(L.dna.species, /datum/species/slime))
return TRUE
return FALSE
/datum/emote/living/carbon/human/howl
key = "howl"
key_third_person = "howls"
message = "howls."
message_mime = "acts out a howl."
message_param = "howls at %t."
species_type_whitelist_typecache = list(/datum/species/vulpkanin)
emote_type = EMOTE_SOUND | EMOTE_MOUTH
age_based = TRUE
sound = "sound/goonstation/voice/howl.ogg"
muzzled_noises = list("very loud")
volume = 100
cooldown = 10 SECONDS
/datum/emote/living/carbon/human/growl
key = "growl"
key_third_person = "growls"
message = "growls."
message_mime = "growls silently."
message_param = "growls at %t."
species_type_whitelist_typecache = list(/datum/species/vulpkanin)
sound = "growls" // what the fuck why is this just top level
volume = 80
muzzled_noises = list("annoyed")
emote_type = EMOTE_SOUND | EMOTE_MOUTH
/datum/emote/living/carbon/human/rattle
key = "rattle"
key_third_person = "rattles"
message = "rattles their bones."
message_param = "rattles their bones at %t."
species_type_whitelist_typecache = list(/datum/species/skeleton, /datum/species/plasmaman)
@@ -67,7 +67,7 @@
if(!(lying || resting))
if(!HAS_TRAIT(src, TRAIT_NOPAIN))
emote("scream")
custom_emote(1, "collapses!")
emote("collapses")
Weaken(10 SECONDS) //can't emote while weakened, apparently.
@@ -93,7 +93,7 @@
continue
var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ")
custom_emote(1, "[HAS_TRAIT(src, TRAIT_NOPAIN) ? "" : emote_scream ]drops what [p_they()] [p_were()] holding in [p_their()] [E.name]!")
custom_emote(EMOTE_VISIBLE, "[HAS_TRAIT(src, TRAIT_NOPAIN) ? "" : emote_scream ]drops what [p_they()] [p_were()] holding in [p_their()] [E.name]!")
else if(E.is_malfunctioning())
@@ -108,7 +108,7 @@
if(!unEquip(r_hand))
continue
custom_emote(1, "drops what [p_they()] [p_were()] holding, [p_their()] [E.name] malfunctioning!")
custom_emote(EMOTE_VISIBLE, "drops what [p_they()] [p_were()] holding, [p_their()] [E.name] malfunctioning!")
do_sparks(5, 0, src)
+1 -1
View File
@@ -62,7 +62,7 @@
SetLoseBreath(0)
if(!gibbed && deathgasp_on_death)
emote("deathgasp", force = TRUE)
emote("deathgasp")
if(mind && suiciding)
mind.suicided = TRUE
+1 -1
View File
@@ -317,7 +317,7 @@
/mob/living/attack_animal(mob/living/simple_animal/M)
M.face_atom(src)
if((M.a_intent == INTENT_HELP && M.ckey) || M.melee_damage_upper == 0)
M.custom_emote(1, "[M.friendly] [src].")
M.custom_emote(EMOTE_VISIBLE, "[M.friendly] [src].")
return FALSE
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "<span class='warning'>You don't want to hurt anyone!</span>")
+434
View File
@@ -0,0 +1,434 @@
/datum/emote/living
mob_type_allowed_typecache = /mob/living
mob_type_blacklist_typecache = list(
/mob/living/carbon/brain, // nice try
/mob/living/captive_brain,
/mob/living/silicon,
/mob/living/simple_animal/bot
)
message_postfix = "at %t."
/datum/emote/living/should_play_sound(mob/user, intentional)
. = ..()
if(user.mind?.miming)
return FALSE // shh
return .
/datum/emote/living/blush
key = "blush"
key_third_person = "blushes"
message = "blushes."
/datum/emote/living/bow
key = "bow"
key_third_person = "bows"
message = "bows."
message_param = "bows to %t."
message_postfix = "to %t."
/datum/emote/living/burp
key = "burp"
key_third_person = "burps"
message = "burps."
message_mime = "opens their mouth rather obnoxiously."
emote_type = EMOTE_AUDIBLE
muzzled_noises = list("peculiar")
/datum/emote/living/choke
key = "choke"
key_third_person = "chokes"
message = "chokes!"
message_mime = "clutches their throat desperately!"
emote_type = EMOTE_AUDIBLE
muzzled_noises = list("gagging", "strong")
/datum/emote/living/collapse
key = "collapse"
key_third_person = "collapses"
message = "collapses!"
emote_type = EMOTE_VISIBLE
/datum/emote/living/collapse/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(. && isliving(user))
var/mob/living/L = user
L.Paralyse(4 SECONDS)
/datum/emote/living/dance
key = "dance"
key_third_person = "dances"
message = "dances around happily."
/datum/emote/living/jump
key = "jump"
key_third_person = "jumps"
message = "jumps!"
/datum/emote/living/deathgasp
key = "deathgasp"
key_third_person = "deathgasps"
emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE // make sure deathgasp gets runechatted regardless
age_based = TRUE
cooldown = 10 SECONDS
volume = 40
unintentional_stat_allowed = DEAD
message = "seizes up and falls limp, their eyes dead and lifeless..."
message_alien = "seizes up and falls limp, their eyes dead and lifeless..."
message_robot = "shudders violently for a moment before falling still, its eyes slowly darkening."
message_AI = "screeches, its screen flickering as its systems slowly halt."
message_alien = "lets out a waning guttural screech, green blood bubbling from its maw..."
message_larva = "lets out a sickly hiss of air and falls limply to the floor..."
message_monkey = "lets out a faint chimper as it collapses and stops moving..."
message_simple = "stops moving..."
mob_type_blacklist_typecache = list(
/mob/living/carbon/brain,
/mob/living/captive_brain
)
/datum/emote/living/deathgasp/get_sound(mob/living/user)
. = ..()
if(isanimal(user))
var/mob/living/simple_animal/S = user
if(S.deathmessage)
message_simple = S.deathmessage
return S.death_sound
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.dna.species)
message = H.dna.species.death_message
return pick(H.dna.species.death_sounds)
if(isalien(user))
var/mob/living/carbon/alien/A = user
message_alien = A.death_message
return A.death_sound
if(issilicon(user))
var/mob/living/silicon/SI = user
return SI.death_sound
/datum/emote/living/drool
key = "drool"
key_third_person = "drools"
message = "drools."
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/quiver
key = "quiver"
key_third_person = "quivers"
message = "quivers."
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/frown
key = "frown"
key_third_person = "frowns"
message = "frowns."
message_param = "frowns at %t."
/datum/emote/living/gag
key = "gag"
key_third_person = "gags"
message = "gags."
message_mime = "appears to gag."
message_param = "gags at %t."
emote_type = EMOTE_AUDIBLE
/datum/emote/living/glare
key = "glare"
key_third_person = "glares"
message = "glares."
message_param = "glares at %t."
/datum/emote/living/grin
key = "grin"
key_third_person = "grins"
message = "grins."
/datum/emote/living/grimace
key = "grimace"
key_third_person = "grimaces"
message = "grimaces."
/datum/emote/living/look
key = "look"
key_third_person = "looks"
message = "looks."
message_param = "looks at %t."
/datum/emote/living/bshake
key = "bshake"
key_third_person = "bshakes"
message = "shakes."
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/shudder
key = "shudder"
key_third_person = "shudders"
message = "shudders."
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/point
key = "point"
key_third_person = "points"
message = "points."
message_param = "points at %t."
hands_use_check = TRUE
target_behavior = EMOTE_TARGET_BHVR_USE_PARAMS_ANYWAY
emote_target_type = EMOTE_TARGET_ANY
/datum/emote/living/point/act_on_target(mob/user, target)
if(!target)
return
user.pointed(target)
/datum/emote/living/point/run_emote(mob/user, params, type_override, intentional)
// again, /tg/ has some flavor when pointing (like if you only have one leg) that applies debuffs
// but it's so common that seems unnecessary for here
message_param = initial(message_param) // reset
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(!H.has_left_hand() && !H.has_right_hand())
if(H.get_num_legs() != 0)
message_param = "tries to point at %t with a leg."
else
// nugget
message_param = "<span class='userdanger>bumps [user.p_their()] head on the ground</span> trying to motion towards %t."
return ..()
/datum/emote/living/pout
key = "pout"
key_third_person = "pouts"
message = "pouts."
/datum/emote/living/scream
key = "scream"
key_third_person = "screams"
message = "screams!"
message_mime = "acts out a scream!"
message_simple = "whimpers."
message_alien = "roars!"
emote_type = EMOTE_SOUND | EMOTE_MOUTH
mob_type_blacklist_typecache = list(
// Humans and silicons get specialized scream.
/mob/living/carbon/human,
/mob/living/silicon
)
volume = 80
/datum/emote/living/scream/get_sound(mob/living/user)
. = ..()
if(isalien(user))
return "sound/voice/hiss5.ogg"
/datum/emote/living/shake
key = "shake"
key_third_person = "shakes"
message = "shakes their head."
/datum/emote/living/shiver
key = "shiver"
key_third_person = "shiver"
message = "shivers."
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/sigh
key = "sigh"
key_third_person = "sighs"
message = "sighs."
message_mime = "appears to sigh."
muzzled_noises = list("weak")
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
/datum/emote/living/sigh/happy
key = "hsigh"
key_third_person = "hsighs"
message = "sighs contentedly."
message_mime = "appears to sigh contentedly"
muzzled_noises = list("chill", "relaxed")
/datum/emote/living/sit
key = "sit"
key_third_person = "sits"
message = "sits down."
/datum/emote/living/smile
key = "smile"
key_third_person = "smiles"
message = "smiles."
message_param = "smiles at %t."
/datum/emote/living/smug
key = "smug"
key_third_person = "smugs"
message = "grins smugly."
message_param = "grins smugly at %t."
/datum/emote/living/sniff
key = "sniff"
key_third_person = "sniffs"
message = "sniffs."
emote_type = EMOTE_AUDIBLE
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/snore
key = "snore"
key_third_person = "snores"
message = "snores."
message_mime = "sleeps soundly."
message_simple = "stirs in their sleep."
message_robot = "dreams of electric sheep..."
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
// lock it so these emotes can only be used while unconscious
stat_allowed = UNCONSCIOUS
max_stat_allowed = UNCONSCIOUS
unintentional_stat_allowed = UNCONSCIOUS
max_unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/nightmare
key = "nightmare"
message = "writhes in their sleep."
emote_type = EMOTE_VISIBLE
stat_allowed = UNCONSCIOUS
max_stat_allowed = UNCONSCIOUS
unintentional_stat_allowed = UNCONSCIOUS
max_unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/nightmare/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
user.dir = pick(GLOB.cardinal)
/datum/emote/living/stare
key = "stare"
key_third_person = "stares"
message = "stares."
message_param = "stares at %t."
/datum/emote/living/strech
key = "stretch"
key_third_person = "stretches"
message = "stretches their arms."
message_robot = "tests their actuators."
/datum/emote/living/sulk
key = "sulk"
key_third_person = "sulks"
message = "sulks down sadly."
/datum/emote/living/sway
key = "sway"
key_third_person = "sways"
message = "sways around dizzily."
/datum/emote/living/swear
key = "swear"
key_third_person = "swears"
message = "says a swear word!"
message_param = "says a swear word at %t!"
message_mime = "makes a rude gesture!"
message_simple = "makes an angry noise!"
message_robot = "makes a particularly offensive series of beeps!"
message_postfix = "at %t!"
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
mob_type_blacklist_typecache = list(
/mob/living/carbon/brain,
/mob/living/captive_brain
)
/datum/emote/living/tilt
key = "tilt"
key_third_person = "tilts"
message = "tilts their head to the side."
/datum/emote/living/tremble
key = "tremble"
key_third_person = "trembles"
message = "trembles in fear!"
/datum/emote/living/twitch
key = "twitch"
key_third_person = "twitches"
message = "twitches violently."
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/twitch_s
key = "twitch_s"
message = "twitches."
unintentional_stat_allowed = UNCONSCIOUS
/datum/emote/living/whimper
key = "whimper"
key_third_person = "whimpers"
message = "whimpers."
message_mime = "appears hurt."
emote_type = EMOTE_AUDIBLE | EMOTE_MOUTH
muzzled_noises = list("weak", "pathetic")
/datum/emote/living/wsmile
key = "wsmile"
key_third_person = "wsmiles"
message = "smiles weakly."
/datum/emote/living/custom
key = "me"
key_third_person = "custom"
message = null
mob_type_blacklist_typecache = list(
/mob/living/carbon/brain, // nice try
/mob/living/captive_brain
)
// Custom emotes should be able to be forced out regardless of context.
// It falls on the caller to determine whether or not it should actually be called.
unintentional_stat_allowed = DEAD
/datum/emote/living/custom/proc/check_invalid(mob/user, input)
var/static/regex/stop_bad_mime = regex(@"says|exclaims|yells|asks")
if(stop_bad_mime.Find(input, 1, 1))
to_chat(user, "<span class='danger'>Invalid emote.</span>")
return TRUE
return FALSE
/datum/emote/living/custom/run_emote(mob/user, params, type_override = null, intentional = FALSE)
var/custom_emote
var/custom_emote_type
if(QDELETED(user))
return FALSE
else if(check_mute(user?.client?.ckey, MUTE_IC))
to_chat(user, "<span class='boldwarning'>You cannot send IC messages (muted).</span>")
return FALSE
else if(!params)
custom_emote = copytext(sanitize(input("Choose an emote to display.") as text|null), 1, MAX_MESSAGE_LEN)
if(custom_emote && !check_invalid(user, custom_emote))
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
switch(type)
if("Visible")
custom_emote_type = EMOTE_VISIBLE
if("Hearable")
custom_emote_type = EMOTE_AUDIBLE
else
to_chat(user,"<span class='warning'>Unable to use this emote, must be either hearable or visible.</span>")
return
else
custom_emote = params
if(type_override)
custom_emote_type = type_override
message = custom_emote
emote_type = custom_emote_type
. = ..()
message = initial(message)
emote_type = initial(emote_type)
/datum/emote/living/custom/replace_pronoun(mob/user, message)
// Trust the user said what they mean
return message
+1 -39
View File
@@ -125,7 +125,7 @@ GLOBAL_LIST_EMPTY(channel_to_radio_key)
var/message_mode = parse_message_mode(message, "headset")
if(copytext(message, 1, 2) == "*")
return emote(copytext(message, 2))
return emote(copytext(message, 2), intentional = TRUE)
//parse the radio code and consume it
if(message_mode)
@@ -295,44 +295,6 @@ GLOBAL_LIST_EMPTY(channel_to_radio_key)
/mob/living/proc/GetVoice()
return name
/mob/living/emote(act, type, message, force) //emote code is terrible, this is so that anything that isn't already snowflaked to shit can call the parent and handle emoting sanely
if(client)
if(check_mute(client.ckey, MUTE_IC))
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
return
if(stat)
return 0
if(..())
return 1
if(act && type && message) //parent call
log_emote(message, src)
for(var/mob/M in GLOB.dead_mob_list)
if(!M.client)
continue //skip monkeys and leavers
if(isnewplayer(M))
continue
if(isobserver(M) && M.get_preference(PREFTOGGLE_CHAT_GHOSTSIGHT) && !(M in viewers(src, null)) && client) // The client check makes sure people with ghost sight don't get spammed by simple mobs emoting.
M.show_message(message)
switch(type)
if(1) //Visible
visible_message(message)
return 1
if(2) //Audible
audible_message(message)
return 1
else //everything else failed, emote is probably invalid
if(act == "help")
return //except help, because help is handled individually
to_chat(src, "<span class='notice'>Unusable emote '[act]'. Say *help for a list.</span>")
/mob/living/whisper(message as text)
message = trim_strip_html_properly(message)
+1 -1
View File
@@ -45,6 +45,6 @@
/mob/living/silicon/death(gibbed)
. = ..()
if(!gibbed)
if(. && !gibbed)
if(death_sound)
playsound(get_turf(src), death_sound, 200, 1)
-81
View File
@@ -1,81 +0,0 @@
/mob/living/silicon/emote(act, m_type=1, message = null, force)
var/param = null
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
//Emote Cooldown System (it's so simple!)
//handle_emote_CD() located in [code\modules\mob\emote.dm]
var/on_CD = 0
act = lowertext(act)
switch(act)
//Cooldown-inducing emotes
if("scream", "screams")
on_CD = handle_emote_CD(50) //longer cooldown
if("ping","pings","buzz","buzzs","buzzes","beep","beeps","yes","no", "buzz2")
//halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT.
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
//Everything else, including typos of the above emotes
else
on_CD = 0 //If it doesn't induce the cooldown, we won't check for the cooldown
if(!force && on_CD == 1) // Check if we need to suppress the emote attempt.
return // Suppress emote, you're still cooling off.
//--FalseIncarnate
switch(act)
if("ping","pings")
var/M = handle_emote_param(param)
message = "<B>[src]</B> pings[M ? " at [M]" : ""]."
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
m_type = 2
if("buzz","buzzs","buzzes")
var/M = handle_emote_param(param)
message = "<B>[src]</B> buzzes[M ? " at [M]" : ""]."
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
m_type = 2
if("beep","beeps")
var/M = handle_emote_param(param)
message = "<B>[src]</B> beeps[M ? " at [M]" : ""]."
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
m_type = 2
if("yes")
var/M = handle_emote_param(param)
message = "<B>[src]</B> emits an affirmative blip[M ? " at [M]" : ""]."
playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0)
m_type = 2
if("no")
var/M = handle_emote_param(param)
message = "<B>[src]</B> emits a negative blip[M ? " at [M]" : ""]."
playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0)
m_type = 2
if("scream", "screams")
var/M = handle_emote_param(param)
message = "<B>[src]</B> screams[M ? " at [M]" : ""]!"
playsound(src.loc, 'sound/goonstation/voice/robot_scream.ogg', 80, 0)
m_type = 2
if("buzz2")
var/M = handle_emote_param(param)
message = "<B>[src]</B> emits an irritated buzzing sound[M ? " at [M]" : ""]."
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
m_type = 2
if("help")
to_chat(src, "yes, no, beep, ping, buzz, scream, buzz2")
..()
@@ -49,9 +49,6 @@
/mob/living/silicon/robot/death(gibbed)
if(can_die())
if(!gibbed && deathgasp_on_death)
emote("deathgasp", force = TRUE)
if(module)
module.handle_death(src, gibbed)
@@ -1,9 +1,3 @@
/mob/living/silicon/robot/drone/say(message)
if(copytext(message, 1, 2) == "*")
return emote(copytext(message, 2))
return ..()
/mob/living/silicon/robot/drone/whisper_say(list/message_pieces)
say(multilingual_to_message(message_pieces)) //drones do not get to whisper, only speak normally
return 1
@@ -1,183 +0,0 @@
/mob/living/silicon/robot/emote(act, m_type=1, message = null, force)
var/param = null
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
//Emote Cooldown System (it's so simple!)
//handle_emote_CD() located in [code\modules\mob\emote.dm]
var/on_CD = 0
act = lowertext(act)
switch(act)
//Cooldown-inducing emotes
if("law","flip","flips","halt") //halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT.
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
if("spin","spins")
on_CD = handle_emote_CD(5 SECONDS)
//Everything else, including typos of the above emotes
else
on_CD = 0 //If it doesn't induce the cooldown, we won't check for the cooldown
if(!force && on_CD == 1) // Check if we need to suppress the emote attempt.
return // Suppress emote, you're still cooling off.
//--FalseIncarnate
switch(act)
if("salute","salutes")
if(!src.buckled)
var/M = null
if(param)
for(var/mob/A in view(null, null))
if(param == A.name)
M = A
break
if(!M)
param = null
if(param)
message = "<B>[src]</B> salutes to [param]."
else
message = "<B>[src]</b> salutes."
m_type = 1
if("bow","bows")
if(!src.buckled)
var/M = null
if(param)
for(var/mob/A in view(null, null))
if(param == A.name)
M = A
break
if(!M)
param = null
if(param)
message = "<B>[src]</B> bows to [param]."
else
message = "<B>[src]</B> bows."
m_type = 1
if("clap","claps")
if(!src.restrained())
message = "<B>[src]</B> claps."
m_type = 2
if("flap","flaps")
if(!src.restrained())
message = "<B>[src]</B> flaps its wings."
m_type = 2
if("aflap","aflaps")
if(!src.restrained())
message = "<B>[src]</B> flaps its wings ANGRILY!"
m_type = 2
if("twitch")
message = "<B>[src]</B> twitches violently."
m_type = 1
if("twitch_s","twitches")
message = "<B>[src]</B> twitches."
m_type = 1
if("nod","nods")
message = "<B>[src]</B> nods."
m_type = 1
if("deathgasp")
message = "<B>[src]</B> shudders violently for a moment, then becomes motionless, its eyes slowly darkening."
m_type = 1
if("glare","glares")
var/M = null
if(param)
for(var/mob/A in view(null, null))
if(param == A.name)
M = A
break
if(!M)
param = null
if(param)
message = "<B>[src]</B> glares at [param]."
else
message = "<B>[src]</B> glares."
if("stare","stares")
var/M = null
if(param)
for(var/mob/A in view(null, null))
if(param == A.name)
M = A
break
if(!M)
param = null
if(param)
message = "<B>[src]</B> stares at [param]."
else
message = "<B>[src]</B> stares."
if("look","looks")
var/M = null
if(param)
for(var/mob/A in view(null, null))
if(param == A.name)
M = A
break
if(!M)
param = null
if(param)
message = "<B>[src]</B> looks at [param]."
else
message = "<B>[src]</B> looks."
m_type = 1
if("law")
if(istype(module,/obj/item/robot_module/security))
message = "<B>[src]</B> shows its legal authorization barcode."
playsound(src.loc, 'sound/voice/biamthelaw.ogg', 50, 0)
m_type = 2
else
to_chat(src, "You are not THE LAW, pal.")
if("halt")
if(istype(module,/obj/item/robot_module/security))
message = "<B>[src]</B>'s speakers skreech, \"Halt! Security!\"."
playsound(src.loc, 'sound/voice/halt.ogg', 50, 0)
m_type = 2
else
to_chat(src, "You are not security.")
if("flip","flips")
m_type = 1
message = "<B>[src]</B> does a flip!"
src.SpinAnimation(5,1)
if("spin","spins")
spin(20, 1)
message = "<B>[src]</B> spins!"
if("help")
to_chat(src, "salute, bow-(none)/mob, clap, flap, aflap, twitch, twitches, nod, deathgasp, glare-(none)/mob, stare-(none)/mob, look,\n law, halt, flip, spin")
..()
/mob/living/silicon/robot/verb/powerwarn()
set category = "Robot Commands"
set name = "Power Warning"
if(handle_emote_CD(50))
return
if(!is_component_functioning("power cell") || !cell || !cell.charge)
visible_message("The power warning light on <span class='name'>[src]</span> flashes urgently.",\
"You announce you are operating in low power mode.")
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
else
to_chat(src, "<span class='warning'>You can only use this emote when you're out of charge.</span>")
@@ -1528,3 +1528,19 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/can_see_reagents()
return see_reagents
/mob/living/silicon/robot/verb/powerwarn()
set category = "Robot Commands"
set name = "Power Warning"
if(!is_component_functioning("power cell") || !cell || !cell.charge)
if(!start_audio_emote_cooldown(10 SECONDS))
to_chat(src, "<span class='warning'>The low-power capacitor for your speaker system is still recharging, please try again later.</span>")
return
visible_message("<span class='warning'>The power warning light on <span class='name'>[src]</span> flashes urgently.</span>",\
"<span class='warning'>You announce you are operating in low power mode.</span>")
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
else
to_chat(src, "<span class='warning'>You can only use this emote when you're out of charge.</span>")
+3 -3
View File
@@ -99,7 +99,7 @@
to_chat(src, "<i><span class='game say'>Holopad action relayed, <span class='name'>[real_name]</span> <span class='message'>[message]</span></span></i>")
for(var/mob/M in viewers(T.loc))
M.show_message(rendered, 2)
M.show_message(rendered, EMOTE_VISIBLE)
log_emote("(HPAD) [message]", src)
else //This shouldn't occur, but better safe then sorry.
@@ -107,10 +107,10 @@
return
return 1
/mob/living/silicon/ai/emote(act, type, message, force)
/mob/living/silicon/ai/emote(act, type, message, intentional = TRUE, force_silence = FALSE)
var/obj/machinery/hologram/holopad/T = current
if(istype(T) && T.masters[src])//Is the AI using a holopad?
src.holopad_emote(message)
holopad_emote(message)
else //Emote normally, then.
..()
@@ -0,0 +1,97 @@
/datum/emote/living/silicon
// Humans are allowed for the sake of IPCs
mob_type_allowed_typecache = list(/mob/living/silicon, /mob/living/simple_animal/bot, /mob/living/carbon/human)
mob_type_blacklist_typecache = list()
/datum/emote/living/silicon/can_run_emote(mob/user, status_check, intentional)
. = ..()
// Let IPCs (and people with robo-heads) make beep-boop noises
if(!.)
return FALSE
if(ishuman(user))
var/mob/living/carbon/human/H = user
var/obj/item/organ/external/head/head = H.get_organ(BODY_ZONE_HEAD)
if(head && !head.is_robotic())
return FALSE
/datum/emote/living/silicon/scream
key = "scream"
key_third_person = "screams"
message = "screams!"
message_param = "screams at %t!"
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
vary = TRUE
sound = "sound/goonstation/voice/robot_scream.ogg"
volume = 80
/datum/emote/living/silicon/ping
key = "ping"
key_third_person = "pings"
message = "pings."
message_param = "pings at %t."
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
sound = "sound/machines/ping.ogg"
/datum/emote/living/silicon/buzz
key = "buzz"
key_third_person = "buzzes"
message = "buzzes."
message_param = "buzzes at %t."
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
sound = "sound/machines/buzz-sigh.ogg"
/datum/emote/living/silicon/buzz2
key = "buzz2"
message = "emits an irritated buzzing sound."
message_param = "emits an irritated buzzing sound at %t."
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
sound = "sound/machines/buzz-two.ogg"
/datum/emote/living/silicon/beep
key = "beep"
key_third_person = "beeps"
message = "beeps."
message_param = "beeps at %t."
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
sound = "sound/machines/twobeep.ogg"
/datum/emote/living/silicon/yes
key = "yes"
message = "emits an affirmative blip."
message_param = "emits an affirmative blip at %t."
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
sound = "sound/machines/synth_yes.ogg"
/datum/emote/living/silicon/no
key = "no"
message = "emits a negative blip."
message_param = "emits a negative blip at %t."
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
sound = "sound/machines/synth_no.ogg"
/datum/emote/living/silicon/law
key = "law"
message = "shows its legal authorization barcode."
message_param = "shows %t its legal authorization barcode."
emote_type = EMOTE_SOUND | EMOTE_AUDIBLE
sound = "sound/voice/biamthelaw.ogg"
/datum/emote/living/silicon/law/can_run_emote(mob/user, status_check, intentional)
. = ..()
var/mob/living/silicon/robot/bot = user
if(!istype(bot) || !istype(bot.module, /obj/item/robot_module/security))
return FALSE
/datum/emote/living/silicon/halt
key = "halt"
message = "screeches \"HALT! SECURITY!\" from its speakers."
message_param = "instructs %t to HALT."
emote_type = EMOTE_SOUND
sound = "sound/voice/halt.ogg"
/datum/emote/living/silicon/halt/can_run_emote(mob/user, status_check, intentional)
. = ..()
var/mob/living/silicon/robot/bot = user
if(!istype(bot) || !istype(bot.module, /obj/item/robot_module/security))
return FALSE
@@ -1,4 +1,5 @@
//Defines for bots are now found in code\__DEFINES\bots.dm
// Emotes for bots are shared with silicon, and are found at code/modules/mob/living/silicon/emotes.dm
// AI (i.e. game AI, not the AI player) controlled bots
/mob/living/simple_animal/bot
@@ -1,74 +0,0 @@
/mob/living/simple_animal/bot/emote(act, m_type = 1, message = null, force)
var/param = null
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
act = copytext(act,1,length(act))
//Emote Cooldown System (it's so simple!)
//handle_emote_CD() located in [code\modules\mob\emote.dm]
var/on_CD = 0
act = lowertext(act)
switch(act)
//Cooldown-inducing emotes
if("scream", "screams")
on_CD = handle_emote_CD(50) //longer cooldown
if("ping","buzz","beep","yes","no") //halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT.
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
//Everything else, including typos of the above emotes
else
on_CD = 0 //If it doesn't induce the cooldown, we won't check for the cooldown
if(!force && on_CD == 1) // Check if we need to suppress the emote attempt.
return // Suppress emote, you're still cooling off.
//--FalseIncarnate
switch(act)
if("ping")
var/M = handle_emote_param(param)
message = "<B>[src]</B> pings[M ? " at [M]" : ""]."
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
m_type = 2
if("buzz")
var/M = handle_emote_param(param)
message = "<B>[src]</B> buzzes[M ? " at [M]" : ""]."
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
m_type = 2
if("beep")
var/M = handle_emote_param(param)
message = "<B>[src]</B> beeps[M ? " at [M]" : ""]."
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
m_type = 2
if("yes")
var/M = handle_emote_param(param)
message = "<B>[src]</B> emits an affirmative blip[M ? " at [M]" : ""]."
playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0)
m_type = 2
if("no")
var/M = handle_emote_param(param)
message = "<B>[src]</B> emits an negative blip[M ? " at [M]" : ""]."
playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0)
m_type = 2
if("scream", "screams")
var/M = handle_emote_param(param)
message = "<B>[src]</B> screams[M ? " at [M]" : ""]!"
playsound(src.loc, 'sound/goonstation/voice/robot_scream.ogg', 80, 0)
m_type = 2
if("help")
to_chat(src, "scream(s), yes, no, beep, buzz, ping")
..()
@@ -11,7 +11,6 @@
speak_emote = list("purrs", "meows")
emote_hear = list("meows", "mews")
emote_see = list("shakes its head", "shivers")
var/meow_sound = 'sound/creatures/cat_meow.ogg' //Used in emote.
speak_chance = 1
turns_per_move = 5
see_in_dark = 6
@@ -104,26 +103,26 @@
/mob/living/simple_animal/pet/cat/handle_automated_action()
if(!stat && !buckled)
if(prob(1))
custom_emote(1, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
custom_emote(EMOTE_VISIBLE, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
StartResting()
else if(prob(1))
custom_emote(1, pick("sits down.", "crouches on its hind legs.", "looks alert."))
custom_emote(EMOTE_VISIBLE, pick("sits down.", "crouches on its hind legs.", "looks alert."))
icon_state = "[icon_living]_sit"
collar_type = "[initial(collar_type)]_sit"
resting = TRUE
update_canmove()
else if(prob(1))
if(resting)
custom_emote(1, pick("gets up and meows.", "walks around.", "stops resting."))
custom_emote(EMOTE_VISIBLE, pick("gets up and meows.", "walks around.", "stops resting."))
StopResting()
else
custom_emote(1, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
custom_emote(EMOTE_VISIBLE, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
//MICE!
if(eats_mice && isturf(loc) && !incapacitated())
for(var/mob/living/simple_animal/mouse/M in view(1, src))
if(!M.stat && Adjacent(M))
custom_emote(1, "splats \the [M]!")
custom_emote(EMOTE_VISIBLE, "splats \the [M]!")
M.death()
M.splat()
movement_target = null
@@ -131,7 +130,7 @@
break
for(var/obj/item/toy/cattoy/T in view(1, src))
if(T.cooldown < (world.time - 400))
custom_emote(1, "bats \the [T] around with its paw!")
custom_emote(EMOTE_VISIBLE, "bats \the [T] around with its paw!")
T.cooldown = world.time
/mob/living/simple_animal/pet/cat/handle_automated_movement()
@@ -155,41 +154,6 @@
stop_automated_movement = 1
walk_to(src,movement_target,0,3)
/mob/living/simple_animal/pet/cat/emote(act, m_type = 1, message = null, force)
if(stat != CONSCIOUS)
return
var/on_CD = 0
act = lowertext(act)
switch(act)
if("meow")
on_CD = handle_emote_CD()
if("hiss")
on_CD = handle_emote_CD()
if("purr")
on_CD = handle_emote_CD()
else
on_CD = 0
if(!force && on_CD == 1)
return
switch(act)
if("meow")
message = "<B>[src]</B> [pick(emote_hear)]!"
m_type = 2 //audible
playsound(src, meow_sound, 50, 0.75)
if("hiss")
message = "<B>[src]</B> hisses!"
m_type = 2
if("purr")
message = "<B>[src]</B> purrs."
m_type = 2
if("help")
to_chat(src, "scream, meow, hiss, purr")
..()
/mob/living/simple_animal/pet/cat/Proc
name = "Proc"
gender = MALE
@@ -215,7 +179,6 @@
icon_living = "Syndicat"
icon_dead = "Syndicat_dead"
icon_resting = "Syndicat_rest"
meow_sound = null //Need robo-meow.
gender = FEMALE
faction = list("syndicate")
gold_core_spawnable = NO_SPAWN
@@ -33,7 +33,6 @@
melee_damage_upper = 8
attacktext = "bites"
attack_sound = 'sound/weapons/bite.ogg'
var/chirp_sound = 'sound/creatures/nymphchirp.ogg' //used in emote
speed = 0
stop_automated_movement = 0
@@ -277,31 +276,6 @@
to_chat(src, "<span class='warning'>You don't have any hands!</span>")
return
/mob/living/simple_animal/diona/emote(act, m_type = 1, message = null, force)
if(stat != CONSCIOUS)
return
var/on_CD = 0
act = lowertext(act)
switch(act)
if("chirp")
on_CD = handle_emote_CD()
else
on_CD = 0
if(!force && on_CD == 1)
return
switch(act) //IMPORTANT: Emotes MUST NOT CONFLICT anywhere along the chain.
if("chirp")
message = "<B>\The [src]</B> chirps!"
m_type = 2 //audible
playsound(src, chirp_sound, 40, 1, 1)
if("help")
to_chat(src, "scream, chirp")
..()
/mob/living/simple_animal/diona/npc_safe(mob/user)
if(!jobban_isbanned(user, ROLE_NYMPH))
return TRUE
@@ -43,40 +43,6 @@
return
playsound(src, yelp_sound, 75, TRUE)
/mob/living/simple_animal/pet/dog/emote(act, m_type = 1, message = null, force)
if(incapacitated())
return
var/on_CD = 0
act = lowertext(act)
switch(act)
if("bark")
on_CD = handle_emote_CD()
if("yelp")
on_CD = handle_emote_CD()
else
on_CD = 0
if(!force && on_CD == 1)
return
switch(act)
if("bark")
message = "<B>[src]</B> [pick(src.speak_emote)]!"
m_type = 2 //audible
playsound(src, pick(src.bark_sound), 50, TRUE)
if("yelp")
message = "<B>[src]</B> yelps!"
m_type = 2 //audible
playsound(src, yelp_sound, 75, TRUE)
if("growl")
message = "<B>[src]</B> growls!"
m_type = 2 //audible
if("help")
to_chat(src, "scream, bark, growl")
..()
/mob/living/simple_animal/pet/dog/attack_hand(mob/living/carbon/human/M)
. = ..()
switch(M.a_intent)
@@ -90,10 +56,10 @@
if(change > 0)
if(M && stat != DEAD) // Added check to see if this mob (the corgi) is dead to fix issue 2454
new /obj/effect/temp_visual/heart(loc)
custom_emote(1, "yaps happily!")
custom_emote(EMOTE_VISIBLE, "yaps happily!")
else
if(M && stat != DEAD) // Same check here, even though emote checks it as well (poor form to check it only in the help case)
custom_emote(1, "growls!")
emote("growl")
//Corgis and pugs are now under one dog subtype
@@ -564,7 +530,7 @@
if(isturf(movement_target.loc))
movement_target.attack_animal(src) // Eat the thing
else if(prob(30) && ishuman(movement_target.loc)) // mean hooman has stolen it
custom_emote(EMOTE_VISUAL, "stares at [movement_target.loc]'s [movement_target] with a sad puppy-face.")
custom_emote(EMOTE_VISIBLE, "stares at [movement_target.loc]'s [movement_target] with a sad puppy-face.")
/obj/item/reagent_containers/food/snacks/meat/corgi
name = "Corgi meat"
@@ -669,7 +635,7 @@
. = ..()
if(!resting && !buckled)
if(prob(1))
custom_emote(1, pick("dances around.","chases her tail."))
custom_emote(EMOTE_VISIBLE, pick("dances around.","chases her tail."))
spin(20, 1)
/mob/living/simple_animal/pet/dog/corgi/exoticcorgi
@@ -765,7 +731,7 @@
. = ..()
if(!resting && !buckled)
if(prob(1))
custom_emote(1, pick("chases its tail."))
custom_emote(EMOTE_VISIBLE, pick("chases its tail."))
spawn(0)
for(var/i in list(1, 2, 4, 8, 4, 2, 1, 2, 4, 8, 4, 2, 1, 2, 4, 8, 4, 2))
dir = i
@@ -0,0 +1,93 @@
/datum/emote/living/simple_animal
mob_type_allowed_typecache = list(/mob/living/simple_animal)
/datum/emote/living/simple_animal/diona_chirp
key = "chirp"
key_third_person = "chirps"
message = "chirps!"
sound = "sound/creatures/nymphchirp.ogg"
emote_type = EMOTE_SOUND
mob_type_allowed_typecache = list(/mob/living/simple_animal/diona)
// Dog emotes
/datum/emote/living/simple_animal/pet/dog
mob_type_allowed_typecache = list(/mob/living/simple_animal/pet/dog)
/datum/emote/living/simple_animal/pet/dog/bark
key = "bark"
key_third_person = "barks"
message = "barks."
message_param = "barks at %t."
emote_type = EMOTE_SOUND
/datum/emote/living/simple_animal/pet/dog/bark/get_sound(mob/living/user)
. = ..()
var/mob/living/simple_animal/pet/dog/D = user
message = pick(D.speak_emote)
return pick(D.bark_sound)
/datum/emote/living/simple_animal/pet/dog/yelp
key = "yelp"
key_third_person = "yelps"
message = "yelps!"
message_param = "yelps at %t!"
emote_type = EMOTE_SOUND
/datum/emote/living/simple_animal/pet/dog/yelp/get_sound(mob/living/user)
var/mob/living/simple_animal/pet/dog/D = user
return D.yelp_sound
/datum/emote/living/simple_animal/pet/dog/growl
key = "growl"
key_third_person = "growls"
message = "growls!"
message_param = "growls at %t!"
emote_type = EMOTE_SOUND
sound = "growl"
// Mouse
/datum/emote/living/simple_animal/mouse
mob_type_allowed_typecache = list(/mob/living/simple_animal/mouse)
/datum/emote/living/simple_animal/mouse/squeak
key = "squeak"
key_third_person = "squeaks"
message = "squeaks!"
message_param = "squeaks at %t!"
emote_type = EMOTE_SOUND
/datum/emote/living/simple_animal/mouse/squeak/get_sound(mob/living/user)
var/mob/living/simple_animal/mouse/M = user
return M.squeak_sound
// cat
/datum/emote/living/simple_animal/pet/cat
mob_type_allowed_typecache = list(/mob/living/simple_animal/pet/cat)
/datum/emote/living/simple_animal/pet/cat/meow
key = "meow"
key_third_person = "meows"
message = "meows."
message_param = "meows at %t."
sound = "sound/creatures/cat_meow.ogg"
emote_type = EMOTE_SOUND
/datum/emote/living/simple_animal/pet/cat/meow/run_emote(mob/user, params, type_override, intentional)
var/mob/living/simple_animal/pet/cat/C = user
message = pick(C.emote_hear)
. = ..()
/datum/emote/living/simple_animal/pet/cat/hiss
key = "hiss"
key_third_person = "hisses"
message = "hisses!"
message_param = "hisses at %t!"
/datum/emote/living/simple_animal/pet/cat/purr
key = "purr"
key_third_person = "purrs"
message = "purrs."
@@ -67,7 +67,7 @@
if(prob(1))
StopResting()
else if(prob(5))
custom_emote(2, "snuffles")
custom_emote(EMOTE_AUDIBLE, "snuffles")
else if(prob(0.5))
StartResting()
@@ -119,31 +119,6 @@
if(client)
client.time_died_as_mouse = world.time
/mob/living/simple_animal/mouse/emote(act, m_type = 1, message = null, force)
if(stat != CONSCIOUS)
return
var/on_CD = 0
act = lowertext(act)
switch(act)
if("squeak") //Mouse time
on_CD = handle_emote_CD()
else
on_CD = 0
if(!force && on_CD == 1)
return
switch(act)
if("squeak")
message = "<B>\The [src]</B> [pick(emote_hear)]!"
m_type = 2 //audible
playsound(src, squeak_sound, 40, 1)
if("help")
to_chat(src, "scream, squeak")
..()
/*
* Mouse types
*/
@@ -47,11 +47,11 @@
return
if(resting)
if(!wants_to_rest())
custom_emote(1, "growls, and gets up.")
custom_emote(EMOTE_VISIBLE, "growls, and gets up.")
playsound(get_turf(src), 'sound/hallucinations/growl2.ogg', 50, 1)
StopResting()
else if(wants_to_rest())
custom_emote(1, "lays down, and starts to lick their wounds.")
custom_emote(EMOTE_VISIBLE, "lays down, and starts to lick their wounds.")
StartResting()
/mob/living/simple_animal/hostile/hellhound/examine(mob/user)
@@ -330,7 +330,7 @@
/mob/living/simple_animal/hostile/proc/Aggro()
vision_range = aggro_vision_range
if(target && emote_taunt.len && prob(taunt_chance))
emote("me", 1, "[pick(emote_taunt)] at [target].")
custom_emote(EMOTE_VISIBLE, "[pick(emote_taunt)] at [target].")
taunt_chance = max(taunt_chance-7,2)
/mob/living/simple_animal/hostile/proc/LoseAggro()
@@ -394,7 +394,7 @@ Difficulty: Medium
return FALSE
return ..()
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message()
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message)
if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit
return
return ..()
@@ -121,7 +121,7 @@
/mob/living/simple_animal/parrot/death(gibbed)
if(can_die())
if(held_item)
custom_emote(EMOTE_VISUAL, "lets go of [held_item]!")
custom_emote(EMOTE_VISIBLE, "lets go of [held_item]!")
drop_held_item()
walk(src, 0)
return ..()
@@ -247,7 +247,7 @@
parrot_state |= PARROT_ATTACK
else
if(held_item)
custom_emote(EMOTE_VISUAL, "lets go of [held_item]!")
custom_emote(EMOTE_VISIBLE, "lets go of [held_item]!")
parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell!
drop_held_item(FALSE)
@@ -347,7 +347,7 @@
//Search for item to steal
parrot_interest = search_for_perch_and_item()
if(parrot_interest)
custom_emote(EMOTE_VISUAL, "looks in [parrot_interest]'s direction and takes flight.")
custom_emote(EMOTE_VISIBLE, "looks in [parrot_interest]'s direction and takes flight.")
parrot_state = PARROT_SWOOP|PARROT_STEAL
icon_state = "parrot_fly"
return
@@ -371,7 +371,7 @@
parrot_interest = AM
parrot_state = PARROT_SWOOP|PARROT_STEAL
face_atom(AM)
custom_emote(EMOTE_VISUAL, "turns and flies towards [parrot_interest].")
custom_emote(EMOTE_VISIBLE, "turns and flies towards [parrot_interest].")
return
else //Else it's a perch
parrot_perch = AM
@@ -493,10 +493,10 @@
var/obj/item/organ/external/affecting = H.get_organ(ran_zone(pick(parrot_dam_zone)))
H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, MELEE), sharp = TRUE)
custom_emote(EMOTE_VISUAL, pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons."))
custom_emote(EMOTE_VISIBLE, pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons."))
else
L.adjustBruteLoss(damage)
custom_emote(EMOTE_VISUAL, pick("pecks at [L].", "claws [L]."))
custom_emote(EMOTE_VISIBLE, pick("pecks at [L].", "claws [L]."))
return
//Otherwise, fly towards the mob!
else
@@ -229,23 +229,23 @@
else
randomValue -= speak.len
if(emote_see && randomValue <= emote_see.len)
custom_emote(1, pick(emote_see))
custom_emote(EMOTE_VISIBLE, pick(emote_see))
else
custom_emote(2, pick(emote_hear))
custom_emote(EMOTE_AUDIBLE, pick(emote_hear))
else
say(pick(speak))
else
if(!(emote_hear && emote_hear.len) && (emote_see && emote_see.len))
custom_emote(1, pick(emote_see))
custom_emote(EMOTE_VISIBLE, pick(emote_see))
if((emote_hear && emote_hear.len) && !(emote_see && emote_see.len))
custom_emote(2, pick(emote_hear))
custom_emote(EMOTE_AUDIBLE, pick(emote_hear))
if((emote_hear && emote_hear.len) && (emote_see && emote_see.len))
var/length = emote_hear.len + emote_see.len
var/pick = rand(1,length)
if(pick <= emote_see.len)
custom_emote(1, pick(emote_see))
custom_emote(EMOTE_VISIBLE, pick(emote_see))
else
custom_emote(2,pick(emote_hear))
custom_emote(EMOTE_AUDIBLE, pick(emote_hear))
/mob/living/simple_animal/handle_environment(datum/gas_mixture/environment)
@@ -316,20 +316,6 @@
pcollar.forceMove(drop_location())
pcollar = null
..()
/mob/living/simple_animal/emote(act, m_type = 1, message = null, force)
if(stat)
return
act = lowertext(act)
switch(act) //IMPORTANT: Emotes MUST NOT CONFLICT anywhere along the chain.
if("scream")
message = "<B>\The [src]</B> whimpers."
m_type = 2
if("help")
to_chat(src, "scream")
..()
/mob/living/simple_animal/say_quote(message)
var/verb = "says"
@@ -1,105 +0,0 @@
/mob/living/simple_animal/slime/emote(act, m_type = 1, message = null, force)
if(stat)
return
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
//param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
act = copytext(act,1,length(act))
act = lowertext(act)
var/regenerate_icons
switch(act) //Alphabetical please
if("me")
if(HAS_TRAIT(src, TRAIT_MUTE))
return
if(src.client)
if(check_mute(client.ckey, MUTE_IC))
to_chat(src, "<span class='warning'>You cannot send IC messages (muted).</span>")
return
if(src.client.handle_spam_prevention(message, MUTE_IC))
return
if(stat)
return
if(!(message))
return
return custom_emote(m_type, message)
if("bounce")
message = "<B>[src]</B> bounces in place."
m_type = 1
if("custom")
return custom_emote(m_type, message)
if("jiggle")
message = "<B>[src]</B> jiggles!"
m_type = 1
if("light")
message = "<B>[src]</B> lights up for a bit, then stops."
m_type = 1
if("moan")
message = "<B>[src]</B> moans."
m_type = 2
if("shiver")
message = "<B>[src]</B> shivers."
m_type = 2
if("sway")
message = "<B>[src]</B> sways around dizzily."
m_type = 1
if("twitch")
message = "<B>[src]</B> twitches."
m_type = 1
if("vibrate")
message = "<B>[src]</B> vibrates!"
m_type = 1
if("noface") //mfw I have no face
mood = null
regenerate_icons = 1
if("smile")
mood = "mischevous"
regenerate_icons = 1
if(":3")
mood = ":33"
regenerate_icons = 1
if("pout")
mood = "pout"
regenerate_icons = 1
if("frown")
mood = "sad"
regenerate_icons = 1
if("scowl")
mood = "angry"
regenerate_icons = 1
if("help") //This is an exception
to_chat(src, "Help for slime emotes. You can use these emotes with say \"*emote\":\n\nbounce, custom, jiggle, light, moan, shiver, sway, twitch, vibrate. \n\nYou may also change your face with: \n\nsmile, :3, pout, frown, scowl, noface")
else
to_chat(src, "<span class='notice'>Unusable emote '[act]'. Say *help for a list.</span>")
if((message && stat == CONSCIOUS))
if(client)
log_emote("[name]/[key] : [message]", src)
if(m_type & 1)
visible_message(message)
else
loc.audible_message(message)
if(regenerate_icons)
regenerate_icons()
@@ -0,0 +1,66 @@
/// Sentinel value; passing this as mood sets mood to null.
#define MOOD_RESET "reset"
/datum/emote/living/simple_animal/slime
mob_type_allowed_typecache = list(/mob/living/simple_animal/slime)
/// Apply mood of the emote. Set this to MOOD_RESET to cause the emote to reset the mood back to default.
var/mood
/datum/emote/living/simple_animal/slime/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
if(mood)
var/mob/living/simple_animal/slime/S = user
if(mood == MOOD_RESET)
S.mood = null
else
S.mood = mood
/datum/emote/living/simple_animal/slime/bounce
key = "bounce"
key_third_person = "bounces"
message = "bounces in place."
/datum/emote/living/simple_animal/slime/jiggle
key = "jiggle"
key_third_person = "jiggles"
message = "jiggles!"
/datum/emote/living/simple_animal/slime/light
key = "light"
key_third_person = "lights"
message = "lights up for a bit, then stops."
/datum/emote/living/simple_animal/slime/vibrate
key = "vibrate"
key_third_person = "vibrates"
message = "vibrates!"
/datum/emote/living/simple_animal/slime/noface
// mfw no face
key = "noface"
mood = MOOD_RESET
/datum/emote/living/simple_animal/slime/smile
key = "smile"
mood = "mischevous"
/datum/emote/living/simple_animal/slime/colon_three
key = ":3"
mood = ":33"
/datum/emote/living/simple_animal/slime/pout
key = "pout"
mood = "pout"
/datum/emote/living/simple_animal/slime/sad
key = "frown"
mood = "sad"
/datum/emote/living/simple_animal/slime/scowl
key = "scowl"
mood = "angry"
#undef MOOD_RESET
+13 -13
View File
@@ -70,26 +70,26 @@
t+= "<span class='notice'>N2O: [environment.sleeping_agent] \n</span>"
t+= "<span class='notice'>Agent B: [environment.agent_b] \n</span>"
usr.show_message(t, 1)
usr.show_message(t, EMOTE_VISIBLE)
/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
if(!client) return
if(type)
if(type & 1 && !has_vision(information_only=TRUE))//Vision related
if(type & EMOTE_VISIBLE && !has_vision(information_only=TRUE))//Vision related
if(!(alt))
return
else
msg = alt
type = alt_type
if(type & EMOTE_AUDIBLE && !can_hear())//Hearing related
if(!( alt ))
return
else
msg = alt
type = alt_type
if(type & 2 && !can_hear())//Hearing related
if(!( alt ))
return
else
msg = alt
type = alt_type
if(type & 1 && !has_vision(information_only=TRUE))
if(type & EMOTE_VISIBLE && !has_vision(information_only=TRUE))
return
// Added voice muffling for Issue 41.
if(stat == UNCONSCIOUS)
@@ -111,7 +111,7 @@
var/msg = message
if(self_message && M == src)
msg = self_message
M.show_message(msg, 1, blind_message, 2)
M.show_message(msg, EMOTE_VISIBLE, blind_message, EMOTE_AUDIBLE)
// Show a message to all mobs in sight of this atom
// Use for objects performing visible actions
@@ -121,7 +121,7 @@
for(var/mob/M in get_mobs_in_view(7, src))
if(!M.client)
continue
M.show_message(message, 1, blind_message, 2)
M.show_message(message, EMOTE_VISIBLE, blind_message, EMOTE_AUDIBLE)
// Show a message to all mobs in earshot of this one
// This would be for audible actions by the src mob
@@ -135,7 +135,7 @@
range = hearing_distance
var/msg = message
for(var/mob/M in get_mobs_in_view(range, src))
M.show_message(msg, 2, deaf_message, 1)
M.show_message(msg, EMOTE_AUDIBLE, deaf_message, EMOTE_VISIBLE)
// based on say code
var/omsg = replacetext(message, "<B>[src]</B> ", "")
@@ -161,7 +161,7 @@
if(hearing_distance)
range = hearing_distance
for(var/mob/M in get_mobs_in_view(range, src))
M.show_message(message, 2, deaf_message, 1)
M.show_message(message, EMOTE_AUDIBLE, deaf_message, EMOTE_VISIBLE)
/mob/proc/findname(msg)
for(var/mob/M in GLOB.mob_list)
+12 -2
View File
@@ -57,7 +57,7 @@
var/list/languages = list() // For speaking/listening.
var/list/abilities = list() // For species-derived or admin-given powers.
var/list/speak_emote = list("says") // Verbs used when speaking. Defaults to 'say' if speak_emote is null.
var/emote_type = 1 // Define emote default type, 1 for seen emotes, 2 for heard emotes
var/emote_type = EMOTE_VISIBLE // Define emote default type, 1 for seen emotes, 2 for heard emotes
var/name_archive //For admin things like possession
var/timeofdeath = 0 //Living
@@ -98,7 +98,17 @@
var/in_throw_mode = 0
var/emote_cd = 0 // Used to supress emote spamming. 1 if on CD, 2 if disabled by admin (manually set), else 0
// See /datum/emote
/// Cooldown on audio effects from emotes.
var/audio_emote_cd_status = EMOTE_READY
/// Override for cooldowns on non-audio emotes. Should be a number in deciseconds.
var/emote_cooldown_override = null
/// Tracks last uses of emotes for cooldown purposes
var/list/emotes_used
var/list/emotes_on_cooldown
var/job = null //Living
+192
View File
@@ -0,0 +1,192 @@
// The datum in use is defined in code/datums/emotes.dm
/**
* Send an emote.
*
* * emote_key: Key of the emote being triggered
* * m_type: Type of the emote, like EMOTE_AUDIBLE. If this is not null, the default type of the emote will be overridden.
* * message: Custom parameter for the emote. This should be used if you want to pass something like a target programmatically.
* * intentional: Whether or not the emote was deliberately triggered by the mob. If true, it's forced, which skips some checks when calling the emote.
* * force_silence: If true, unusable/nonexistent emotes will not notify the user.
*/
/mob/proc/emote(emote_key, type_override = null, message = null, intentional = FALSE, force_silence = FALSE)
emote_key = lowertext(emote_key)
var/param = message
var/custom_param_offset = findtext(emote_key, EMOTE_PARAM_SEPARATOR, 1, null)
if(custom_param_offset)
param = copytext(emote_key, custom_param_offset + length(emote_key[custom_param_offset]))
emote_key = copytext(emote_key, 1, custom_param_offset)
var/list/key_emotes = GLOB.emote_list[emote_key]
if(!length(key_emotes))
if(intentional && !force_silence)
to_chat(src, "<span class='notice'>'[emote_key]' emote does not exist. Say *help for a list.</span>")
else if(!intentional)
CRASH("Emote with key [emote_key] was attempted to be called, though doesn't exist!")
return FALSE
var/silenced = FALSE
for(var/datum/emote/P in key_emotes)
if(!P.check_cooldown(src, intentional))
// if an emote's on cooldown, don't spam them with messages of not being able to use it
silenced = TRUE
continue
if(P.try_run_emote(src, param, type_override, intentional))
return TRUE
if(intentional && !silenced && !force_silence)
to_chat(src, "<span class='notice'>Unusable emote '[emote_key]'. Say *help for a list.</span>")
return FALSE
/**
* Perform a custom emote.
*
* * m_type: Type of message to send.
* * message: Content of the message. If none is provided, the user will be prompted to choose the input.
* * intentional: Whether or not the user intendeded to perform the emote.
*/
/mob/proc/custom_emote(m_type = EMOTE_VISIBLE, message = null, intentional = FALSE)
var/input = ""
if(!message && !client)
CRASH("An empty custom emote was called from a client-less mob.")
else if (!message)
input = sanitize(copytext(input(src,"Choose an emote to display.") as text|null, 1, MAX_MESSAGE_LEN))
else
input = message
emote("me", m_type, input, intentional)
/**
* Get a list of all emote keys usable by the current mob.
*
* * intentional_use: Whether or not to check based on if the action was intentional.
*/
/mob/proc/usable_emote_keys(intentional_use = TRUE)
var/list/all_keys = list()
for(var/key in GLOB.emote_list)
for(var/datum/emote/P in GLOB.emote_list[key])
if(P.key in all_keys)
continue
if(P.can_run_emote(src, status_check = FALSE, intentional = null))
all_keys += P.key
if(P.key_third_person)
all_keys += P.key_third_person
return all_keys
/datum/emote/help
key = "help"
mob_type_ignore_stat_typecache = list(/mob/dead/observer, /mob/living/silicon/ai)
/datum/emote/help/run_emote(mob/user, params, type_override, intentional)
. = ..()
var/list/base_keys = list()
var/list/all_keys = list()
var/list/species_emotes = list()
var/list/message = list("Available emotes, you can use them with say \"*emote\": ")
var/mob/living/carbon/human/H = user
for(var/key in GLOB.emote_list)
for(var/datum/emote/P in GLOB.emote_list[key])
var/full_key = P.key
if(P.key in all_keys)
continue
if(P.can_run_emote(user, status_check = FALSE, intentional = TRUE))
if(P.message_param && P.param_desc)
// Add our parameter description, like flap-user
full_key = P.key + "\[[EMOTE_PARAM_SEPARATOR][P.param_desc]\]"
if(istype(H) && P.species_type_whitelist_typecache && H.dna && is_type_in_typecache(H.dna.species, P.species_type_whitelist_typecache))
species_emotes += full_key
else
base_keys += full_key
all_keys += P.key
base_keys = sortList(base_keys)
message += base_keys.Join(", ")
message += "."
message = message.Join("")
if(length(species_emotes) > 0)
species_emotes = sortList(species_emotes)
message += "\n<u>[user?.dna?.species.name] specific emotes</u> :- "
message += species_emotes.Join(", ")
message += "."
to_chat(user, message)
/datum/emote/flip
key = "flip"
key_third_person = "flips"
message = "does a flip!"
hands_use_check = TRUE
emote_type = EMOTE_VISIBLE | EMOTE_FORCE_NO_RUNECHAT // don't need an emote to see that
mob_type_allowed_typecache = list(/mob/living, /mob/dead/observer) // okay but what if we allowed ghosts to flip as well
mob_type_blacklist_typecache = list(/mob/living/carbon/brain, /mob/camera, /mob/living/silicon/ai)
mob_type_ignore_stat_typecache = list(/mob/dead/observer)
/datum/emote/flip/run_emote(mob/user, params, type_override, intentional)
if(isobserver(user))
user.SpinAnimation(5, 1)
return TRUE
var/mob/living/L = user
if(user.lying || (istype(L) && L.IsWeakened()))
message = "flops and flails around on the floor."
return ..()
else if(params)
message_param = "flips in %t's general direction."
else if(ishuman(user))
var/mob/living/carbon/human/H = user
if(istype(H.get_active_hand(), /obj/item/grab))
var/obj/item/grab/G = H.get_active_hand()
if(G && G.affecting)
if(H.buckled || G.affecting.buckled)
to_chat(user, "<span class='warning'>[G.affecting] is buckled, you can't flip around [G.affecting.p_them()]!</span>")
return TRUE
var/turf/oldloc = user.loc
var/turf/newloc = G.affecting.loc
if(isturf(oldloc) && isturf(newloc))
user.SpinAnimation(5, 1)
user.glide_for(0.6 SECONDS) // This and the glide_for below are purely arbitrary. Pick something that looks aesthetically pleasing.
user.forceMove(newloc)
G.glide_for(0.6 SECONDS)
G.affecting.forceMove(oldloc)
message = "flips over [G.affecting]!"
return ..()
user.SpinAnimation(5, 1)
if(prob(5) && ishuman(user))
message = "attempts a flip and crashes to the floor!"
sleep(0.3 SECONDS)
if(istype(L))
L.Weaken(4 SECONDS)
return ..()
. = ..()
/datum/emote/spin
key = "spin"
key_third_person = "spins"
hands_use_check = TRUE
emote_type = EMOTE_VISIBLE | EMOTE_FORCE_NO_RUNECHAT
mob_type_allowed_typecache = list(/mob/living, /mob/dead/observer)
mob_type_blacklist_typecache = list(/mob/living/carbon/brain, /mob/camera, /mob/living/silicon/ai)
mob_type_ignore_stat_typecache = list(/mob/dead/observer)
cooldown = 2 SECONDS // how long the spin takes, any faster and mobs can spin
/datum/emote/spin/run_emote(mob/user, params, type_override, intentional)
. = ..()
if(!.)
return FALSE
if(prob(95) || isobserver(user) || !ishuman(user))
user.spin(20, 1)
return TRUE
user.spin(32, 1)
to_chat(user, "<span class='warning'>You spin too much!</span>")
var/mob/living/L = user
if(istype(L))
L.Dizzy(24 SECONDS)
L.Confused(24 SECONDS)
+45
View File
@@ -744,3 +744,48 @@ GLOBAL_LIST_INIT(intents, list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM
message_admins("[src.ckey] just got booted back to lobby with no jobs enabled, but antag rolling enabled. Likely antag rolling abuse.")
return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well
return TRUE
/**
* Helper proc to determine if a mob can use emotes that make sound or not.
*/
/mob/proc/can_use_audio_emote()
switch(audio_emote_cd_status)
if(EMOTE_INFINITE) // Spam those emotes
return TRUE
if(EMOTE_ADMIN_BLOCKED) // Cooldown emotes were disabled by an admin, prevent use
return FALSE
if(EMOTE_ON_COOLDOWN) // Already on CD, prevent use
return FALSE
if(EMOTE_READY)
return TRUE
CRASH("Invalid emote type")
/**
* # Start the cooldown for an emote that plays audio.
*
* * cooldown: The amount of time that should be waited before any other audio emote can fire.
*/
/mob/proc/start_audio_emote_cooldown(cooldown = AUDIO_EMOTE_COOLDOWN)
if(!can_use_audio_emote())
return FALSE
if(audio_emote_cd_status == EMOTE_READY)
audio_emote_cd_status = EMOTE_ON_COOLDOWN // Starting cooldown
addtimer(CALLBACK(src, .proc/on_audio_emote_cooldown_end), cooldown)
return TRUE // proceed with emote
/mob/proc/on_audio_emote_cooldown_end()
if(audio_emote_cd_status == EMOTE_ON_COOLDOWN)
// only reset emotes that probably weren't set by an admin
audio_emote_cd_status = EMOTE_READY
/proc/stat_to_text(stat)
switch(stat)
if(CONSCIOUS)
return "conscious"
if(UNCONSCIOUS)
return "unconscious"
if(DEAD)
return "dead"
+12 -8
View File
@@ -2,6 +2,8 @@
#define ILLEGAL_CHARACTERS_LIST list("<" = "", ">" = "", \
"\[" = "", "]" = "", "{" = "", "}" = "")
#define USABLE_DEAD_EMOTES list("*flip", "*spin")
/mob/proc/say()
return
@@ -39,9 +41,9 @@
set_typing_indicator(FALSE, TRUE)
if(use_me)
custom_emote(usr.emote_type, message)
custom_emote(usr.emote_type, message, intentional = TRUE)
else
usr.emote(message)
usr.emote(message, intentional = TRUE)
/mob/proc/say_dead(message)
@@ -62,6 +64,13 @@
if(client.handle_spam_prevention(message, MUTE_DEADCHAT))
return
if(message in USABLE_DEAD_EMOTES)
emote(copytext(message, 2), intentional = TRUE)
log_emote(message, src)
create_log(DEADCHAT_LOG, message)
return
say_dead_direct("[pick("complains", "moans", "whines", "laments", "blubbers", "salts")], <span class='message'>\"[message]\"</span>", src)
create_log(DEADCHAT_LOG, message)
log_ghostsay(message, src)
@@ -110,12 +119,6 @@
verb = "asks"
return verb
/mob/proc/emote(act, type, message, force)
if(act == "me")
return custom_emote(type, message)
/mob/proc/get_ear()
// returns an atom representing a location on the map from which this
// mob can hear things
@@ -220,4 +223,5 @@
. += S.message + " "
. = trim_right(.)
#undef USABLE_DEAD_EMOTES
#undef ILLEGAL_CHARACTERS_LIST
+1 -1
View File
@@ -106,7 +106,7 @@
if(blood_volume)
blood_volume = max(blood_volume - amt, 0)
if(prob(10 * amt)) // +5% chance per internal bleeding site that we'll cough up blood on a given tick.
custom_emote(1, "coughs up blood!")
custom_emote(EMOTE_VISIBLE, "coughs up blood!")
add_splatter_floor(loc, 1)
return 1
else if(amt >= 1 && prob(5 * amt)) // +2.5% chance per internal bleeding site that we'll cough up blood on a given tick. Must be bleeding internally in more than one place to have a chance at this.
+2 -2
View File
@@ -77,10 +77,10 @@
if(is_bruised())
if(prob(2) && !(NO_BLOOD in owner.dna.species.species_traits))
owner.custom_emote(1, "coughs up blood!")
owner.custom_emote(EMOTE_VISIBLE, "coughs up blood!")
owner.bleed(1)
if(prob(4))
owner.custom_emote(1, "gasps for air!")
owner.custom_emote(EMOTE_VISIBLE, "gasps for air!")
owner.AdjustLoseBreath(10 SECONDS)
/obj/item/organ/internal/lungs/proc/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H)
@@ -181,7 +181,7 @@
I.receive_damage(brute * 0.5)
brute -= brute * 0.5
if(status & ORGAN_BROKEN && prob(40) && brute)
if(status & ORGAN_BROKEN && prob(40) && brute && !owner.stat)
owner.emote("scream") //getting hit on broken hand hurts
if(status & ORGAN_SPLINTED && prob((brute + burn)*4)) //taking damage to splinted limbs removes the splints
status &= ~ORGAN_SPLINTED
@@ -627,7 +627,7 @@ Note that amputating the affected organ does in fact remove the infection from t
)
to_chat(owner, "<span class='userdanger'>Something feels like it shattered in your [name]!</span>")
playsound(owner, "bonebreak", 150, 1)
if(!HAS_TRAIT(owner, TRAIT_NOPAIN))
if(!HAS_TRAIT(owner, TRAIT_NOPAIN) && !owner.stat)
owner.emote("scream")
status |= ORGAN_BROKEN
@@ -62,7 +62,7 @@
if(hand && owner.canUnEquip(hand))
owner.unEquip(hand)
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, dropping what it was holding!</span>")
owner.custom_emote(1, "drops what [owner.p_they()] [owner.p_were()] holding, [owner.p_their()] [name] malfunctioning!")
owner.custom_emote(EMOTE_VISIBLE, "drops what [owner.p_they()] [owner.p_were()] holding, [owner.p_their()] [name] malfunctioning!")
/obj/item/organ/external/arm/right
limb_name = "r_arm"
@@ -92,10 +92,10 @@
return
if(owner.AmountWeakened())
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, preventing you from getting back up!</span>")
owner.custom_emote(1, "is unable to get back up, [owner.p_their()] [name] malfunctioning!")
owner.custom_emote(EMOTE_VISIBLE, "is unable to get back up, [owner.p_their()] [name] malfunctioning!")
else
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, dropping you to the ground!</span>")
owner.custom_emote(1, "drops to the ground, [owner.p_their()] [name] malfunctioning!")
owner.custom_emote(EMOTE_VISIBLE, "drops to the ground, [owner.p_their()] [name] malfunctioning!")
switch(severity)
if(1)
owner.AdjustWeakened(8 SECONDS)
@@ -130,10 +130,10 @@
return
if(owner.AmountWeakened())
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, preventing you from getting back up!</span>")
owner.custom_emote(1, "is unable to get back up, [owner.p_their()] [name] malfunctioning!")
owner.custom_emote(EMOTE_VISIBLE, "is unable to get back up, [owner.p_their()] [name] malfunctioning!")
else
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, dropping you to the ground!</span>")
owner.custom_emote(1, "drops to the ground, [owner.p_their()] [name] malfunctioning!")
owner.custom_emote(EMOTE_VISIBLE, "drops to the ground, [owner.p_their()] [name] malfunctioning!")
switch(severity)
if(1)
owner.AdjustWeakened(8 SECONDS)
@@ -173,7 +173,7 @@
if(hand && owner.canUnEquip(hand))
owner.unEquip(hand)
to_chat(owner, "<span class='userdanger'>Your [name] malfunctions, dropping what it was holding!</span>")
owner.custom_emote(1, "drops what [owner.p_they()] [owner.p_were()] holding, [owner.p_their()] [name] malfunctioning!")
owner.custom_emote(EMOTE_VISIBLE, "drops what [owner.p_they()] [owner.p_were()] holding, [owner.p_their()] [name] malfunctioning!")
/obj/item/organ/external/hand/remove()
if(owner)
+1
View File
@@ -5,6 +5,7 @@
#include "component_tests.dm"
#include "config_sanity.dm"
#include "crafting_lists.dm"
#include "emotes.dm"
#include "log_format.dm"
#include "map_templates.dm"
#include "purchase_reference_test.dm"
+29
View File
@@ -0,0 +1,29 @@
/datum/unit_test/emote/Run()
// be aware that some of these values (like message, message_param) are subject to being set at runtime.
for(var/emote_type in subtypesof(/datum/emote))
var/datum/emote/cur_emote = new emote_type()
if(cur_emote.message_param && !cur_emote.param_desc)
Fail("emote [cur_emote] was given a message parameter without a description.")
// Sanity checks, these emotes probably won't appear to a user but we should make sure they're cleaned up.
if(!cur_emote.key)
if(cur_emote.message || cur_emote.message_param)
Fail("emote [cur_emote] is missing a key but has a message defined.")
if(cur_emote.key_third_person)
Fail("emote [cur_emote] has a third-person key defined, but no first-person key. Either first person, both, or neither should be defined.")
// These are ones that might appear to a user, and so could use some special handling.
else
if(isnull(cur_emote.emote_type))
Fail("emote [cur_emote] has a null target type.")
if(isnum(cur_emote.max_stat_allowed) && cur_emote.max_stat_allowed < cur_emote.stat_allowed)
Fail("emote [cur_emote]'s max_stat_allowed is greater than its stat_allowed, and would be unusable.")
if(isnum(cur_emote.max_unintentional_stat_allowed) && cur_emote.max_unintentional_stat_allowed < cur_emote.unintentional_stat_allowed)
Fail("emote [cur_emote]'s max_unintentional_stat_allowed is greater than its unintentional_stat_allowed, and would be unusable.")
/datum/unit_test/emote/proc/has_punctuation(datum/emote/E, msg)
return E.remove_ending_punctuation(msg) == msg