mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-29 10:31:34 +00:00
## About The Pull Request People can now pet held mothroaches and pugs if they want to, or use items on them, hopefully without causing many issues. After all, it only took about a couple dozen lines of code to make... ...Oh, did the 527 files changed or the 850~ lines added/removed perhaps catch your eye? Made you wonder if I accidentally pushed the wrong branch? or skewed something up big time? Well, nuh uh. I just happen to be fed up with the melee attack chain still using stringized params instead of an array/list. It was frankly revolting to see how I'd have had to otherwise call `list2params` for what I'm trying to accomplish here, and make this PR another tessera to the immense stupidity of our attack chain procs calling `params2list` over and over and over instead of just using that one call instance from `ClickOn` as an argument. It's 2025, honey, wake up! I also tried to replace some of those single letter vars/args but there are just way too many of them. ## Why It's Good For The Game Improving old code. And I want to be able to pet mobroaches while holding them too. ## Changelog 🆑 qol: You can now interact with held mobs in more ways beside wearing them. /🆑
702 lines
25 KiB
Plaintext
702 lines
25 KiB
Plaintext
//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.")
|
|
/// The martial art we teach
|
|
var/datum/martial_art/psychotic_brawling/psychotic_brawling
|
|
|
|
/datum/brain_trauma/special/psychotic_brawling/on_gain()
|
|
. = ..()
|
|
psychotic_brawling = new(src)
|
|
psychotic_brawling.locked_to_use = TRUE
|
|
psychotic_brawling.teach(owner)
|
|
|
|
/datum/brain_trauma/special/psychotic_brawling/on_lose()
|
|
. = ..()
|
|
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."))
|
|
|
|
/datum/brain_trauma/special/axedoration
|
|
name = "Axe Delusions"
|
|
desc = "Patient feels an immense sense of duty towards protecting an axe and has hallucinations regarding it."
|
|
scan_desc = "object attachment"
|
|
gain_text = span_notice("You feel like protecting the fire axe is one of your greatest duties.")
|
|
lose_text = span_warning("You feel like you lost your sense of duty.")
|
|
resilience = TRAUMA_RESILIENCE_ABSOLUTE
|
|
random_gain = FALSE
|
|
var/static/list/talk_lines = list(
|
|
"I'm proud of you.",
|
|
"I believe in you!",
|
|
"Do I bother you?",
|
|
"Praise me!",
|
|
"Fires burn.",
|
|
"We made it!",
|
|
"Mother, my body disgusts me.",
|
|
"There's a gap where we meet, where I end and you begin.",
|
|
"Humble yourself.",
|
|
)
|
|
var/static/list/hurt_lines = list(
|
|
"Ow!",
|
|
"Ouch!",
|
|
"Ack!",
|
|
"It burns!",
|
|
"Stop!",
|
|
"Arghh!",
|
|
"Please!",
|
|
"End it!",
|
|
"Cease!",
|
|
"Ah!",
|
|
)
|
|
|
|
/datum/brain_trauma/special/axedoration/on_life(seconds_per_tick, times_fired)
|
|
if(owner.stat != CONSCIOUS)
|
|
return
|
|
|
|
if(!GLOB.bridge_axe)
|
|
if(SPT_PROB(0.5, seconds_per_tick))
|
|
to_chat(owner, span_warning("I've failed my duty..."))
|
|
owner.set_jitter_if_lower(5 SECONDS)
|
|
owner.set_stutter_if_lower(5 SECONDS)
|
|
if(SPT_PROB(20, seconds_per_tick))
|
|
owner.vomit(VOMIT_CATEGORY_DEFAULT)
|
|
return
|
|
|
|
var/atom/axe_location = get_axe_location()
|
|
if(!SPT_PROB(1.5, seconds_per_tick))
|
|
return
|
|
if(isliving(axe_location))
|
|
var/mob/living/axe_holder = axe_location
|
|
if(axe_holder == owner)
|
|
talk_tuah(pick(talk_lines))
|
|
return
|
|
var/datum/job/holder_job = axe_holder.mind?.assigned_role
|
|
if(holder_job && (/datum/job_department/command in holder_job.departments_list))
|
|
to_chat(owner, span_notice("I hope the axe is in good hands..."))
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_neutral)
|
|
return
|
|
to_chat(owner, span_warning("You start having a bad feeling..."))
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_missing)
|
|
return
|
|
|
|
if(!isarea(axe_location))
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_gone)
|
|
return
|
|
|
|
if(istype(axe_location, /area/station/command))
|
|
to_chat(owner, span_notice("You feel a sense of relief..."))
|
|
if(istype(GLOB.bridge_axe.loc, /obj/structure/fireaxecabinet))
|
|
return
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_neutral)
|
|
return
|
|
|
|
to_chat(owner, span_warning("You start having a bad feeling..."))
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_missing)
|
|
|
|
/datum/brain_trauma/special/axedoration/on_gain()
|
|
RegisterSignal(owner, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(on_equip))
|
|
RegisterSignal(owner, COMSIG_MOB_UNEQUIPPED_ITEM, PROC_REF(on_unequip))
|
|
RegisterSignal(owner, COMSIG_MOB_EXAMINING, PROC_REF(on_examine))
|
|
if(!GLOB.bridge_axe)
|
|
axe_gone()
|
|
return ..()
|
|
RegisterSignal(GLOB.bridge_axe, COMSIG_QDELETING, PROC_REF(axe_gone))
|
|
if(istype(get_axe_location(), /area/station/command) && istype(GLOB.bridge_axe.loc, /obj/structure/fireaxecabinet))
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_cabinet)
|
|
else if(owner.is_holding(GLOB.bridge_axe))
|
|
on_equip(owner, GLOB.bridge_axe)
|
|
else
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_neutral)
|
|
RegisterSignal(GLOB.bridge_axe, COMSIG_ITEM_AFTERATTACK, PROC_REF(on_axe_attack))
|
|
return ..()
|
|
|
|
|
|
/datum/brain_trauma/special/axedoration/on_lose()
|
|
owner.clear_mood_event("fireaxe")
|
|
UnregisterSignal(owner, list(COMSIG_MOB_EQUIPPED_ITEM, COMSIG_MOB_UNEQUIPPED_ITEM, COMSIG_MOB_EXAMINING))
|
|
if(GLOB.bridge_axe)
|
|
UnregisterSignal(GLOB.bridge_axe, COMSIG_ITEM_AFTERATTACK)
|
|
return ..()
|
|
|
|
/datum/brain_trauma/special/axedoration/proc/axe_gone(source)
|
|
SIGNAL_HANDLER
|
|
to_chat(owner, span_danger("You feel a great disturbance in the force."))
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_gone)
|
|
owner.set_jitter_if_lower(15 SECONDS)
|
|
owner.set_stutter_if_lower(15 SECONDS)
|
|
|
|
/datum/brain_trauma/special/axedoration/proc/on_equip(source, obj/item/picked_up, slot)
|
|
SIGNAL_HANDLER
|
|
if(!istype(picked_up, /obj/item/fireaxe))
|
|
return
|
|
owner.set_jitter_if_lower(3 SECONDS)
|
|
if(picked_up == GLOB.bridge_axe)
|
|
to_chat(owner, span_hypnophrase("I have it. It's time to put it back."))
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_held)
|
|
return
|
|
ADD_TRAIT(picked_up, TRAIT_NODROP, type)
|
|
to_chat(owner, span_warning("...This is not the one I'm looking after."))
|
|
owner.Immobilize(2 SECONDS)
|
|
addtimer(CALLBACK(src, PROC_REF(throw_faker), picked_up), 2 SECONDS)
|
|
|
|
/datum/brain_trauma/special/axedoration/proc/throw_faker(obj/item/faker)
|
|
REMOVE_TRAIT(faker, TRAIT_NODROP, type)
|
|
var/held_index = owner.get_held_index_of_item(faker)
|
|
if(!held_index)
|
|
return
|
|
to_chat(owner, span_warning("Be gone with you."))
|
|
owner.swap_hand(held_index, silent = TRUE)
|
|
var/turf/target_turf = get_ranged_target_turf(owner, owner.dir, faker.throw_range)
|
|
owner.throw_item(target_turf)
|
|
|
|
/datum/brain_trauma/special/axedoration/proc/on_unequip(datum/source, obj/item/dropped_item, force, new_location)
|
|
SIGNAL_HANDLER
|
|
if(dropped_item != GLOB.bridge_axe)
|
|
return
|
|
if(get_axe_location() == owner)
|
|
return
|
|
if(istype(new_location, /obj/structure/fireaxecabinet))
|
|
if(istype(get_area(new_location), /area/station/command))
|
|
to_chat(owner, span_nicegreen("Ah! Back where it belongs!"))
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_cabinet)
|
|
INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob, emote), "smile")
|
|
return
|
|
to_chat(owner, span_warning("Leaving it outside of command? Am I sure about that?"))
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_neutral)
|
|
return
|
|
to_chat(owner, span_warning("Should I really leave it here?"))
|
|
owner.add_mood_event("fireaxe", /datum/mood_event/axe_neutral)
|
|
|
|
/datum/brain_trauma/special/axedoration/proc/on_examine(mob/source, atom/target, list/examine_strings)
|
|
SIGNAL_HANDLER
|
|
if(!istype(target, /obj/item/fireaxe))
|
|
return
|
|
if(target == GLOB.bridge_axe)
|
|
examine_strings += span_notice("It's the axe I've sworn to protect.")
|
|
else
|
|
examine_strings += span_warning("It's a simulacra, a fake axe made to fool the masses.")
|
|
|
|
/datum/brain_trauma/special/axedoration/proc/on_axe_attack(obj/item/axe, atom/target, mob/user, list/modifiers)
|
|
SIGNAL_HANDLER
|
|
if(user != owner)
|
|
return
|
|
talk_tuah(pick(hurt_lines))
|
|
|
|
/datum/brain_trauma/special/axedoration/proc/talk_tuah(sent_message = "Hello World.")
|
|
owner.Hear(null, GLOB.bridge_axe, owner.get_selected_language(), sent_message)
|
|
|
|
/datum/brain_trauma/special/axedoration/proc/get_axe_location()
|
|
if(!GLOB.bridge_axe)
|
|
return
|
|
var/atom/axe_loc = GLOB.bridge_axe.loc
|
|
while(!ismob(axe_loc) && !isarea(axe_loc) && !isnull(axe_loc))
|
|
axe_loc = axe_loc.loc
|
|
return axe_loc
|