mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-21 12:08:55 +01:00
## About The Pull Request Deletes `can_hear`, replaces it with trait-checking deafness. The only two non-trait sources of deafness (hardcrit and lacking ears) were refactored into using the trait. ## Why It's Good For The Game Many places inconsistently check for the deaf trait rather than use can_hear which meant behavior was not consistent. Some code would treat "do we lack ears?" as being deaf, some would not. This unifies all the behavior so being deaf means you're deaf everywhere. It also means we can now easily react to gaining and losing deafness via signal, where before we could not react to it without hooking the trait, organ remove, AND stat change. Which no one did, of course, because who would ever think to do that? ## Changelog 🆑 Melbert refactor: Refactored how deafness is tracked. Please report any weird interactions with sounds, like messages or sfx being missing. fix: Lacking ears and being in hard crit now consistently treats you as "being deaf". This affects a few minor interactions like empath, the jukebox, and sleeping. /🆑
485 lines
21 KiB
Plaintext
485 lines
21 KiB
Plaintext
#define COOLDOWN_STUN (120 SECONDS)
|
|
#define COOLDOWN_DAMAGE (60 SECONDS)
|
|
#define COOLDOWN_MEME (30 SECONDS)
|
|
#define COOLDOWN_NONE (10 SECONDS)
|
|
|
|
/// Used to stop listeners with silly or clown-esque (first) names such as "Honk" or "Flip" from screwing up certain commands.
|
|
GLOBAL_DATUM(all_voice_of_god_triggers, /regex)
|
|
/// List of all voice of god commands
|
|
GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands())
|
|
|
|
/proc/init_voice_of_god_commands()
|
|
. = list()
|
|
var/all_triggers
|
|
var/separator
|
|
for(var/datum/voice_of_god_command/prototype as anything in subtypesof(/datum/voice_of_god_command))
|
|
var/init_trigger = initial(prototype.trigger)
|
|
if(!init_trigger)
|
|
continue
|
|
. += new prototype
|
|
all_triggers += "[separator][init_trigger]"
|
|
separator = "|" // Shouldn't be at the start or end of the regex, or it won't work.
|
|
GLOB.all_voice_of_god_triggers = regex(all_triggers, "i")
|
|
|
|
/*
|
|
* The main proc for the voice of god power. it makes the user shout a message in an ominous way,
|
|
* The first matching command (from a list of static datums) the listeners must obey,
|
|
* and the return value of this proc the cooldown variable of the command dictates. (only relevant for things with cooldowns i guess)
|
|
*/
|
|
/proc/voice_of_god(message, mob/living/user, list/span_list, base_multiplier = 1, include_speaker = FALSE, forced = null, ignore_spam = FALSE)
|
|
var/log_message = uppertext(message)
|
|
var/is_cultie = IS_CULTIST(user)
|
|
if(LAZYLEN(span_list) && is_cultie)
|
|
span_list = list("narsiesmall")
|
|
|
|
if(!user.say(message, spans = span_list, sanitize = FALSE, ignore_spam = ignore_spam, forced = forced))
|
|
return
|
|
|
|
message = LOWER_TEXT(message)
|
|
|
|
var/list/mob/living/listeners = list()
|
|
//used to check if the speaker specified a name or a job to focus on
|
|
var/list/specific_listeners = list()
|
|
// string to remove at the end of the following of the following loop, so saying "Burn Mr. Hopkins" doesn't also burn the HoP later when we check jobs.
|
|
var/to_remove_string
|
|
var/list/candidates = get_hearers_in_view(8, user) - (include_speaker ? null : user)
|
|
for(var/mob/living/candidate in candidates)
|
|
if(candidate.stat != DEAD && !HAS_TRAIT(candidate, TRAIT_DEAF))
|
|
if(candidate.can_block_magic(MAGIC_RESISTANCE_HOLY|MAGIC_RESISTANCE_MIND, charge_cost = 0))
|
|
to_chat(user, span_userdanger("Something's wrong! [candidate] seems to be resisting your commands."))
|
|
continue
|
|
|
|
listeners += candidate
|
|
|
|
//Let's ensure the listener's name is not matched within another word or command (and vice-versa). e.g. "Saul" in "somersault"
|
|
var/their_first_name = first_name(candidate.name)
|
|
if(!GLOB.all_voice_of_god_triggers.Find(their_first_name) && findtext(message, regex("(\\L|^)[their_first_name](\\L|$)", "i")))
|
|
specific_listeners += candidate //focus on those with the specified name
|
|
to_remove_string += "[to_remove_string ? "|" : null][their_first_name]"
|
|
continue
|
|
var/their_last_name = last_name(candidate.name)
|
|
if(their_last_name != their_first_name && !GLOB.all_voice_of_god_triggers.Find(their_last_name) && findtext(message, regex("(\\L|^)[their_last_name](\\L|$)", "i")))
|
|
specific_listeners += candidate // Ditto
|
|
to_remove_string += "[to_remove_string ? "|" : null][their_last_name]"
|
|
|
|
if(!listeners.len)
|
|
return
|
|
if(to_remove_string)
|
|
to_remove_string = "(\\L|^)([to_remove_string])(\\L|$)"
|
|
message = replacetext(message, regex(to_remove_string, "i"), "")
|
|
|
|
var/power_multiplier = base_multiplier * (user.mind?.assigned_role.voice_of_god_power || 1)
|
|
|
|
//Cultists are closer to their gods and are more powerful, but they'll give themselves away
|
|
if(is_cultie)
|
|
power_multiplier *= 2
|
|
|
|
//Now get the proper job titles and check for matches.
|
|
var/job_message = get_full_job_name(message)
|
|
for(var/mob/living/candidate in candidates)
|
|
var/their_role = candidate.mind?.assigned_role.title
|
|
if(their_role && findtext(job_message, their_role))
|
|
specific_listeners |= candidate //focus on those with the specified job. "|=" instead "+=" so "Mrs. Capri the Captain" doesn't get affected twice.
|
|
|
|
if(specific_listeners.len)
|
|
listeners = specific_listeners
|
|
power_multiplier *= (1 + (1/specific_listeners.len)) //2x on a single guy, 1.5x on two and so on
|
|
|
|
for(var/datum/voice_of_god_command/command as anything in GLOB.voice_of_god_commands)
|
|
if(findtext(message, command.trigger))
|
|
. = command.execute(listeners, user, power_multiplier, message) || command.cooldown
|
|
break
|
|
|
|
if(!forced)
|
|
message_admins("[ADMIN_LOOKUPFLW(user)] said '[log_message]' with Voice of God, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].")
|
|
user.log_message("said '[log_message]' with Voice of God[forced ? " forced by [forced]" : ""], affecting [english_list(listeners)], with a power multiplier of [power_multiplier].", LOG_GAME, color="red")
|
|
SSblackbox.record_feedback("tally", "voice_of_god", 1, log_message)
|
|
|
|
/// Voice of god command datums that are used in [/proc/voice_of_god()]
|
|
/datum/voice_of_god_command
|
|
///a text string or regex that triggers the command.
|
|
var/trigger
|
|
/// Is the trigger supposed to be a regex? If so, convert it to such on New()
|
|
var/is_regex = TRUE
|
|
/// cooldown variable which is normally returned to [proc/voice_of_god] and used as its return value.
|
|
var/cooldown = COOLDOWN_MEME
|
|
|
|
/datum/voice_of_god_command/New()
|
|
if(is_regex)
|
|
trigger = regex(trigger)
|
|
|
|
/*
|
|
* What happens when the command is triggered.
|
|
* If a return value is set, it'll be used in place of the 'cooldown' var.
|
|
* Args:
|
|
* * listeners: the list of living mobs who are affected by the command.
|
|
* * user: the one who casted Voice of God
|
|
* * power_multiplier: multiplies the power of the command, most times.
|
|
*/
|
|
/datum/voice_of_god_command/proc/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
return
|
|
|
|
/// This command knocks the listeners down.
|
|
/datum/voice_of_god_command/knockdown
|
|
trigger = "drop|fall|trip|knockdown"
|
|
cooldown = COOLDOWN_STUN
|
|
|
|
/datum/voice_of_god_command/knockdown/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.Knockdown(4 SECONDS * power_multiplier)
|
|
|
|
/// This command stops the listeners from moving.
|
|
/datum/voice_of_god_command/immobilize
|
|
trigger = "stop|wait|stand\\s*still|hold\\s*on|halt"
|
|
cooldown = COOLDOWN_STUN
|
|
|
|
/datum/voice_of_god_command/immobilize/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.Immobilize(4 SECONDS * power_multiplier)
|
|
|
|
/// This command makes carbon listeners throw up like Mr. Creosote.
|
|
/datum/voice_of_god_command/vomit
|
|
trigger = "vomit|throw\\s*up|sick"
|
|
cooldown = COOLDOWN_STUN
|
|
|
|
/datum/voice_of_god_command/vomit/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/carbon/target in listeners)
|
|
target.vomit(vomit_flags = (MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM), lost_nutrition = (power_multiplier * 10), distance = power_multiplier)
|
|
|
|
/// This command silences the listeners. Thrice as effective is the user is a mime or curator.
|
|
/datum/voice_of_god_command/silence
|
|
trigger = "shut\\s*up|silence|be\\s*silent|ssh|quiet|hush"
|
|
cooldown = COOLDOWN_STUN
|
|
|
|
/datum/voice_of_god_command/silence/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
power_multiplier *= user.mind?.assigned_role?.voice_of_god_silence_power || 1
|
|
for(var/mob/living/carbon/target in listeners)
|
|
target.adjust_silence(20 SECONDS * power_multiplier)
|
|
|
|
/// This command makes the listeners see others as corgis, carps, skellies etcetera etcetera.
|
|
/datum/voice_of_god_command/hallucinate
|
|
trigger = "see\\s*the\\s*truth|hallucinate"
|
|
|
|
/datum/voice_of_god_command/hallucinate/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target in listeners)
|
|
target.cause_hallucination( \
|
|
get_random_valid_hallucination_subtype(/datum/hallucination/delusion/preset), \
|
|
"voice of god", \
|
|
duration = 15 SECONDS * power_multiplier, \
|
|
affects_us = FALSE, \
|
|
affects_others = TRUE, \
|
|
skip_nearby = FALSE, \
|
|
)
|
|
|
|
/// This command wakes up the listeners.
|
|
/datum/voice_of_god_command/wake_up
|
|
trigger = "wake\\s*up|awaken"
|
|
cooldown = COOLDOWN_DAMAGE
|
|
|
|
/datum/voice_of_god_command/wake_up/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.SetSleeping(0)
|
|
|
|
/// This command heals the listeners for 10 points of total damage.
|
|
/datum/voice_of_god_command/heal
|
|
trigger = "live|heal|survive|mend|life|heroes\\s*never\\s*die"
|
|
cooldown = COOLDOWN_DAMAGE
|
|
|
|
/datum/voice_of_god_command/heal/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.heal_overall_damage(10 * power_multiplier, 10 * power_multiplier)
|
|
|
|
/// This command applies 15 points of brute damage to the listeners. There's subtle theological irony in this being more powerful than healing.
|
|
/datum/voice_of_god_command/brute
|
|
trigger = "die|suffer|hurt|pain|death"
|
|
cooldown = COOLDOWN_DAMAGE
|
|
|
|
/datum/voice_of_god_command/brute/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.apply_damage(15 * power_multiplier, def_zone = BODY_ZONE_CHEST, wound_bonus = CANT_WOUND)
|
|
|
|
/// This command makes carbon listeners bleed from a random body part.
|
|
/datum/voice_of_god_command/bleed
|
|
trigger = "bleed|there\\s*will\\s*be\\s*blood"
|
|
cooldown = COOLDOWN_DAMAGE
|
|
|
|
/datum/voice_of_god_command/bleed/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/carbon/human/target in listeners)
|
|
var/obj/item/bodypart/chosen_part = pick(target.bodyparts)
|
|
chosen_part.adjustBleedStacks(5)
|
|
|
|
/// This command sets the listeners ablaze.
|
|
/datum/voice_of_god_command/burn
|
|
trigger = "burn|ignite"
|
|
cooldown = COOLDOWN_DAMAGE
|
|
|
|
/datum/voice_of_god_command/burn/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.adjust_fire_stacks(1 * power_multiplier)
|
|
target.ignite_mob()
|
|
|
|
/// This command heats the listeners up like boiling water.
|
|
/datum/voice_of_god_command/hot
|
|
trigger = "heat|hot|hell"
|
|
cooldown = COOLDOWN_DAMAGE
|
|
|
|
/datum/voice_of_god_command/hot/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.adjust_bodytemperature(50 * power_multiplier)
|
|
|
|
/// This command cools the listeners down like freezing water.
|
|
/datum/voice_of_god_command/cold
|
|
trigger = "cold|chill|freeze"
|
|
cooldown = COOLDOWN_DAMAGE
|
|
|
|
/datum/voice_of_god_command/cold/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.adjust_bodytemperature(-50 * power_multiplier)
|
|
|
|
/// This command throws the listeners away from the user.
|
|
/datum/voice_of_god_command/repulse
|
|
trigger = "shoo|go\\s*away|leave\\s*me\\s*alone|begone|flee|fus\\s*ro\\s*dah|get\\s*away|repulse"
|
|
cooldown = COOLDOWN_DAMAGE
|
|
|
|
/datum/voice_of_god_command/repulse/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
var/throwtarget = get_edge_target_turf(user, get_dir(user, get_step_away(target, user)))
|
|
target.throw_at(throwtarget, 3 * power_multiplier, 1 * power_multiplier)
|
|
|
|
/// This command throws the listeners at the user.
|
|
/datum/voice_of_god_command/attract
|
|
trigger = "come\\s*here|come\\s*to\\s*me|get\\s*over\\s*here|attract"
|
|
cooldown = COOLDOWN_DAMAGE
|
|
|
|
/datum/voice_of_god_command/attract/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.throw_at(get_step_towards(user, target), 3 * power_multiplier, 1 * power_multiplier)
|
|
|
|
/// This command forces the listeners to say their true name (so masks and hoods won't help).
|
|
/// Basic and simple mobs who are forced to state their name and don't have one already will... reveal their actual one!
|
|
/datum/voice_of_god_command/who_are_you
|
|
trigger = "who\\s*are\\s*you|say\\s*your\\s*name|state\\s*your\\s*name|identify"
|
|
|
|
/datum/voice_of_god_command/who_are_you/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
var/iteration = 1
|
|
for(var/mob/living/target as anything in listeners)
|
|
addtimer(CALLBACK(src, PROC_REF(state_name), target), 0.5 SECONDS * iteration)
|
|
iteration++
|
|
|
|
///just states the target's name, but also includes the renaming funny.
|
|
/datum/voice_of_god_command/who_are_you/proc/state_name(mob/living/target)
|
|
if(QDELETED(target))
|
|
return
|
|
var/gold_core_spawnable = NO_SPAWN
|
|
if(isbasicmob(target))
|
|
var/mob/living/basic/basic_bandy = target
|
|
gold_core_spawnable = basic_bandy.gold_core_spawnable
|
|
else if(isanimal(target))
|
|
var/mob/living/simple_animal/simple_sandy = target
|
|
gold_core_spawnable = simple_sandy.gold_core_spawnable
|
|
if(target.name == initial(target.name) && gold_core_spawnable == FRIENDLY_SPAWN)
|
|
var/canonical_deep_lore_name
|
|
switch(target.gender)
|
|
if(MALE)
|
|
canonical_deep_lore_name = pick(GLOB.first_names_male)
|
|
if(FEMALE)
|
|
canonical_deep_lore_name = pick(GLOB.first_names_female)
|
|
else
|
|
canonical_deep_lore_name = pick(GLOB.first_names)
|
|
target.fully_replace_character_name(target.real_name, canonical_deep_lore_name)
|
|
target.say(target.real_name)
|
|
|
|
/// This command forces the listeners to say the user's name
|
|
/datum/voice_of_god_command/say_my_name
|
|
trigger = "say\\s*my\\s*name|who\\s*am\\s*i"
|
|
|
|
/datum/voice_of_god_command/say_my_name/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
var/iteration = 1
|
|
var/regex/smartass_regex = regex(@"^say my name[.!]*$")
|
|
for(var/mob/living/target as anything in listeners)
|
|
var/to_say = user.name
|
|
// 0.1% chance to be a smartass
|
|
if(findtext(LOWER_TEXT(message), smartass_regex) && prob(0.1))
|
|
to_say = "My name"
|
|
addtimer(CALLBACK(target, TYPE_PROC_REF(/atom/movable, say), to_say), 0.5 SECONDS * iteration)
|
|
iteration++
|
|
|
|
/// This command forces the listeners to say "Who's there?".
|
|
/datum/voice_of_god_command/knock_knock
|
|
trigger = "knock\\s*knock"
|
|
|
|
/datum/voice_of_god_command/knock_knock/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
var/iteration = 1
|
|
for(var/mob/living/target as anything in listeners)
|
|
addtimer(CALLBACK(target, TYPE_PROC_REF(/atom/movable, say), "Who's there?"), 0.5 SECONDS * iteration)
|
|
iteration++
|
|
|
|
/// This command forces silicon listeners to state all their laws.
|
|
/datum/voice_of_god_command/state_laws
|
|
trigger = "state\\s*(your)?\\s*laws"
|
|
|
|
/datum/voice_of_god_command/state_laws/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
var/iteration = 0
|
|
for(var/mob/living/silicon/target in listeners)
|
|
addtimer(CALLBACK(target, TYPE_PROC_REF(/mob/living/silicon, statelaws), TRUE), (3 SECONDS * iteration) + 0.5 SECONDS)
|
|
iteration++
|
|
|
|
/// This command forces the listeners to take step in a direction chosen by the user, otherwise a random cardinal one.
|
|
/datum/voice_of_god_command/move
|
|
trigger = "move|walk"
|
|
var/static/up_words = regex("up|north|fore")
|
|
var/static/down_words = regex("down|south|aft")
|
|
var/static/left_words = regex("left|west|port")
|
|
var/static/right_words = regex("right|east|starboard")
|
|
|
|
/datum/voice_of_god_command/move/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
var/iteration = 1
|
|
var/direction
|
|
if(findtext(message, up_words))
|
|
direction = NORTH
|
|
else if(findtext(message, down_words))
|
|
direction = SOUTH
|
|
else if(findtext(message, left_words))
|
|
direction = WEST
|
|
else if(findtext(message, right_words))
|
|
direction = EAST
|
|
for(var/mob/living/target as anything in listeners)
|
|
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step), target, direction || pick(GLOB.cardinals)), 1 SECONDS * (iteration - 1))
|
|
iteration++
|
|
|
|
/// This command forces the listeners to switch to walk intent.
|
|
/datum/voice_of_god_command/walk
|
|
trigger = "slow\\s*down"
|
|
|
|
/datum/voice_of_god_command/walk/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
if(target.move_intent != MOVE_INTENT_WALK)
|
|
target.toggle_move_intent()
|
|
|
|
/// This command forces the listeners to switch to run intent.
|
|
/datum/voice_of_god_command/run
|
|
trigger = "run"
|
|
is_regex = FALSE
|
|
|
|
/datum/voice_of_god_command/walk/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
if(target.move_intent != MOVE_INTENT_RUN)
|
|
target.toggle_move_intent()
|
|
|
|
/// This command turns the listeners' throw mode on.
|
|
/datum/voice_of_god_command/throw_catch
|
|
trigger = "throw|catch"
|
|
|
|
/datum/voice_of_god_command/throw_catch/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/carbon/target in listeners)
|
|
target.throw_mode_on(THROW_MODE_TOGGLE)
|
|
|
|
/// This command forces the listeners to say a brain damage line.
|
|
/datum/voice_of_god_command/speak
|
|
trigger = "speak|say\\s*something"
|
|
|
|
/datum/voice_of_god_command/speak/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
var/iteration = 1
|
|
for(var/mob/living/target in listeners)
|
|
addtimer(CALLBACK(target, TYPE_PROC_REF(/atom/movable, say), pick_list_replacements(BRAIN_DAMAGE_FILE, "brain_damage")), 0.5 SECONDS * iteration)
|
|
iteration++
|
|
|
|
/// This command forces the listeners to get the fuck up, resetting all stuns.
|
|
/datum/voice_of_god_command/getup
|
|
trigger = "get\\s*up"
|
|
cooldown = COOLDOWN_DAMAGE
|
|
|
|
/datum/voice_of_god_command/getup/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.set_resting(FALSE)
|
|
target.SetAllImmobility(0)
|
|
|
|
/// This command forces each listener to buckle to a chair found on the same tile.
|
|
/datum/voice_of_god_command/sit
|
|
trigger = "sit"
|
|
is_regex = FALSE
|
|
|
|
/datum/voice_of_god_command/sit/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
var/obj/structure/chair/chair = locate(/obj/structure/chair) in get_turf(target)
|
|
chair?.buckle_mob(target)
|
|
|
|
/// This command forces each listener to unbuckle from whatever they are buckled to.
|
|
/datum/voice_of_god_command/stand
|
|
trigger = "stand"
|
|
is_regex = FALSE
|
|
|
|
/datum/voice_of_god_command/stand/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.buckled?.unbuckle_mob(target)
|
|
|
|
/// This command forces the listener to do the jump emote 3/4 of the times or reply "HOW HIGH?!!".
|
|
/datum/voice_of_god_command/jump
|
|
trigger = "jump"
|
|
is_regex = FALSE
|
|
|
|
/datum/voice_of_god_command/jump/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
var/iteration = 1
|
|
for(var/mob/living/target as anything in listeners)
|
|
if(prob(25))
|
|
addtimer(CALLBACK(target, TYPE_PROC_REF(/atom/movable, say), "HOW HIGH?!!"), 0.5 SECONDS * iteration)
|
|
else
|
|
addtimer(CALLBACK(target, TYPE_PROC_REF(/mob/living/, emote), "jump"), 0.5 SECONDS * iteration)
|
|
iteration++
|
|
|
|
///This command plays a bikehorn sound after 2 seconds and a half have passed, and also slips listeners if the user is a clown.
|
|
/datum/voice_of_god_command/honk
|
|
trigger = "ho+nk"
|
|
|
|
/datum/voice_of_god_command/honk/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), get_turf(user), 'sound/items/bikehorn.ogg', 300, 1), 2.5 SECONDS)
|
|
if(is_clown_job(user.mind?.assigned_role))
|
|
. = COOLDOWN_STUN //it slips.
|
|
for(var/mob/living/carbon/target in listeners)
|
|
target.slip(14 SECONDS * power_multiplier)
|
|
|
|
///This command spins the listeners 1800° degrees clockwise.
|
|
/datum/voice_of_god_command/multispin
|
|
trigger = "like\\s*a\\s*record\\s*baby|right\\s*round"
|
|
|
|
/datum/voice_of_god_command/multispin/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
for(var/mob/living/target as anything in listeners)
|
|
target.SpinAnimation(speed = 10, loops = 5)
|
|
|
|
/// Supertype of all those commands that make people emote and nothing else. Fuck copypasta.
|
|
/datum/voice_of_god_command/emote
|
|
/// The emote to run.
|
|
var/emote_name = "dance"
|
|
|
|
/datum/voice_of_god_command/emote/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
|
|
var/iteration = 1
|
|
for(var/mob/living/target as anything in listeners)
|
|
addtimer(CALLBACK(target, TYPE_PROC_REF(/mob/living/, emote), emote_name), 0.5 SECONDS * iteration)
|
|
iteration++
|
|
|
|
/datum/voice_of_god_command/emote/flip
|
|
trigger = "flip|rotate|revolve|roll|somersault"
|
|
emote_name = "flip"
|
|
|
|
/datum/voice_of_god_command/emote/dance
|
|
trigger = "dance"
|
|
is_regex = FALSE
|
|
|
|
/datum/voice_of_god_command/emote/salute
|
|
trigger = "salute"
|
|
emote_name = "salute"
|
|
is_regex = FALSE
|
|
|
|
/datum/voice_of_god_command/emote/play_dead
|
|
trigger = "play\\s*dead"
|
|
emote_name = "deathgasp"
|
|
|
|
/datum/voice_of_god_command/emote/clap
|
|
trigger = "clap|applaud"
|
|
emote_name = "clap"
|
|
|
|
#undef COOLDOWN_STUN
|
|
#undef COOLDOWN_DAMAGE
|
|
#undef COOLDOWN_MEME
|
|
#undef COOLDOWN_NONE
|