diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 883856cc9b7..753a953b8f9 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -151,7 +151,7 @@
// The old system would loop through lists for a total of 5000 per function call, in an empty server.
// This new system will loop at around 1000 in an empty server.
-/proc/get_mobs_in_view(var/R, var/atom/source)
+/proc/get_mobs_in_view(var/R, var/atom/source, var/include_clientless = FALSE)
// Returns a list of mobs in range of R from source. Used in radio and say code.
var/turf/T = get_turf(source)
@@ -165,7 +165,7 @@
for(var/atom/A in range)
if(ismob(A))
var/mob/M = A
- if(M.client)
+ if(M.client || include_clientless)
hear += M
//log_to_dd("Start = [M] - [get_turf(M)] - ([M.x], [M.y], [M.z])")
else if(istype(A, /obj/item/device/radio))
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index d5b75eb4c7c..4c6abbd7d0b 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -431,3 +431,17 @@ proc/checkhtml(var/t)
text = copytext(text, 1, index) + repl_chars[char] + copytext(text, index+keylength)
index = findtext(text, char)
return text
+
+//Checks if any of a given list of needles is in the haystack
+/proc/text_in_list(haystack, list/needle_list, start=1, end=0)
+ for(var/needle in needle_list)
+ if(findtext(haystack, needle, start, end))
+ return 1
+ return 0
+
+//Like above, but case sensitive
+/proc/text_in_list_case(haystack, list/needle_list, start=1, end=0)
+ for(var/needle in needle_list)
+ if(findtextEx(haystack, needle, start, end))
+ return 1
+ return 0
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index d5b789e7523..28b3cfe7132 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -449,7 +449,7 @@ var/list/turret_icons
return
health -= force
- if(force > 5 && prob(45))
+ if(force > 5 && prob(45) && spark_system)
spark_system.start()
if(health <= 0)
die() //the death process :(
@@ -504,7 +504,8 @@ var/list/turret_icons
/obj/machinery/porta_turret/proc/die() //called when the turret dies, ie, health <= 0
health = 0
stat |= BROKEN //enables the BROKEN bit
- spark_system.start() //creates some sparks because they look cool
+ if(spark_system)
+ spark_system.start() //creates some sparks because they look cool
update_icon()
/obj/machinery/porta_turret/process()
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index 558a6f8e9de..4876aa60b7b 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -221,6 +221,16 @@
if(!src.restrained())
message = "[src] is strumming the air and headbanging like a safari chimp."
m_type = 1
+
+ if("dance")
+ if(!src.restrained())
+ message = "[src] dances around happily."
+ m_type = 1
+
+ if("jump")
+ if(!src.restrained())
+ message = "[src] jumps!"
+ m_type = 1
if("blink", "blinks")
message = "[src] blinks."
@@ -841,9 +851,9 @@
M.reagents.add_reagent("jenkem", 1)
if("help")
- var/emotelist = "aflap(s), airguitar, blink(s), blink(s)_r, blush(es), bow(s)-(none)/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s),cry, cries, custom, dap(s)(none)/mob," \
- + " deathgasp(s), drool(s), eyebrow,fart(s), faint(s), flap(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-(none)/mob, grin(s), groan(s), grumble(s), handshake-mob, hug(s)-(none)/mob," \
- + " glare(s)-(none)/mob, grin(s), johnny, laugh(s), look(s)-(none)/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-(none)/mob, scream(s), shake(s)," \
+ var/emotelist = "aflap(s), airguitar, blink(s), blink(s)_r, blush(es), bow(s)-(none)/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s),cry, cries, custom, dance, dap(s)(none)/mob," \
+ + " deathgasp(s), drool(s), eyebrow, fart(s), faint(s), flap(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-(none)/mob, grin(s), groan(s), grumble(s), grin(s)," \
+ + " handshake-mob, hug(s)-(none)/mob, johnny, jump, laugh(s), look(s)-(none)/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-(none)/mob, scream(s), shake(s)," \
+ " shiver(s), shrug(s), sigh(s), signal(s)-#1-10,slap(s)-(none)/mob, smile(s),snap(s), sneeze(s), sniff(s), snore(s), stare(s)-(none)/mob, swag(s), tremble(s), twitch(es), twitch(es)_s," \
+ " wag(s), wave(s), whimper(s), wink(s), yawn(s)"
if(species.name == "Machine")
diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm
index 26ca4af83e8..7384ccc6796 100644
--- a/code/modules/mob/living/carbon/human/say.dm
+++ b/code/modules/mob/living/carbon/human/say.dm
@@ -1,10 +1,10 @@
-/mob/living/carbon/human/say(var/message)
+/mob/living/carbon/human/say(var/message, var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
var/alt_name = ""
if(name != GetVoice())
alt_name = " (as [get_id_name("Unknown")])"
- ..(message, alt_name = alt_name) //ohgod we should really be passing a datum here.
+ ..(message, alt_name = alt_name, sanitize = sanitize, ignore_speech_problems = ignore_speech_problems, ignore_atmospherics = ignore_atmospherics) //ohgod we should really be passing a datum here.
/mob/living/carbon/human/proc/forcesay(list/append)
if(stat == CONSCIOUS)
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index d5a1580ded9..44db25814c9 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -14,6 +14,7 @@ var/list/department_radio_keys = list(
":u" = "Supply", "#u" = "Supply", ".u" = "Supply",
":z" = "Service", "#z" = "Service", ".z" = "Service",
":p" = "AI Private", "#p" = "AI Private", ".p" = "AI Private",
+ ":x" = "cords", "#x" = "cords", ".x" = "cords",
":R" = "right ear", "#R" = "right ear", ".R" = "right ear",
":L" = "left ear", "#L" = "left ear", ".L" = "left ear",
@@ -30,7 +31,8 @@ var/list/department_radio_keys = list(
":Z" = "Service", "#Z" = "Service", ".Z" = "Service",
":P" = "AI Private", "#P" = "AI Private", ".P" = "AI Private",
":-" = "Special Ops", "#-" = "Special Ops", ".-" = "Special Ops",
- ":_" = "SyndTeam", "#_" = "SyndTeam", "._" = "SyndTeam"
+ ":_" = "SyndTeam", "#_" = "SyndTeam", "._" = "SyndTeam",
+ ":X" = "cords", "#X" = "cords", ".X" = "cords"
)
@@ -106,13 +108,14 @@ proc/get_radio_key_from_channel(var/channel)
return returns
-/mob/living/say(var/message, var/datum/language/speaking = null, var/verb = "says", var/alt_name="")
+/mob/living/say(var/message, var/datum/language/speaking = null, var/verb = "says", var/alt_name = "", var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
if(client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, "You cannot speak in IC (Muted).")
return
- message = trim_strip_html_properly(message)
+ if(sanitize)
+ message = trim_strip_html_properly(message)
if(stat)
if(stat == DEAD)
@@ -146,6 +149,15 @@ proc/get_radio_key_from_channel(var/channel)
if(speaking && (speaking.flags & HIVEMIND))
speaking.broadcast(src,trim(message))
return 1
+
+ if(message_mode == "cords")
+ if(iscarbon(src))
+ var/mob/living/carbon/C = src
+ var/obj/item/organ/internal/vocal_cords/V = C.get_int_organ(/obj/item/organ/internal/vocal_cords)
+ if(V && V.can_speak_with())
+ C.say(V.handle_speech(message), sanitize = FALSE, ignore_speech_problems = TRUE, ignore_atmospherics = TRUE)
+ V.speak_with(message) //words come before actions
+ return 1
verb = say_quote(message, speaking)
@@ -162,7 +174,7 @@ proc/get_radio_key_from_channel(var/channel)
message = handle_autohiss(message, speaking)
- if(speaking && !(speaking.flags & NO_STUTTER))
+ if(!ignore_speech_problems && (speaking && !(speaking.flags & NO_STUTTER)))
var/list/handle_s = handle_speech_problems(message, verb)
message = handle_s[1]
verb = handle_s[2]
@@ -217,12 +229,13 @@ proc/get_radio_key_from_channel(var/channel)
//make sure the air can transmit speech - speaker's side
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment ? environment.return_pressure() : 0
- if(pressure < SOUND_MINIMUM_PRESSURE)
- message_range = 1
+ if(!ignore_atmospherics)
+ if(pressure < SOUND_MINIMUM_PRESSURE)
+ message_range = 1
- if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
- italics = 1
- sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
+ if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
+ italics = 1
+ sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
var/list/hear = hear(message_range, T)
var/list/hearturfs = list()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 132655bc923..b0a81e4444c 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -46,7 +46,7 @@ Difficulty: Very Hard
del_on_death = 1
medal_type = MEDAL_PREFIX
score_type = COLOSSUS_SCORE
- loot = list(/obj/machinery/anomalous_crystal/random)
+ loot = list(/obj/machinery/anomalous_crystal/random, /obj/item/organ/internal/vocal_cords/colossus)
butcher_results = list(/obj/item/weapon/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30)
deathmessage = "disintegrates, leaving a glowing core in its wake."
death_sound = 'sound/misc/demon_dies.ogg'
diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm
index f34d9797124..5ac16d095e5 100644
--- a/code/modules/research/designs/autolathe_designs.dm
+++ b/code/modules/research/designs/autolathe_designs.dm
@@ -162,6 +162,14 @@
materials = list(MAT_METAL = 50, MAT_GLASS = 50)
build_path = /obj/item/weapon/firealarm_electronics
category = list("initial", "Electronics")
+
+/datum/design/earmuffs
+ name = "Earmuffs"
+ id = "earmuffs"
+ build_type = AUTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500)
+ build_path = /obj/item/clothing/ears/earmuffs
+ category = list("initial", "Miscellaneous")
/datum/design/igniter
name = "Igniter"
@@ -188,7 +196,7 @@
category = list("initial", "Medical")
/datum/design/kitchen_knife
- name = "Kitchen knife"
+ name = "Kitchen Knife"
id = "kitchen_knife"
build_type = AUTOLATHE
materials = list(MAT_METAL = 12000)
@@ -196,7 +204,7 @@
category = list("initial","Miscellaneous")
/datum/design/minihoe
- name = "Mini hoe"
+ name = "Mini Hoe"
id = "mini_hoe"
build_type = AUTOLATHE
materials = list(MAT_METAL = 50)
@@ -204,7 +212,7 @@
category = list("initial","Miscellaneous")
/datum/design/plant_analyzer
- name = "Plant analyzer"
+ name = "Plant Analyzer"
id = "plant_analyzer"
build_type = AUTOLATHE
materials = list(MAT_METAL = 30, MAT_GLASS = 20)
@@ -324,12 +332,12 @@
category = list("initial", "Miscellaneous")
/datum/design/foambox
- name = "Box of Foam Force darts"
- id = "foamforce"
- build_type = AUTOLATHE
- materials = list(MAT_METAL = 2000)
- build_path = /obj/item/ammo_box/foambox
- category = list("initial", "Miscellaneous")
+ name = "Box of Foam Force darts"
+ id = "foamforce"
+ build_type = AUTOLATHE
+ materials = list(MAT_METAL = 2000)
+ build_path = /obj/item/ammo_box/foambox
+ category = list("initial", "Miscellaneous")
/datum/design/canvas/twentythreeXtwentythree
name = "23px by 23px Canvas"
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
new file mode 100644
index 00000000000..99a152da957
--- /dev/null
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -0,0 +1,453 @@
+var/static/regex/stun_words = regex("stop|wait|stand still|hold on|halt")
+var/static/regex/weaken_words = regex("drop|fall|trip")
+var/static/regex/sleep_words = regex("sleep|slumber")
+var/static/regex/vomit_words = regex("vomit|throw up")
+var/static/regex/silence_words = regex("shut up|silence|ssh|quiet|hush")
+var/static/regex/hallucinate_words = regex("see the truth|hallucinate")
+var/static/regex/wakeup_words = regex("wake up|awaken")
+var/static/regex/heal_words = regex("live|heal|survive|mend|heroes never die")
+var/static/regex/hurt_words = regex("die|suffer")
+var/static/regex/bleed_words = regex("bleed")
+var/static/regex/burn_words = regex("burn|ignite")
+var/static/regex/repulse_words = regex("shoo|go away|leave me alone|begone|flee|fus ro dah")
+var/static/regex/whoareyou_words = regex("who are you|say your name|state your name|identify")
+var/static/regex/saymyname_words = regex("say my name")
+var/static/regex/knockknock_words = regex("knock knock")
+var/static/regex/statelaws_words = regex("state laws|state your laws")
+var/static/regex/move_words = regex("move")
+var/static/regex/walk_words = regex("walk|slow down")
+var/static/regex/run_words = regex("run")
+var/static/regex/helpintent_words = regex("help")
+var/static/regex/disarmintent_words = regex("disarm")
+var/static/regex/grabintent_words = regex("grab")
+var/static/regex/harmintent_words = regex("harm|fight")
+var/static/regex/throwmode_words = regex("throw|catch")
+var/static/regex/flip_words = regex("flip|rotate|revolve|roll|somersault")
+var/static/regex/rest_words = regex("rest")
+var/static/regex/getup_words = regex("get up")
+var/static/regex/sit_words = regex("sit")
+var/static/regex/stand_words = regex("stand")
+var/static/regex/dance_words = regex("dance")
+var/static/regex/jump_words = regex("jump")
+var/static/regex/salute_words = regex("salute")
+var/static/regex/deathgasp_words = regex("play dead")
+var/static/regex/clap_words = regex("clap|applaud")
+var/static/regex/honk_words = regex("ho+nk") //hooooooonk
+var/static/regex/multispin_words = regex("like a record baby")
+
+/obj/item/organ/internal/vocal_cords //organs that are activated through speech with the :x channel
+ name = "vocal cords"
+ icon_state = "appendix"
+ zone = "mouth"
+ slot = "vocal_cords"
+ parent_organ = "mouth"
+ var/spans = null
+
+/obj/item/organ/internal/vocal_cords/proc/can_speak_with() //if there is any limitation to speaking with these cords
+ return TRUE
+
+/obj/item/organ/internal/vocal_cords/proc/speak_with(message) //do what the organ does
+ return
+
+/obj/item/organ/internal/vocal_cords/proc/handle_speech(message) //change the message
+ return message
+
+//Colossus drop, forces the listeners to obey certain commands
+/obj/item/organ/internal/vocal_cords/colossus
+ name = "divine vocal cords"
+ desc = "They carry the voice of an ancient god."
+ icon_state = "voice_of_god"
+ actions_types = list(/datum/action/item_action/organ_action/colossus)
+ var/next_command = 0
+ var/cooldown_stun = 1200
+ var/cooldown_damage = 600
+ var/cooldown_meme = 300
+ var/cooldown_none = 150
+ var/base_multiplier = 1
+ spans = "colossus yell"
+
+/datum/action/item_action/organ_action/colossus
+ name = "Voice of God"
+ var/obj/item/organ/internal/vocal_cords/colossus/cords = null
+
+/datum/action/item_action/organ_action/colossus/New()
+ ..()
+ cords = target
+
+/datum/action/item_action/organ_action/colossus/IsAvailable()
+ if(world.time < cords.next_command)
+ return FALSE
+ if(!owner)
+ return FALSE
+ if(!owner.can_speak())
+ return FALSE
+ if(check_flags & AB_CHECK_CONSCIOUS)
+ if(owner.stat)
+ return FALSE
+ return TRUE
+
+/datum/action/item_action/organ_action/colossus/Trigger()
+ . = ..()
+ if(!IsAvailable())
+ if(world.time < cords.next_command)
+ to_chat(owner, "You must wait [(cords.next_command - world.time)/10] seconds before Speaking again.")
+ return
+ var/command = input(owner, "Speak with the Voice of God", "Command")
+ if(!command)
+ return
+ owner.say(".x[command]")
+
+/obj/item/organ/internal/vocal_cords/colossus/can_speak_with()
+ if(world.time < next_command)
+ to_chat(owner, "You must wait [(next_command - world.time)/10] seconds before Speaking again.")
+ return FALSE
+ if(!owner)
+ return FALSE
+ if(!owner.can_speak())
+ to_chat(owner, "You are unable to speak!")
+ return FALSE
+ if(owner.stat)
+ return FALSE
+ return TRUE
+
+/obj/item/organ/internal/vocal_cords/colossus/handle_speech(message)
+ spans = "colossus yell" //reset spans, just in case someone gets deculted or the cords change owner
+ if(iscultist(owner))
+ spans += " narsiesmall"
+ return "[uppertext(message)]"
+
+/obj/item/organ/internal/vocal_cords/colossus/speak_with(message)
+ var/log_message = uppertext(message)
+ message = lowertext(message)
+ playsound(get_turf(owner), 'sound/magic/invoke_general.ogg', 300, 1, 5)
+
+ var/mob/living/list/listeners = list()
+ for(var/mob/living/L in get_mobs_in_view(8, owner, TRUE))
+ if(!L.ear_deaf && !L.null_rod_check() && L != owner && L.stat != DEAD)
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs))
+ continue
+ listeners += L
+
+ if(!listeners.len)
+ next_command = world.time + cooldown_none
+ return
+
+ var/power_multiplier = base_multiplier
+
+ if(owner.mind)
+ //Chaplains are very good at speaking with the voice of god
+ if(owner.mind.assigned_role == "Chaplain")
+ power_multiplier *= 2
+ //Command staff has authority
+ if(owner.mind.assigned_role in command_positions)
+ power_multiplier *= 1.4
+ //Why are you speaking
+ if(owner.mind.assigned_role == "Mime")
+ power_multiplier *= 0.5
+
+ //Cultists are closer to their gods and are more powerful, but they'll give themselves away
+ if(iscultist(owner))
+ power_multiplier *= 2
+
+ //Try to check if the speaker specified a name or a job to focus on
+ var/list/specific_listeners = list()
+ var/found_string = null
+
+ for(var/V in listeners)
+ var/mob/living/L = V
+ /*if(L.mind && L.mind.devilinfo && findtext(message, L.mind.devilinfo.truename))
+ var/start = findtext(message, L.mind.devilinfo.truename)
+ listeners = list(L) //let's be honest you're never going to find two devils with the same name
+ power_multiplier *= 5 //if you're a devil and god himself addressed you, you fucked up
+ //Cut out the name so it doesn't trigger commands
+ message = copytext(message, 0, start)+copytext(message, start + length(L.mind.devilinfo.truename), length(message) + 1)
+ break*/
+ if(findtext(message, L.real_name) == 1)
+ specific_listeners += L //focus on those with the specified name
+ //Cut out the name so it doesn't trigger commands
+ found_string = L.real_name
+
+ else if(L.mind && findtext(message, L.mind.assigned_role) == 1)
+ specific_listeners += L //focus on those with the specified job
+ //Cut out the job so it doesn't trigger commands
+ found_string = L.mind.assigned_role
+
+ 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
+ message = copytext(message, 0, 1)+copytext(message, 1 + length(found_string), length(message) + 1)
+
+ //STUN
+ if(findtext(message, stun_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.Stun(3 * power_multiplier)
+ next_command = world.time + cooldown_stun
+
+ //WEAKEN
+ else if(findtext(message, weaken_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.Weaken(3 * power_multiplier)
+ next_command = world.time + cooldown_stun
+
+ //SLEEP
+ else if((findtext(message, sleep_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.Sleeping(2 * power_multiplier)
+ next_command = world.time + cooldown_stun
+
+ //VOMIT
+ else if((findtext(message, vomit_words)))
+ for(var/mob/living/carbon/C in listeners)
+ C.vomit(10 * power_multiplier)
+ next_command = world.time + cooldown_stun
+
+ //SILENCE
+ else if((findtext(message, silence_words)))
+ for(var/mob/living/carbon/C in listeners)
+ if(owner.mind && (owner.mind.assigned_role == "Librarian" || owner.mind.assigned_role == "Mime"))
+ power_multiplier *= 3
+ C.silent += (10 * power_multiplier)
+ next_command = world.time + cooldown_stun
+
+ //HALLUCINATE
+ else if((findtext(message, hallucinate_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ new /obj/effect/hallucination/delusion(get_turf(L),L,duration=150 * power_multiplier,skip_nearby=0)
+ next_command = world.time + cooldown_meme
+
+ //WAKE UP
+ else if((findtext(message, wakeup_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.SetSleeping(0)
+ next_command = world.time + cooldown_damage
+
+ //HEAL
+ else if((findtext(message, heal_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.heal_overall_damage(10 * power_multiplier, 10 * power_multiplier, 0, 0)
+ next_command = world.time + cooldown_damage
+
+ //BRUTE DAMAGE
+ else if((findtext(message, hurt_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.apply_damage(15 * power_multiplier, def_zone = "chest")
+ next_command = world.time + cooldown_damage
+
+ //BLEED
+ else if((findtext(message, bleed_words)))
+ for(var/mob/living/carbon/human/H in listeners)
+ H.drip(100 * power_multiplier)
+ next_command = world.time + cooldown_damage
+
+ //FIRE
+ else if((findtext(message, burn_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.adjust_fire_stacks(1 * power_multiplier)
+ L.IgniteMob()
+ next_command = world.time + cooldown_damage
+
+ //REPULSE
+ else if((findtext(message, repulse_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/throwtarget = get_edge_target_turf(owner, get_dir(owner, get_step_away(L, owner)))
+ L.throw_at(throwtarget, 3 * power_multiplier, 1)
+ next_command = world.time + cooldown_damage
+
+ //WHO ARE YOU?
+ else if((findtext(message, whoareyou_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ /*if(L.mind && L.mind.devilinfo)
+ L.say("[L.mind.devilinfo.truename]")
+ else*/
+ L.say("[L.real_name]")
+ next_command = world.time + cooldown_meme
+
+ //SAY MY NAME
+ else if((findtext(message, saymyname_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.say("[owner.name]!") //"Unknown!"
+ next_command = world.time + cooldown_meme
+
+ //KNOCK KNOCK
+ else if((findtext(message, knockknock_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.say("Who's there?")
+ next_command = world.time + cooldown_meme
+
+ //STATE LAWS
+ else if((findtext(message, statelaws_words)))
+ for(var/mob/living/silicon/S in listeners)
+ S.statelaws(S.laws)
+ next_command = world.time + cooldown_stun
+
+ //MOVE
+ else if((findtext(message, move_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ step(L, pick(cardinal))
+ next_command = world.time + cooldown_meme
+
+ //WALK
+ else if((findtext(message, walk_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ if(L.m_intent != "walk")
+ L.m_intent = "walk"
+ L.hud_used.move_intent.icon_state = "walking"
+ next_command = world.time + cooldown_meme
+
+ //RUN
+ else if((findtext(message, run_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ if(L.m_intent != "run")
+ L.m_intent = "run"
+ L.hud_used.move_intent.icon_state = "running"
+ next_command = world.time + cooldown_meme
+
+ //HELP INTENT
+ else if((findtext(message, helpintent_words)))
+ for(var/mob/living/carbon/human/H in listeners)
+ H.a_intent_change(I_HELP)
+ next_command = world.time + cooldown_meme
+
+ //DISARM INTENT
+ else if((findtext(message, disarmintent_words)))
+ for(var/mob/living/carbon/human/H in listeners)
+ H.a_intent_change(I_DISARM)
+ next_command = world.time + cooldown_meme
+
+ //GRAB INTENT
+ else if((findtext(message, grabintent_words)))
+ for(var/mob/living/carbon/human/H in listeners)
+ H.a_intent_change(I_GRAB)
+ next_command = world.time + cooldown_meme
+
+ //HARM INTENT
+ else if((findtext(message, harmintent_words)))
+ for(var/mob/living/carbon/human/H in listeners)
+ H.a_intent_change(I_HARM)
+ next_command = world.time + cooldown_meme
+
+ //THROW/CATCH
+ else if((findtext(message, throwmode_words)))
+ for(var/mob/living/carbon/C in listeners)
+ C.throw_mode_on()
+ next_command = world.time + cooldown_meme
+
+ //FLIP
+ else if((findtext(message, flip_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.emote("flip")
+ next_command = world.time + cooldown_meme
+
+ //REST
+ else if((findtext(message, rest_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ if(!L.resting)
+ L.lay_down()
+ next_command = world.time + cooldown_meme
+
+ //GET UP
+ else if((findtext(message, getup_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ if(L.resting)
+ L.lay_down() //aka get up
+ L.SetStunned(0)
+ L.SetWeakened(0)
+ L.SetParalysis(0) //i said get up i don't care if you're being tazed
+ next_command = world.time + cooldown_damage
+
+ //SIT
+ else if((findtext(message, sit_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ for(var/obj/structure/stool/bed/chair/chair in get_turf(L))
+ chair.buckle_mob(L)
+ break
+ next_command = world.time + cooldown_meme
+
+ //STAND UP
+ else if((findtext(message, stand_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ if(L.buckled && istype(L.buckled, /obj/structure/stool/bed/chair))
+ L.buckled.unbuckle_mob(L)
+ next_command = world.time + cooldown_meme
+
+ //DANCE
+ else if((findtext(message, dance_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.emote("dance")
+ next_command = world.time + cooldown_meme
+
+ //JUMP
+ else if((findtext(message, jump_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.say("HOW HIGH?!!")
+ L.emote("jump")
+ next_command = world.time + cooldown_meme
+
+ //SALUTE
+ else if((findtext(message, salute_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.emote("salute")
+ next_command = world.time + cooldown_meme
+
+ //PLAY DEAD
+ else if((findtext(message, deathgasp_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.emote("deathgasp")
+ next_command = world.time + cooldown_meme
+
+ //PLEASE CLAP
+ else if((findtext(message, clap_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.emote("clap")
+ next_command = world.time + cooldown_meme
+
+ //HONK
+ else if((findtext(message, honk_words)))
+ spawn(25)
+ playsound(get_turf(owner), "sound/items/bikehorn.ogg", 300, 1)
+ if(owner.mind && owner.mind.assigned_role == "Clown")
+ for(var/mob/living/carbon/C in listeners)
+ C.slip(0,7 * power_multiplier)
+ next_command = world.time + cooldown_stun
+ else
+ next_command = world.time + cooldown_meme
+
+ //RIGHT ROUND
+ else if((findtext(message, multispin_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ L.SpinAnimation(speed = 10, loops = 5)
+ next_command = world.time + cooldown_meme
+
+ else
+ next_command = world.time + cooldown_none
+
+ message_admins("[key_name_admin(owner)] has said '[log_message]' with a Voice of God, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].")
+ log_game("[key_name(owner)] has said '[log_message]' with a Voice of God, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].")
\ No newline at end of file
diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css
index d1669591f82..cce2a515d7b 100644
--- a/goon/browserassets/css/browserOutput.css
+++ b/goon/browserassets/css/browserOutput.css
@@ -239,6 +239,7 @@ em {font-style: normal; font-weight: bold;}
.playerreply {color: #8800bb; font-weight: bold;}
.name { font-weight: bold;}
.say {}
+.yell { font-weight: bold;}
.siliconsay {font-family: 'Courier New', Courier, monospace;}
.deadsay {color: #5c00e6;}
.radio {color: #008000;}
@@ -323,8 +324,9 @@ h1.alert, h2.alert {color: #000000;}
.cult {color: #800080; font-weight: bold; font-style: italic;}
.cultspeech {color: #7F0000; font-style: italic;}
.cultitalic {color: #960000; font-style: italic;}
-.cultlarge {color: #960000; font-weight: bold; font-size: 3;}
-.narsie {color: #960000; font-weight: bold; font-size: 15;}
+.cultlarge {color: #960000; font-weight: bold; font-size: 120%;}
+.narsie {color: #960000; font-weight: bold; font-size: 300%;}
+.narsiesmall {color: #960000; font-weight: bold; font-size: 200%;}
.interface {color: #330033;}
.big {font-size: 150%;}
.reallybig {font-size: 175%;}
@@ -341,10 +343,10 @@ h1.alert, h2.alert {color: #000000;}
.revennotice {color: #1d2953;}
.revenboldnotice {color: #1d2953; font-weight: bold;}
-.revenbignotice {color: #1d2953; font-weight: bold; font-size: 3;}
+.revenbignotice {color: #1d2953; font-weight: bold; font-size: 120%;}
.revenminor {color: #823abb}
.revenwarning {color: #760fbb; font-style: italic;}
-.revendanger {color: #760fbb; font-weight: bold; font-size: 3;}
+.revendanger {color: #760fbb; font-weight: bold; font-size: 120%;}
/* /vg/ */
.good {color: green;}
@@ -358,7 +360,7 @@ h1.alert, h2.alert {color: #000000;}
"}
.memo {color: #638500; text-align: center;}
-.memoedit {text-align: center; font-size: 2;}
+.memoedit {text-align: center; font-size: 75%;}
.connectionClosed, .fatalError {background: red; color: white; padding: 5px;}
.connectionClosed.restored {background: green;}
@@ -369,6 +371,6 @@ h1.alert, h2.alert {color: #000000;}
.hidden {display: none; visibility: hidden;}
/* MEGAFAUNA */
-.colossus {color: #7F282A; font-size: 5;}
-.hierophant {color: #660099; font-weight: bold; font-size: 4;}
+.colossus {color: #7F282A; font-size: 175%;}
+.hierophant {color: #660099; font-weight: bold; font-size: 150%;}
.hierophant_warning {color: #660099; font-weight: bold; font-style: italic;}
\ No newline at end of file
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index 033446d49d3..a5638d1db1b 100644
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ
diff --git a/paradise.dme b/paradise.dme
index d9b5b155bb0..0f96de59c40 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -2068,6 +2068,7 @@
#include "code\modules\surgery\organs\parasites.dm"
#include "code\modules\surgery\organs\robolimbs.dm"
#include "code\modules\surgery\organs\skeleton.dm"
+#include "code\modules\surgery\organs\vocal_cords.dm"
#include "code\modules\surgery\organs\wound.dm"
#include "code\modules\surgery\organs\subtypes\diona.dm"
#include "code\modules\surgery\organs\subtypes\drask.dm"