//Brain traumas that are rare and/or somewhat beneficial; //they are the easiest to cure, which means that if you want //to keep them, you can't cure your other traumas /datum/brain_trauma/special abstract_type = /datum/brain_trauma/special /datum/brain_trauma/special/godwoken name = "Godwoken Syndrome" desc = "Patient occasionally and uncontrollably channels an eldritch god when speaking." scan_desc = "god delusion" gain_text = span_notice("You feel a higher power inside your mind...") lose_text = span_warning("The divine presence leaves your head, no longer interested.") /datum/brain_trauma/special/godwoken/on_life(seconds_per_tick, times_fired) ..() if(SPT_PROB(2, seconds_per_tick)) if(prob(33) && (owner.IsStun() || owner.IsParalyzed() || owner.IsUnconscious())) speak("unstun", TRUE) else if(prob(60) && owner.health <= owner.crit_threshold) speak("heal", TRUE) else if(prob(30) && owner.combat_mode) speak("aggressive") else speak("neutral", prob(25)) /datum/brain_trauma/special/godwoken/on_gain() ADD_TRAIT(owner, TRAIT_HOLY, TRAUMA_TRAIT) ..() /datum/brain_trauma/special/godwoken/on_lose() REMOVE_TRAIT(owner, TRAIT_HOLY, TRAUMA_TRAIT) ..() /datum/brain_trauma/special/godwoken/proc/speak(type, include_owner = FALSE) var/message switch(type) if("unstun") message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_unstun") if("heal") message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_heal") if("neutral") message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral") if("aggressive") message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_aggressive") else message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral") playsound(get_turf(owner), 'sound/effects/magic/clockwork/invoke_general.ogg', 200, TRUE, 5) voice_of_god(message, owner, list("colossus","yell"), 2.5, include_owner, name, TRUE) /datum/brain_trauma/special/bluespace_prophet name = "Bluespace Prophecy" desc = "Patient can sense the bob and weave of bluespace around them, showing them passageways no one else can see." scan_desc = "bluespace attunement" gain_text = span_notice("You feel the bluespace pulsing around you...") lose_text = span_warning("The faint pulsing of bluespace fades into silence.") /// Cooldown so we can't teleport literally everywhere on a whim COOLDOWN_DECLARE(portal_cooldown) /datum/brain_trauma/special/bluespace_prophet/on_life(seconds_per_tick, times_fired) if(!COOLDOWN_FINISHED(src, portal_cooldown)) return COOLDOWN_START(src, portal_cooldown, 10 SECONDS) var/list/turf/possible_turfs = list() for(var/turf/T as anything in RANGE_TURFS(8, owner)) if(T.density) continue var/clear = TRUE for(var/obj/O in T) if(O.density) clear = FALSE break if(clear) possible_turfs += T if(!LAZYLEN(possible_turfs)) return var/turf/first_turf = pick(possible_turfs) if(!first_turf) return possible_turfs -= (possible_turfs & range(first_turf, 3)) var/turf/second_turf = pick(possible_turfs) if(!second_turf) return var/obj/effect/client_image_holder/bluespace_stream/first = new(first_turf, owner) var/obj/effect/client_image_holder/bluespace_stream/second = new(second_turf, owner) first.linked_to = second second.linked_to = first /obj/effect/client_image_holder/bluespace_stream name = "bluespace stream" desc = "You see a hidden pathway through bluespace..." image_icon = 'icons/effects/effects.dmi' image_state = "bluestream" image_layer = ABOVE_MOB_LAYER var/obj/effect/client_image_holder/bluespace_stream/linked_to /obj/effect/client_image_holder/bluespace_stream/Initialize(mapload, list/mobs_which_see_us) . = ..() QDEL_IN(src, 30 SECONDS) /obj/effect/client_image_holder/bluespace_stream/generate_image() . = ..() apply_wibbly_filters(.) /obj/effect/client_image_holder/bluespace_stream/Destroy() if(!QDELETED(linked_to)) qdel(linked_to) linked_to = null return ..() /obj/effect/client_image_holder/bluespace_stream/attack_hand(mob/user, list/modifiers) . = ..() if(.) return if(!(user in who_sees_us) || !linked_to) return var/slip_in_message = pick("slides sideways in an odd way, and disappears", "jumps into an unseen dimension",\ "sticks one leg straight out, wiggles [user.p_their()] foot, and is suddenly gone", "stops, then blinks out of reality", \ "is pulled into an invisible vortex, vanishing from sight") var/slip_out_message = pick("silently fades in", "leaps out of thin air","appears", "walks out of an invisible doorway",\ "slides out of a fold in spacetime") to_chat(user, span_notice("You try to align with the bluespace stream...")) if(!do_after(user, 2 SECONDS, target = src)) return var/turf/source_turf = get_turf(src) var/turf/destination_turf = get_turf(linked_to) new /obj/effect/temp_visual/bluespace_fissure(source_turf) new /obj/effect/temp_visual/bluespace_fissure(destination_turf) user.visible_message(span_warning("[user] [slip_in_message]."), ignored_mobs = user) if(do_teleport(user, destination_turf, no_effects = TRUE)) user.visible_message(span_warning("[user] [slip_out_message]."), span_notice("...and find your way to the other side.")) else user.visible_message(span_warning("[user] [slip_out_message], ending up exactly where they left."), span_notice("...and find yourself where you started?")) /obj/effect/client_image_holder/bluespace_stream/attack_tk(mob/user) to_chat(user, span_warning("\The [src] actively rejects your mind, and the bluespace energies surrounding it disrupt your telekinesis!")) return COMPONENT_CANCEL_ATTACK_CHAIN /datum/brain_trauma/special/quantum_alignment name = "Quantum Alignment" desc = "Patient is prone to frequent spontaneous quantum entanglement, against all odds, causing spatial anomalies." scan_desc = "quantum alignment" gain_text = span_notice("You feel faintly connected to everything around you...") lose_text = span_warning("You no longer feel connected to your surroundings.") var/atom/linked_target = null var/linked = FALSE var/returning = FALSE /// Cooldown for snapbacks COOLDOWN_DECLARE(snapback_cooldown) /datum/brain_trauma/special/quantum_alignment/on_life(seconds_per_tick, times_fired) if(linked) if(QDELETED(linked_target)) linked_target = null linked = FALSE return if(!returning && COOLDOWN_FINISHED(src, snapback_cooldown)) start_snapback() return if(SPT_PROB(2, seconds_per_tick)) try_entangle() /datum/brain_trauma/special/quantum_alignment/proc/try_entangle() //Check for pulled mobs if(ismob(owner.pulling)) entangle(owner.pulling) return //Check for adjacent mobs for(var/mob/living/L in oview(1, owner)) if(owner.Adjacent(L)) entangle(L) return //Check for pulled objects if(isobj(owner.pulling)) entangle(owner.pulling) return //Check main hand var/obj/item/held_item = owner.get_active_held_item() if(held_item && !(HAS_TRAIT(held_item, TRAIT_NODROP))) entangle(held_item) return //Check off hand held_item = owner.get_inactive_held_item() if(held_item && !(HAS_TRAIT(held_item, TRAIT_NODROP))) entangle(held_item) return //Just entangle with the turf entangle(get_turf(owner)) /datum/brain_trauma/special/quantum_alignment/proc/entangle(atom/target) to_chat(owner, span_notice("You start feeling a strong sense of connection to [target].")) linked_target = target linked = TRUE COOLDOWN_START(src, snapback_cooldown, rand(45 SECONDS, 10 MINUTES)) /datum/brain_trauma/special/quantum_alignment/proc/start_snapback() if(QDELETED(linked_target)) linked_target = null linked = FALSE return to_chat(owner, span_warning("Your connection to [linked_target] suddenly feels extremely strong... you can feel it pulling you!")) owner.playsound_local(owner, 'sound/effects/magic/lightning_chargeup.ogg', 75, FALSE) returning = TRUE addtimer(CALLBACK(src, PROC_REF(snapback)), 10 SECONDS) /datum/brain_trauma/special/quantum_alignment/proc/snapback() returning = FALSE if(QDELETED(linked_target)) to_chat(owner, span_notice("The connection fades abruptly, and the pull with it.")) linked_target = null linked = FALSE return to_chat(owner, span_warning("You're pulled through spacetime!")) do_teleport(owner, get_turf(linked_target), null, channel = TELEPORT_CHANNEL_QUANTUM) owner.playsound_local(owner, 'sound/effects/magic/repulse.ogg', 100, FALSE) linked_target = null linked = FALSE /datum/brain_trauma/special/psychotic_brawling name = "Violent Psychosis" desc = "Patient fights in unpredictable ways, ranging from helping his target to hitting them with brutal strength." scan_desc = "violent psychosis" gain_text = span_warning("You feel unhinged...") lose_text = span_notice("You feel more balanced.") var/datum/martial_art/psychotic_brawling/psychotic_brawling /datum/brain_trauma/special/psychotic_brawling/on_gain() ..() psychotic_brawling = new() psychotic_brawling.allow_temp_override = FALSE if(!psychotic_brawling.teach(owner, TRUE)) to_chat(owner, span_notice("But your martial knowledge keeps you grounded.")) qdel(src) /datum/brain_trauma/special/psychotic_brawling/on_lose() ..() psychotic_brawling.fully_remove(owner) QDEL_NULL(psychotic_brawling) /datum/brain_trauma/special/psychotic_brawling/bath_salts name = "Chemical Violent Psychosis" /datum/brain_trauma/special/tenacity name = "Tenacity" desc = "Patient is psychologically unaffected by pain and injuries, and can remain standing far longer than a normal person." scan_desc = "traumatic neuropathy" gain_text = span_warning("You suddenly stop feeling pain.") lose_text = span_warning("You realize you can feel pain again.") /datum/brain_trauma/special/tenacity/on_gain() owner.add_traits(list(TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_ANALGESIA), TRAUMA_TRAIT) ..() /datum/brain_trauma/special/tenacity/on_lose() owner.remove_traits(list(TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_ANALGESIA), TRAUMA_TRAIT) ..() /datum/brain_trauma/special/death_whispers name = "Functional Cerebral Necrosis" desc = "Patient's brain is stuck in a functional near-death state, causing occasional moments of lucid hallucinations, which are often interpreted as the voices of the dead." scan_desc = "chronic functional necrosis" gain_text = span_warning("You feel dead inside.") lose_text = span_notice("You feel alive again.") var/active = FALSE /datum/brain_trauma/special/death_whispers/on_life() ..() if(!active && prob(2)) whispering() /datum/brain_trauma/special/death_whispers/on_lose() if(active) cease_whispering() ..() /datum/brain_trauma/special/death_whispers/proc/whispering() ADD_TRAIT(owner, TRAIT_SIXTHSENSE, TRAUMA_TRAIT) active = TRUE addtimer(CALLBACK(src, PROC_REF(cease_whispering)), rand(5 SECONDS, 30 SECONDS)) /datum/brain_trauma/special/death_whispers/proc/cease_whispering() REMOVE_TRAIT(owner, TRAIT_SIXTHSENSE, TRAUMA_TRAIT) active = FALSE /datum/brain_trauma/special/existential_crisis name = "Existential Crisis" desc = "Patient's hold on reality becomes faint, causing occasional bouts of non-existence." scan_desc = "existential crisis" gain_text = span_warning("You feel less real.") lose_text = span_notice("You feel more substantial again.") var/obj/effect/abstract/sync_holder/veil/veil /// A cooldown to prevent constantly erratic dolphining through the fabric of reality COOLDOWN_DECLARE(crisis_cooldown) /datum/brain_trauma/special/existential_crisis/on_life(seconds_per_tick, times_fired) ..() if(!veil && COOLDOWN_FINISHED(src, crisis_cooldown) && SPT_PROB(1.5, seconds_per_tick)) if(isturf(owner.loc)) fade_out() /datum/brain_trauma/special/existential_crisis/on_lose() if(veil) fade_in() ..() /datum/brain_trauma/special/existential_crisis/proc/fade_out() if(veil) return var/duration = rand(5 SECONDS, 45 SECONDS) veil = new(owner.drop_location()) to_chat(owner, span_warning("[pick(list( "Do you even exist?", "To be or not to be...", "Why exist?", "You simply fade away.", "You stop keeping it real.", "You stop thinking for a moment. Therefore you are not.", ))]")) owner.forceMove(veil) COOLDOWN_START(src, crisis_cooldown, 1 MINUTES) addtimer(CALLBACK(src, PROC_REF(fade_in)), duration) /datum/brain_trauma/special/existential_crisis/proc/fade_in() QDEL_NULL(veil) to_chat(owner, span_notice("You fade back into reality.")) COOLDOWN_START(src, crisis_cooldown, 1 MINUTES) //base sync holder is in desynchronizer.dm /obj/effect/abstract/sync_holder/veil name = "non-existence" desc = "Existence is just a state of mind." /datum/brain_trauma/special/beepsky name = "Criminal" desc = "Patient seems to be a criminal." scan_desc = "criminal mind" gain_text = span_warning("Justice is coming for you.") lose_text = span_notice("You were absolved for your crimes.") random_gain = FALSE /// A ref to our fake beepsky image that we chase the owner with var/obj/effect/client_image_holder/securitron/beepsky /datum/brain_trauma/special/beepsky/Destroy() QDEL_NULL(beepsky) return ..() /datum/brain_trauma/special/beepsky/on_gain() create_securitron() return ..() /datum/brain_trauma/special/beepsky/proc/create_securitron() QDEL_NULL(beepsky) var/turf/where = locate(owner.x + pick(-12, 12), owner.y + pick(-12, 12), owner.z) beepsky = new(where, owner) /datum/brain_trauma/special/beepsky/on_lose() QDEL_NULL(beepsky) return ..() /datum/brain_trauma/special/beepsky/on_life() if(QDELETED(beepsky) || !beepsky.loc || beepsky.z != owner.z) if(prob(30)) create_securitron() else return if(get_dist(owner, beepsky) >= 10 && prob(20)) create_securitron() if(owner.stat != CONSCIOUS) if(prob(20)) owner.playsound_local(beepsky, 'sound/mobs/non-humanoids/beepsky/iamthelaw.ogg', 50) return if(get_dist(owner, beepsky) <= 1) owner.playsound_local(owner, 'sound/items/weapons/egloves.ogg', 50) owner.visible_message(span_warning("[owner]'s body jerks as if it was shocked."), span_userdanger("You feel the fist of the LAW.")) owner.adjustStaminaLoss(rand(40, 70)) QDEL_NULL(beepsky) if(prob(20) && get_dist(owner, beepsky) <= 8) owner.playsound_local(beepsky, 'sound/mobs/non-humanoids/beepsky/criminal.ogg', 40) /obj/effect/client_image_holder/securitron name = "Securitron" desc = "The LAW is coming." image_icon = 'icons/mob/silicon/aibots.dmi' image_state = "secbot-c" /obj/effect/client_image_holder/securitron/Initialize(mapload) . = ..() name = pick("Officer Beepsky", "Officer Johnson", "Officer Pingsky") START_PROCESSING(SSfastprocess, src) /obj/effect/client_image_holder/securitron/Destroy() STOP_PROCESSING(SSfastprocess,src) return ..() /obj/effect/client_image_holder/securitron/process() if(prob(40)) return var/mob/victim = pick(who_sees_us) forceMove(get_step_towards(src, victim)) if(prob(5)) var/beepskys_cry = "Level 10 infraction alert!" to_chat(victim, "[span_name("[name]")] exclaims, \"[span_robot("[beepskys_cry]")]") if(victim.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat)) victim.create_chat_message(src, raw_message = beepskys_cry, spans = list("robotic")) // Used by Veteran Security Advisor job. /datum/brain_trauma/special/ptsd name = "Combat PTSD" desc = "The patient is experiencing PTSD stemming from past combat exposure, resulting in a lack of emotions. Additionally, they are experiencing mild hallucinations." scan_desc = "PTSD" gain_text = span_warning("You're thrust back into the chaos of past! Explosions! Gunfire! Emotions, gone AWOL!") lose_text = span_notice("You feel flashbacks of past fade, as your emotions return and mind clear.") resilience = TRAUMA_RESILIENCE_ABSOLUTE can_gain = TRUE random_gain = FALSE /// Our cooldown declare for causing hallucinations COOLDOWN_DECLARE(ptsd_hallucinations) var/list/ptsd_hallucinations_list = list( /datum/hallucination/fake_sound/normal/boom, /datum/hallucination/fake_sound/normal/distant_boom, /datum/hallucination/stray_bullet, /datum/hallucination/battle/gun/disabler, /datum/hallucination/battle/gun/laser, /datum/hallucination/battle/bomb, /datum/hallucination/battle/e_sword, /datum/hallucination/battle/harm_baton, /datum/hallucination/battle/stun_prod, ) /datum/brain_trauma/special/ptsd/on_life(seconds_per_tick, times_fired) if(owner.stat != CONSCIOUS) return if(!COOLDOWN_FINISHED(src, ptsd_hallucinations)) return owner.cause_hallucination(pick(ptsd_hallucinations_list), "Caused by The Combat PTSD brain trauma") COOLDOWN_START(src, ptsd_hallucinations, rand(10 SECONDS, 10 MINUTES)) /datum/brain_trauma/special/ptsd/on_gain() owner.add_mood_event("combat_ptsd", /datum/mood_event/desentized) owner.mob_mood?.mood_modifier -= 1 //Basically nothing can change your mood owner.mob_mood?.sanity_level = SANITY_DISTURBED //Makes sanity on a unstable level unless cured ..() /datum/brain_trauma/special/ptsd/on_lose() owner.clear_mood_event("combat_ptsd") owner.mob_mood?.mood_modifier += 1 owner.mob_mood?.sanity_level = SANITY_GREAT return ..() /datum/brain_trauma/special/primal_instincts name = "Feral Instincts" desc = "Patient's mind is stuck in a primal state, causing them to act on instinct rather than reason." scan_desc = "ferality" gain_text = span_warning("Your pupils dilate, and it becomes harder to think straight.") lose_text = span_notice("Your mind clears, and you feel more in control.") resilience = TRAUMA_RESILIENCE_SURGERY /// Tracks any existing AI controller, so we can restore it when we're cured var/old_ai_controller_type /datum/brain_trauma/special/primal_instincts/on_gain() . = ..() if(!isnull(owner.ai_controller)) old_ai_controller_type = owner.ai_controller.type QDEL_NULL(owner.ai_controller) owner.ai_controller = new /datum/ai_controller/monkey(owner) owner.ai_controller.continue_processing_when_client = TRUE owner.ai_controller.can_idle = FALSE owner.ai_controller.set_ai_status(AI_STATUS_OFF) /datum/brain_trauma/special/primal_instincts/on_lose(silent) . = ..() if(QDELING(owner)) return QDEL_NULL(owner.ai_controller) if(old_ai_controller_type) owner.ai_controller = new old_ai_controller_type(owner) owner.remove_language(/datum/language/monkey, UNDERSTOOD_LANGUAGE, TRAUMA_TRAIT) /datum/brain_trauma/special/primal_instincts/on_life(seconds_per_tick, times_fired) if(isnull(owner.ai_controller)) qdel(src) return if(!SPT_PROB(3, seconds_per_tick)) return owner.grant_language(/datum/language/monkey, UNDERSTOOD_LANGUAGE, TRAUMA_TRAIT) owner.ai_controller.set_blackboard_key(BB_MONKEY_AGGRESSIVE, prob(75)) if(owner.ai_controller.ai_status == AI_STATUS_OFF) owner.ai_controller.set_ai_status(AI_STATUS_ON) owner.log_message("became controlled by monkey instincts ([owner.ai_controller.blackboard[BB_MONKEY_AGGRESSIVE] ? "aggressive" : "docile"])", LOG_ATTACK, color = "orange") to_chat(owner, span_warning("You feel the urge to act on your primal instincts...")) // extend original timer if we roll the effect while it's already ongoing addtimer(CALLBACK(src, PROC_REF(primal_instincts_off)), rand(20 SECONDS, 40 SECONDS), TIMER_UNIQUE|TIMER_NO_HASH_WAIT|TIMER_OVERRIDE|TIMER_DELETE_ME) /datum/brain_trauma/special/primal_instincts/proc/primal_instincts_off() owner.ai_controller.set_ai_status(AI_STATUS_OFF) owner.remove_language(/datum/language/monkey, UNDERSTOOD_LANGUAGE, TRAUMA_TRAIT) to_chat(owner, span_green("The urge subsides."))