diff --git a/code/datums/brain_damage/hypnosis.dm b/code/datums/brain_damage/hypnosis.dm new file mode 100644 index 00000000000..61e59026ebb --- /dev/null +++ b/code/datums/brain_damage/hypnosis.dm @@ -0,0 +1,48 @@ +/datum/brain_trauma/hypnosis + name = "Hypnosis" + desc = "Patient's unconscious is completely enthralled by a word or sentence, focusing their thoughts and actions on it." + scan_desc = "looping thought pattern" + gain_text = "" + lose_text = "" + resilience = TRAUMA_RESILIENCE_SURGERY + + var/hypnotic_phrase = "" + +/datum/brain_trauma/hypnosis/New(phrase) + if(!phrase) + qdel(src) + hypnotic_phrase = phrase + ..() + +/datum/brain_trauma/hypnosis/on_gain() + message_admins("[ADMIN_LOOKUPFLW(owner)] was hypnotized with the phrase '[hypnotic_phrase]'.") + log_game("[key_name(owner)] was hypnotized with the phrase '[hypnotic_phrase]'.") + to_chat(owner, "[hypnotic_phrase]") + to_chat(owner, "[pick("You feel your thoughts focusing on this phrase... you can't seem to get it out of your head.",\ + "Your head hurts, but this is all you can think of. It must be vitally important.",\ + "You feel a part of your mind repeating this over and over. You need to follow these words.",\ + "Something about this sounds... right, for some reason. You feel like you should follow these words.",\ + "These words keep echoing in your mind. You find yourself completely fascinated by them.")]") + to_chat(owner, "You've been hypnotized by this sentence. You must follow these words. If it isn't a clear order, you can freely interpret how to do so,\ + as long as you act like the words are your highest priority.") + ..() + +/datum/brain_trauma/hypnosis/on_lose() + message_admins("[ADMIN_LOOKUPFLW(owner)] is no longer hypnotized with the phrase '[hypnotic_phrase]'.") + log_game("[key_name(owner)] is no longer hypnotized with the phrase '[hypnotic_phrase]'.") + to_chat(owner, "You suddenly snap out of your hypnosis. The phrase '[hypnotic_phrase]' no longer feels important to you.") + ..() + +/datum/brain_trauma/hypnosis/on_life() + ..() + if(prob(2)) + switch(rand(1,2)) + if(1) + to_chat(owner, "...[lowertext(hypnotic_phrase)]...") + if(2) + new /datum/hallucination/chat(owner, TRUE, FALSE, "[hypnotic_phrase]") + +/datum/brain_trauma/hypnosis/on_hear(message, speaker, message_language, raw_message, radio_freq) + var/regex/target_phrase = new("(\\b[hypnotic_phrase]\\b)","ig") + message = target_phrase.Replace(message, "$1") + return message \ No newline at end of file diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index a8adbfbce81..9c8bfffcb33 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -203,4 +203,21 @@ /datum/brain_trauma/severe/pacifism/on_lose() owner.remove_trait(TRAIT_PACIFISM, TRAUMA_TRAIT) - ..() \ No newline at end of file + ..() + +/datum/brain_trauma/severe/hypnotic_stupor + name = "Hypnotic Stupor" + desc = "Patient is prone to episodes of extreme stupor that leaves them extremely suggestible." + scan_desc = "oneiric feedback loop" + gain_text = "You feel somewhat dazed." + lose_text = "You feel like a fog was lifted from your mind." + +/datum/brain_trauma/severe/hypnotic_stupor/on_lose() //hypnosis must be cleared separately, but brain surgery should get rid of both anyway + ..() + owner.remove_status_effect(/datum/status_effect/trance) + +/datum/brain_trauma/severe/hypnotic_stupor/on_life() + ..() + if(prob(1) && !owner.has_status_effect(/datum/status_effect/trance)) + owner.apply_status_effect(/datum/status_effect/trance, rand(100,300), FALSE) + \ No newline at end of file diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 63b826a8989..286b92861b2 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -524,4 +524,52 @@ /datum/status_effect/gonbolaPacify/on_remove() owner.remove_trait(TRAIT_PACIFISM, "gonbolaPacify") owner.remove_trait(TRAIT_MUTE, "gonbolaMute") - owner.remove_trait(TRAIT_JOLLY, "gonbolaJolly") \ No newline at end of file + owner.remove_trait(TRAIT_JOLLY, "gonbolaJolly") + +/datum/status_effect/trance + id = "trance" + status_type = STATUS_EFFECT_UNIQUE + duration = 300 + tick_interval = 10 + examine_text = "SUBJECTPRONOUN seems slow and unfocused." + var/stun = TRUE + +/datum/status_effect/trance/tick() + if(stun) + owner.Stun(60, TRUE, TRUE) + owner.dizziness = 20 + +/datum/status_effect/trance/on_apply() + if(!iscarbon(owner)) + return FALSE + RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/hypnotize) + owner.add_trait(TRAIT_MUTE, "trance") + if(!owner.has_quirk(/datum/quirk/monochromatic)) + owner.add_client_colour(/datum/client_colour/monochrome) + owner.visible_message("[stun ? "[owner] stands still as [owner.p_their()] eyes seem to focus on a distant point." : ""]", \ + "[pick("You feel your thoughts slow down...", "You suddenly feel extremely dizzy...", "You feel like you're in the middle of a dream...","You feel incredibly relaxed...")]") + return TRUE + +/datum/status_effect/trance/on_creation(mob/living/new_owner, _duration, _stun = TRUE) + duration = _duration + stun = _stun + . = ..() + +/datum/status_effect/trance/on_remove() + UnregisterSignal(owner, COMSIG_MOVABLE_HEAR) + owner.remove_trait(TRAIT_MUTE, "trance") + owner.dizziness = 0 + if(!owner.has_quirk(/datum/quirk/monochromatic)) + owner.remove_client_colour(/datum/client_colour/monochrome) + to_chat(owner, "You snap out of your trance!") + +/datum/status_effect/trance/proc/hypnotize(datum/source, message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) + if(!owner.can_hear()) + return + if(speaker == owner) + return + var/mob/living/carbon/C = owner + C.cure_trauma_type(/datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY) //clear previous hypnosis + addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, raw_message), 10) + addtimer(CALLBACK(C, /mob/living.proc/Stun, 60, TRUE, TRUE), 15) //Take some time to think about it + qdel(src) diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css index fe90e8a333e..0451c45069a 100644 --- a/code/modules/goonchat/browserassets/css/browserOutput.css +++ b/code/modules/goonchat/browserassets/css/browserOutput.css @@ -393,6 +393,13 @@ h1.alert, h2.alert {color: #000000;} .redtext {color: #FF0000; font-size: 24px;} .clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} .his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} +.hypnophrase {color: #0d0d0d; font-weight: bold; animation: hypnocolor 1500ms infinite;} +@keyframes hypnocolor { + 0% { color: #0d0d0d; } + 25% { color: #410194; } + 50% { color: #7f17d8; } + 75% { color: #410194; } +} .icon {height: 1em; width: auto;} diff --git a/code/modules/mob/living/carbon/say.dm b/code/modules/mob/living/carbon/say.dm index f6e43f487f4..2c12a0d7995 100644 --- a/code/modules/mob/living/carbon/say.dm +++ b/code/modules/mob/living/carbon/say.dm @@ -39,10 +39,8 @@ else . = initial(dt.flags) & TONGUELESS_SPEECH -/mob/living/carbon/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) - . = ..() - if(!client) - return +/mob/living/carbon/hear_intercept(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) for(var/T in get_traumas()) var/datum/brain_trauma/trauma = T - message = trauma.on_hear(message, speaker, message_language, raw_message, radio_freq) \ No newline at end of file + message = trauma.on_hear(message, speaker, message_language, raw_message, radio_freq) + return message diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 5ed5534e993..49edbfe81de 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -228,9 +228,13 @@ GLOBAL_LIST_INIT(department_radio_keys, list( // Recompose message for AI hrefs, language incomprehension. message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode) + message = hear_intercept(message, speaker, message_language, raw_message, radio_freq, spans, message_mode) show_message(message, 2, deaf_message, deaf_type) return message +/mob/living/proc/hear_intercept(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) + return message + /mob/living/send_speech(message, message_range = 6, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language=null, message_mode) var/static/list/eavesdropping_modes = list(MODE_WHISPER = TRUE, MODE_WHISPER_CRIT = TRUE) var/eavesdrop_range = 0 diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm index 5eb4a355766..bca391f6539 100644 --- a/interface/stylesheet.dm +++ b/interface/stylesheet.dm @@ -153,6 +153,13 @@ h1.alert, h2.alert {color: #000000;} .redtext {color: #FF0000; font-size: 3;} .clown {color: #FF69Bf; font-size: 3; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} .his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} +.hypnophrase {color: #3bb5d3; font-weight: bold; animation: hypnocolor 1500ms infinite;} +@keyframes hypnocolor { + 0% { color: #0d0d0d; } + 25% { color: #410194; } + 50% { color: #7f17d8; } + 75% { color: #410194; } +} .icon {height: 1em; width: auto;} diff --git a/tgstation.dme b/tgstation.dme index c2f49a9d2a3..538006dcdbb 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -318,6 +318,7 @@ #include "code\datums\actions\beam_rifle.dm" #include "code\datums\actions\ninja.dm" #include "code\datums\brain_damage\brain_trauma.dm" +#include "code\datums\brain_damage\hypnosis.dm" #include "code\datums\brain_damage\imaginary_friend.dm" #include "code\datums\brain_damage\mild.dm" #include "code\datums\brain_damage\phobia.dm"