From 60d27e07de73f0fe72f4cff78b9c4100fd1d3b19 Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Wed, 25 Feb 2015 01:14:06 -0500 Subject: [PATCH] Emote Cooldown System Introduces the Emote Cooldown System, designed to prevent spamming of sound-based emotes. Emotes that respect the cooldown: - *beep - *buzz - *ping - *squish - *scream - *fart - *chirp - *law Emotes that are exempt: - Everything not listed above Emotes can be added to the system easily, and all cooldown-incurring emotes share a single cooldown. This means you have to wait to *scream after you *fart. Also adds Tigercat's *squish emote ( #394 ), with sound credit to DrMinky(Freesound.org). This emote is only usable by Slime People, and accepts a parameter if you wish to squish at something/someone. Admins with +VAREDIT can manually disable the use of cooldown emotes for a specific mob by setting the emote_cd var to 2. --- code/modules/mob/emote.dm | 15 ++ code/modules/mob/living/carbon/human/emote.dm | 133 +++++++++++------- .../modules/mob/living/carbon/monkey/emote.dm | 27 +++- code/modules/mob/living/carbon/monkey/say.dm | 28 ++++ .../modules/mob/living/silicon/robot/emote.dm | 15 ++ code/modules/mob/mob_defines.dm | 2 + paradise.dme | 1 + sound/effects/slime_squish.ogg | Bin 0 -> 12231 bytes 8 files changed, 166 insertions(+), 55 deletions(-) create mode 100644 code/modules/mob/living/carbon/monkey/say.dm create mode 100644 sound/effects/slime_squish.ogg diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index 32af0998702..25c712354ce 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -1,3 +1,18 @@ +#define EMOTE_COOLDOWN 50 //Time in deciseconds that the cooldown lasts + +//Emote Cooldown System (it's so simple!) +/mob/proc/handle_emote_CD() + if(emote_cd == 2) return 1 // Cooldown emotes were disabled by an admin, prevent use + if(src.emote_cd == 1) return 1 // Already on CD, prevent use + + src.emote_cd = 1 // Starting cooldown + spawn(EMOTE_COOLDOWN) + if(emote_cd == 2) return 1 // Don't reset if cooldown emotes were disabled by an admin during the cooldown + src.emote_cd = 0 // Cooldown complete, ready for more! + + return 0 // Proceed with emote +//--FalseIncarnate + // All mobs should have custom emote, really.. /mob/proc/custom_emote(var/m_type=1,var/message = null) diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 65c9d41c478..b2cf5cea48f 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -20,69 +20,100 @@ if(src.stat == 2.0 && (act != "deathgasp")) return + + //Emote Cooldown System (it's so simple!) + // proc/handle_emote_CD() located in [code\modules\mob\emote.dm] + var/on_CD = 0 + switch(act) + //Cooldown-inducing emotes + if("ping","buzz","beep") + if (species.name == "Machine") //Only Machines can beep, ping, and buzz + on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm + else //Everyone else fails, skip the emote attempt + return + if("squish") + if(species.name == "Slime People") //Only Slime People can squish + on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm + else //Everyone else fails, skip the emote attempt + return + if("scream", "fart", "flip") + 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(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") - if (species.name == "Machine") - var/M = null - if(param) - for (var/mob/A in view(null, null)) - if (param == A.name) - M = A - break - if(!M) - param = null + var/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 = "[src] pings at [param]." - else - message = "[src] pings." - playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) - m_type = 1 + if (param) + message = "[src] pings at [param]." else - if (!species.name == "Machine") - return + message = "[src] pings." + playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) + m_type = 1 if("buzz") - if (species.name == "Machine") - var/M = null - if(param) - for (var/mob/A in view(null, null)) - if (param == A.name) - M = A - break - if(!M) - param = null + var/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 = "[src] buzzes at [param]." - else - message = "[src] buzzes." - playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0) - m_type = 1 + if (param) + message = "[src] buzzes at [param]." else - if (!species.name == "Machine") - return + message = "[src] buzzes." + playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + m_type = 1 if("beep") - if(species.name == "Machine") - var/M = null - if(param) - for (var/mob/A in view(null, null)) - if (param == A.name) - M = A - break - if(!M) - param = null + var/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 = "[src] beeps at [param]." - else - message = "[src] beeps." - playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) - m_type = 1 + if (param) + message = "[src] beeps at [param]." else - if (!species.name == "Machine") - return + message = "[src] beeps." + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) + m_type = 1 + + if("squish") + 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 = "[src] squishes at [param]." + else + message = "[src] squishes." + playsound(src.loc, 'sound/effects/slime_squish.ogg', 50, 0) //Credit to DrMinky (freesound.org) for the sound. + m_type = 1 if("wag") if(species.bodyflags & TAIL_WAGGING) diff --git a/code/modules/mob/living/carbon/monkey/emote.dm b/code/modules/mob/living/carbon/monkey/emote.dm index 706029df8c9..0f19e93c326 100644 --- a/code/modules/mob/living/carbon/monkey/emote.dm +++ b/code/modules/mob/living/carbon/monkey/emote.dm @@ -11,6 +11,26 @@ var/muzzled = is_muzzled() + //Emote Cooldown System (it's so simple!) + // proc/handle_emote_CD() located in [code\modules\mob\emote.dm] + var/on_CD = 0 + switch(act) + //Cooldown-inducing emotes + if("chirp") + if(istype(src,/mob/living/carbon/monkey/diona)) //Only Diona Nymphs can chirp + on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm + else //Everyone else fails, skip the emote attempt + return + if("flip") + on_CD = handle_emote_CD() + //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(on_CD == 1) // Check if we need to suppress the emote attempt. + return // Suppress emote, you're still cooling off. + //--FalseIncarnate + switch(act) if ("me") if(silent) @@ -32,10 +52,9 @@ return custom_emote(m_type, message) if ("chirp") - if(istype(src,/mob/living/carbon/monkey/diona)) - message = "The [src.name] chirps!" - playsound(src.loc, 'sound/misc/nymphchirp.ogg', 50, 0) - m_type = 2 + message = "The [src.name] chirps!" + playsound(src.loc, 'sound/misc/nymphchirp.ogg', 50, 0) + m_type = 2 if("sign") if (!src.restrained()) message = text("The monkey signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null)) diff --git a/code/modules/mob/living/carbon/monkey/say.dm b/code/modules/mob/living/carbon/monkey/say.dm new file mode 100644 index 00000000000..9a629c358fc --- /dev/null +++ b/code/modules/mob/living/carbon/monkey/say.dm @@ -0,0 +1,28 @@ +/mob/living/carbon/monkey/say(var/message) + var/verb = "says" + var/message_range = world.view + + if(client) + if(client.prefs.muted & MUTE_IC) + src << "\red You cannot speak in IC (Muted)." + return + + message = trim_strip_html_properly(message) + + if(stat == 2) + return say_dead(message) + + if(copytext(message,1,2) == "*") + return emote(copytext(message,2)) + + var/datum/language/speaking = parse_language(message) + + if(speaking) + message = copytext(message, 2+length(speaking.key)) + + message = trim(message) + + if(!message || stat) + return + + ..(message, speaking, verb, null, null, message_range, null) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm index 6bf18971ba6..8efab8a0f57 100644 --- a/code/modules/mob/living/silicon/robot/emote.dm +++ b/code/modules/mob/living/silicon/robot/emote.dm @@ -8,6 +8,21 @@ 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!) + // proc/handle_emote_CD() located in [code\modules\mob\emote.dm] + var/on_CD = 0 + switch(act) + //Cooldown-inducing emotes + if("ping","buzz","beep","law") //halt is exempt because it's used to stop criminal scum + 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(on_CD == 1) // Check if we need to suppress the emote attempt. + return // Suppress emote, you're still cooling off. + //--FalseIncarnate + switch(act) if ("me") if (src.client) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index b91583758af..7aa2f58efca 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -138,6 +138,8 @@ var/coughedtime = null + var/emote_cd = 0 // Used to supress emote spamming. 1 if on CD, 2 if disabled by admin (manually set), else 0 + var/inertia_dir = 0 var/music_lastplayed = "null" diff --git a/paradise.dme b/paradise.dme index c7692b54575..40cb30de985 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1301,6 +1301,7 @@ #include "code\modules\mob\living\carbon\monkey\login.dm" #include "code\modules\mob\living\carbon\monkey\monkey.dm" #include "code\modules\mob\living\carbon\monkey\powers.dm" +#include "code\modules\mob\living\carbon\monkey\say.dm" #include "code\modules\mob\living\carbon\monkey\update_icons.dm" #include "code\modules\mob\living\silicon\death.dm" #include "code\modules\mob\living\silicon\login.dm" diff --git a/sound/effects/slime_squish.ogg b/sound/effects/slime_squish.ogg new file mode 100644 index 0000000000000000000000000000000000000000..60e118e217b470689b792a4adf9cbf950114811e GIT binary patch literal 12231 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 UoxQD^ZQ|CCNoF5#OV literal 0 HcmV?d00001