From 9f8ad74bf9c067ac06334ead6fc9826cb4b06aa3 Mon Sep 17 00:00:00 2001 From: GrayRachnid Date: Tue, 8 Oct 2019 03:53:01 -0400 Subject: [PATCH] New traumas and some other things. --- code/__DEFINES/components.dm | 8 + code/__DEFINES/status_effects.dm | 4 + code/__DEFINES/traits.dm | 3 + code/__HELPERS/mobs.dm | 10 +- code/_globalvars/lists/poll_ignore.dm | 4 + code/_onclick/hud/alert.dm | 6 + code/datums/brain_damage/brain_trauma.dm | 25 ++- code/datums/brain_damage/creepy_trauma.dm | 116 +++++++++++++ code/datums/brain_damage/hypnosis.dm | 37 ++-- code/datums/brain_damage/imaginary_friend.dm | 70 ++++++-- code/datums/brain_damage/mild.dm | 164 ++++++++++++------ code/datums/brain_damage/phobia.dm | 119 ++++++++++--- code/datums/brain_damage/severe.dm | 6 +- code/datums/brain_damage/special.dm | 109 +++++++++++- code/datums/brain_damage/split_personality.dm | 16 +- code/datums/components/stationloving.dm | 3 +- code/datums/status_effects/debuffs.dm | 97 +++++++---- code/datums/status_effects/neutral.dm | 14 ++ code/datums/status_effects/status_effect.dm | 9 + code/game/atoms.dm | 2 +- .../temporary_visuals/miscellaneous.dm | 5 + .../objects/items/devices/desynchronizer.dm | 87 ++++++++++ .../antagonists/traitor/datum_traitor.dm | 6 + code/modules/client/client_colour.dm | 3 + code/modules/mob/living/carbon/say.dm | 16 +- code/modules/mob/living/emote.dm | 4 +- .../chemistry/reagents/alcohol_reagents.dm | 1 + .../chemistry/reagents/drink_reagents.dm | 4 + .../research/designs/bluespace_designs.dm | 10 ++ .../research/nanites/nanite_programs.dm | 3 - .../nanites/nanite_programs/sensor.dm | 9 +- code/modules/research/techweb/all_nodes.dm | 9 + icons/mob/screen_alert.dmi | Bin 105034 -> 106746 bytes icons/obj/device.dmi | Bin 45858 -> 46595 bytes tgstation.dme | 1 + 35 files changed, 785 insertions(+), 195 deletions(-) create mode 100644 code/datums/brain_damage/creepy_trauma.dm create mode 100644 code/game/objects/items/devices/desynchronizer.dm diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm index 40aea24105..d387575235 100644 --- a/code/__DEFINES/components.dm +++ b/code/__DEFINES/components.dm @@ -118,7 +118,15 @@ #define COMPONENT_CANCEL_THROW 1 #define COMSIG_MOVABLE_POST_THROW "movable_post_throw" //from base of atom/movable/throw_at(): (datum/thrownthing, spin) #define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit" //from base of atom/movable/onTransitZ(): (old_z, new_z) +#define COMSIG_MOVABLE_SECLUDED_LOCATION "movable_secluded" //called when the movable is placed in an unaccessible area, used for stationloving: () #define COMSIG_MOVABLE_HEAR "movable_hear" //from base of atom/movable/Hear(): (message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) + #define HEARING_MESSAGE 1 + #define HEARING_SPEAKER 2 +// #define HEARING_LANGUAGE 3 + #define HEARING_RAW_MESSAGE 4 + /* #define HEARING_RADIO_FREQ 5 + #define HEARING_SPANS 6 + #define HEARING_MESSAGE_MODE 7 */ #define COMSIG_MOVABLE_DISPOSING "movable_disposing" //called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, obj/machinery/disposal/source) // /mob signals diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 3cd64af8c7..96207e2468 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -7,6 +7,8 @@ #define STATUS_EFFECT_REPLACE 2 //if it allows only one, but new instances replace +#define STATUS_EFFECT_REFRESH 3 // if it only allows one, and new instances just instead refresh the timer + /////////// // BUFFS // /////////// @@ -72,6 +74,8 @@ #define STATUS_EFFECT_ICHORIAL_STAIN /datum/status_effect/ichorial_stain //Prevents a servant from being revived by vitality matrices for one minute. +#define STATUS_EFFECT_SPASMS /datum/status_effect/spasms //causes random muscle spasms + ///////////// // NEUTRAL // ///////////// diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index e198041c6e..546d587f56 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -110,6 +110,7 @@ #define TRAIT_NOHARDCRIT "nohardcrit" #define TRAIT_NOSOFTCRIT "nosoftcrit" #define TRAIT_MINDSHIELD "mindshield" +#define TRAIT_SIXTHSENSE "sixthsense" #define TRAIT_FEARLESS "fearless" #define TRAIT_UNSTABLE "unstable" #define TRAIT_PARALYSIS_L_ARM "para-l-arm" //These are used for brain-based paralysis, where replacing the limb won't fix it @@ -117,6 +118,7 @@ #define TRAIT_PARALYSIS_L_LEG "para-l-leg" #define TRAIT_PARALYSIS_R_LEG "para-r-leg" #define TRAIT_UNINTELLIGIBLE_SPEECH "unintelligible-speech" +#define TRAIT_SOOTHED_THROAT "soothed-throat" #define TRAIT_LAW_ENFORCEMENT_METABOLISM "law-enforcement-metabolism" #define TRAIT_STRONG_GRABBER "strong_grabber" #define TRAIT_CALCIUM_HEALER "calcium_healer" @@ -174,6 +176,7 @@ #define CULT_TRAIT "cult" #define CURSED_ITEM_TRAIT "cursed-item" // The item is magically cursed #define ABSTRACT_ITEM_TRAIT "abstract-item" +#define STATUS_EFFECT_TRAIT "status-effect" #define ROUNDSTART_TRAIT "roundstart" //cannot be removed without admin intervention // unique trait sources, still defines diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 8f3cd4f60d..be9ce87e86 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -514,12 +514,14 @@ GLOBAL_LIST_EMPTY(species_list) else prefs = new - var/adminoverride = 0 + var/override = FALSE if(M.client && M.client.holder && (prefs.chat_toggles & CHAT_DEAD)) - adminoverride = 1 - if(isnewplayer(M) && !adminoverride) + override = TRUE + if(HAS_TRAIT(M, TRAIT_SIXTHSENSE)) + override = TRUE + if(isnewplayer(M) && !override) continue - if(M.stat != DEAD && !adminoverride) + if(M.stat != DEAD && !override) continue if(speaker_key && speaker_key in prefs.ignoring) continue diff --git a/code/_globalvars/lists/poll_ignore.dm b/code/_globalvars/lists/poll_ignore.dm index 94723cae38..2aa12ad7a7 100644 --- a/code/_globalvars/lists/poll_ignore.dm +++ b/code/_globalvars/lists/poll_ignore.dm @@ -13,6 +13,8 @@ #define POLL_IGNORE_GOLEM "golem" #define POLL_IGNORE_SWARMER "swarmer" #define POLL_IGNORE_DRONE "drone" +#define POLL_IGNORE_IMAGINARYFRIEND "imaginary_friend" +#define POLL_IGNORE_SPLITPERSONALITY "split_personality" GLOBAL_LIST_INIT(poll_ignore_desc, list( POLL_IGNORE_SENTIENCE_POTION = "Sentience potion", @@ -28,6 +30,8 @@ GLOBAL_LIST_INIT(poll_ignore_desc, list( POLL_IGNORE_GOLEM = "Golems", POLL_IGNORE_SWARMER = "Swarmer shells", POLL_IGNORE_DRONE = "Drone shells", + POLL_IGNORE_IMAGINARYFRIEND = "Imaginary Friend", + POLL_IGNORE_SPLITPERSONALITY = "Split Personality", )) GLOBAL_LIST_INIT(poll_ignore, init_poll_ignore()) diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index cc183dd6d3..391e86f390 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -213,6 +213,12 @@ or something covering your eyes." desc = "Whoa man, you're tripping balls! Careful you don't get addicted... if you aren't already." icon_state = "high" +/obj/screen/alert/hypnosis + name = "Hypnosis" + desc = "Something's hypnotizing you, but you're not really sure about what." + icon_state = "hypnosis" + var/phrase + /obj/screen/alert/drunk //Not implemented name = "Drunk" desc = "All that alcohol you've been drinking is impairing your speech, motor skills, and mental cognition. Make sure to act like it." diff --git a/code/datums/brain_damage/brain_trauma.dm b/code/datums/brain_damage/brain_trauma.dm index 56a3f3969b..1aa1341c9c 100644 --- a/code/datums/brain_damage/brain_trauma.dm +++ b/code/datums/brain_damage/brain_trauma.dm @@ -1,10 +1,12 @@ //Brain Traumas are the new actual brain damage. Brain damage itself acts as a way to acquire traumas: every time brain damage is dealt, there's a chance of receiving a trauma. //This chance gets higher the higher the mob's brainloss is. Removing traumas is a separate thing from removing brain damage: you can get restored to full brain operativity, -//but keep the quirks, until repaired by mannitol (for mild/special ones) or brain surgery (for severe ones). +// but keep the quirks, until repaired by neurine, surgery, lobotomy or magic; depending on the resilience +// of the trauma. + /datum/brain_trauma var/name = "Brain Trauma" var/desc = "A trauma caused by brain damage, which causes issues to the patient." - var/scan_desc = "a generic brain trauma" //description when detected by a health scanner + var/scan_desc = "generic brain trauma" //description when detected by a health scanner var/mob/living/carbon/owner //the poor bastard var/obj/item/organ/brain/brain //the poor bastard's brain var/gain_text = "You feel traumatized." @@ -12,15 +14,21 @@ var/can_gain = TRUE var/random_gain = TRUE //can this be gained through random traumas? var/resilience = TRAUMA_RESILIENCE_BASIC //how hard is this to cure? + var/clonable = TRUE // will this transfer if the brain is cloned? /datum/brain_trauma/Destroy() - brain.traumas -= src + if(brain && brain.traumas) + brain.traumas -= src if(owner) on_lose() brain = null owner = null return ..() +/datum/brain_trauma/proc/on_clone() + if(clonable) + return new type + //Called on life ticks /datum/brain_trauma/proc/on_life() return @@ -33,17 +41,24 @@ /datum/brain_trauma/proc/on_gain() to_chat(owner, gain_text) RegisterSignal(owner, COMSIG_MOB_SAY, .proc/handle_speech) + RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/handle_hearing) //Called when removed from a mob /datum/brain_trauma/proc/on_lose(silent) if(!silent) to_chat(owner, lose_text) UnregisterSignal(owner, COMSIG_MOB_SAY) + UnregisterSignal(owner, COMSIG_MOVABLE_HEAR) //Called when hearing a spoken message -/datum/brain_trauma/proc/on_hear(message, speaker, message_language, raw_message, radio_freq) - return message +/datum/brain_trauma/proc/handle_hearing(datum/source, list/hearing_args) + UnregisterSignal(owner, COMSIG_MOVABLE_HEAR) //Called when speaking /datum/brain_trauma/proc/handle_speech(datum/source, list/speech_args) UnregisterSignal(owner, COMSIG_MOB_SAY) + + +//Called when hugging. expand into generally interacting, where future coders could switch the intent? +/datum/brain_trauma/proc/on_hug(mob/living/hugger, mob/living/hugged) + return diff --git a/code/datums/brain_damage/creepy_trauma.dm b/code/datums/brain_damage/creepy_trauma.dm new file mode 100644 index 0000000000..8c0e49d5e6 --- /dev/null +++ b/code/datums/brain_damage/creepy_trauma.dm @@ -0,0 +1,116 @@ +/datum/brain_trauma/special/obsessed + name = "Psychotic Schizophrenia" + desc = "Patient has a subtype of delusional disorder, becoming irrationally attached to someone." + scan_desc = "psychotic schizophrenic delusions" + gain_text = "If you see this message, make a github issue report. The trauma initialized wrong." + lose_text = "The voices in your head fall silent." + can_gain = TRUE + random_gain = FALSE + resilience = TRAUMA_RESILIENCE_SURGERY + var/mob/living/obsession + var/datum/objective/spendtime/attachedobsessedobj + var/datum/antagonist/obsessed/antagonist + var/viewing = FALSE //it's a lot better to store if the owner is watching the obsession than checking it twice between two procs + + var/total_time_creeping = 0 //just for roundend fun + var/time_spent_away = 0 + var/obsession_hug_count = 0 + +/datum/brain_trauma/special/obsessed/on_gain() + + //setup, linking, etc// + if(!obsession)//admins didn't set one + obsession = find_obsession() + if(!obsession)//we didn't find one + lose_text = "" + qdel(src) + return + gain_text = "You hear a sickening, raspy voice in your head. It wants one small task of you..." + owner.mind.add_antag_datum(/datum/antagonist/obsessed) + antagonist = owner.mind.has_antag_datum(/datum/antagonist/obsessed) + antagonist.trauma = src + ..() + //antag stuff// + antagonist.forge_objectives(obsession.mind) + antagonist.greet() + +/datum/brain_trauma/special/obsessed/on_life() + if(!obsession || obsession.stat == DEAD) + viewing = FALSE//important, makes sure you no longer stutter when happy if you murdered them while viewing + return + if(get_dist(get_turf(owner), get_turf(obsession)) > 7) + viewing = FALSE //they are further than our viewrange they are not viewing us + out_of_view() + return//so we're not searching everything in view every tick + if(obsession in view(7, owner)) + viewing = TRUE + else + viewing = FALSE + if(viewing) + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "creeping", /datum/mood_event/creeping, obsession.name) + total_time_creeping += 20 + time_spent_away = 0 + if(attachedobsessedobj)//if an objective needs to tick down, we can do that since traumas coexist with the antagonist datum + attachedobsessedobj.timer -= 20 //mob subsystem ticks every 2 seconds(?), remove 20 deciseconds from the timer. sure, that makes sense. + else + out_of_view() + +/datum/brain_trauma/special/obsessed/proc/out_of_view() + time_spent_away += 20 + if(time_spent_away > 1800) //3 minutes + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "creeping", /datum/mood_event/notcreepingsevere, obsession.name) + else + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "creeping", /datum/mood_event/notcreeping, obsession.name) + +/datum/brain_trauma/special/obsessed/on_lose() + ..() + owner.mind.remove_antag_datum(/datum/antagonist/obsessed) + +/datum/brain_trauma/special/obsessed/handle_speech(datum/source, list/speech_args) + if(!viewing) + return + var/datum/component/mood/mood = owner.GetComponent(/datum/component/mood) + if(mood && mood.sanity >= SANITY_GREAT && social_interaction()) + speech_args[SPEECH_MESSAGE] = "" + +/datum/brain_trauma/special/obsessed/on_hug(mob/living/hugger, mob/living/hugged) + if(hugged == obsession) + obsession_hug_count++ + +/datum/brain_trauma/special/obsessed/proc/social_interaction() + var/fail = FALSE //whether you can finish a sentence while doing it + owner.stuttering = max(3, owner.stuttering) + owner.blur_eyes(10) + switch(rand(1,4)) + if(1) + shake_camera(owner, 15, 1) + owner.vomit() + fail = TRUE + if(2) + owner.emote("cough") + owner.dizziness += 10 + fail = TRUE + if(3) + to_chat(owner, "You feel your heart lurching in your chest...") + owner.Stun(20) + shake_camera(owner, 15, 1) + if(4) + to_chat(owner, "You faint.") + owner.Unconscious(80) + fail = TRUE + return fail + + +/datum/brain_trauma/special/obsessed/proc/find_obsession() + var/chosen_victim + var/list/possible_targets = list() + var/list/viable_minds = list() + for(var/mob/Player in GLOB.player_list)//prevents crewmembers falling in love with nuke ops they never met, and other annoying hijinks + if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) && !isbrain(Player) && Player.client && Player != owner && SSjob.GetJob(Player.mind.assigned_role)) + viable_minds += Player.mind + for(var/datum/mind/possible_target in viable_minds) + if(possible_target != owner && ishuman(possible_target.current)) + possible_targets += possible_target.current + if(possible_targets.len > 0) + chosen_victim = pick(possible_targets) + return chosen_victim diff --git a/code/datums/brain_damage/hypnosis.dm b/code/datums/brain_damage/hypnosis.dm index 8909d1b85f..e717d43859 100644 --- a/code/datums/brain_damage/hypnosis.dm +++ b/code/datums/brain_damage/hypnosis.dm @@ -5,19 +5,14 @@ gain_text = "" lose_text = "" resilience = TRAUMA_RESILIENCE_SURGERY + var/hypnotic_phrase = "" var/regex/target_phrase -/datum/brain_trauma/hypnosis/New(phrase, quirk = FALSE) +/datum/brain_trauma/hypnosis/New(phrase) if(!phrase) qdel(src) - if(quirk == TRUE) - hypnotic_phrase = phrase - else - friendliify(phrase) - if(IsAdminAdvancedProcCall()) - to_chat(usr, "Hypnosis New() skipped due to try/catch incompatibility with admin proccalling.") - qdel(src) + hypnotic_phrase = phrase try target_phrase = new("(\\b[hypnotic_phrase]\\b)","ig") catch(var/exception/e) @@ -25,16 +20,6 @@ qdel(src) ..() -/datum/brain_trauma/hypnosis/proc/friendliify(phrase) - phrase = replacetext(lowertext(phrase), "kill", "hug") - phrase = replacetext(lowertext(phrase), "murder", "cuddle") - phrase = replacetext(lowertext(phrase), "harm", "snuggle") - phrase = replacetext(lowertext(phrase), "decapitate", "headpat") - phrase = replacetext(lowertext(phrase), "strangle", "meow at") - phrase = replacetext(lowertext(phrase), "suicide", "self-love") - phrase = replacetext(lowertext(phrase), "lynch", "kiss") - 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]'.") @@ -44,18 +29,17 @@ "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.")]") - if(!HAS_TRAIT(owner, "hypnotherapy")) - 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,\ + 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.") - else - to_chat(owner, "You've been hypnotized by this sentence. You feel an incredible desire to follow these words, but are able to resist it somewhat. If it isn't a clear order, you can freely interpret how to do so,\ - however this does not take precedence over your other objectives.") + var/obj/screen/alert/hypnosis/hypno_alert = owner.throw_alert("hypnosis", /obj/screen/alert/hypnosis) + hypno_alert.desc = "\"[hypnotic_phrase]\"... your mind seems to be fixated on this concept." ..() /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 fixation. The phrase '[hypnotic_phrase]' no longer feels important to you.") + to_chat(owner, "You suddenly snap out of your hypnosis. The phrase '[hypnotic_phrase]' no longer feels important to you.") + owner.clear_alert("hypnosis") ..() /datum/brain_trauma/hypnosis/on_life() @@ -67,6 +51,5 @@ 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) - message = target_phrase.Replace(message, "$1") - return message +/datum/brain_trauma/hypnosis/handle_hearing(datum/source, list/hearing_args) + hearing_args[HEARING_MESSAGE] = target_phrase.Replace(hearing_args[HEARING_MESSAGE], "$1") diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index 1bc7d8e3be..3115ea914f 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -8,6 +8,10 @@ var/friend_initialized = FALSE /datum/brain_trauma/special/imaginary_friend/on_gain() + var/mob/living/M = owner + if(M.stat == DEAD || !M.client) + qdel(src) + return ..() make_friend() get_ghost() @@ -43,7 +47,7 @@ /datum/brain_trauma/special/imaginary_friend/proc/get_ghost() set waitfor = FALSE - var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s imaginary friend?", ROLE_PAI, null, null, 75, friend) + var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s imaginary friend?", ROLE_PAI, null, null, 75, friend, POLL_IGNORE_IMAGINARYFRIEND) if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) friend.key = C.key @@ -74,26 +78,34 @@ /mob/camera/imaginary_friend/Login() ..() - to_chat(src, "You are the imaginary friend of [owner]!") - to_chat(src, "You are absolutely loyal to your friend, no matter what.") - to_chat(src, "You cannot directly influence the world around you, but you can see what [owner] cannot.") + greet() Show() +/mob/camera/imaginary_friend/proc/greet() + to_chat(src, "You are the imaginary friend of [owner]!") + to_chat(src, "You are absolutely loyal to your friend, no matter what.") + to_chat(src, "You cannot directly influence the world around you, but you can see what [owner] cannot.") + /mob/camera/imaginary_friend/Initialize(mapload, _trauma) . = ..() - var/gender = pick(MALE, FEMALE) - real_name = random_unique_name(gender) - name = real_name + trauma = _trauma owner = trauma.owner copy_known_languages_from(owner, TRUE) - human_image = get_flat_human_icon(null, pick(SSjob.occupations)) + + setup_friend() join = new join.Grant(src) hide = new hide.Grant(src) +/mob/camera/imaginary_friend/proc/setup_friend() + var/gender = pick(MALE, FEMALE) + real_name = random_unique_name(gender) + name = real_name + human_image = get_flat_human_icon(null, pick(SSjob.occupations)) + /mob/camera/imaginary_friend/proc/Show() if(!client) //nobody home return @@ -132,7 +144,7 @@ if(client.prefs.muted & MUTE_IC) to_chat(src, "You cannot send IC messages (muted).") return - if (src.client.handle_spam_prevention(message,MUTE_IC)) + if (!(ignore_spam || forced) && src.client.handle_spam_prevention(message,MUTE_IC)) return friend_talk(message) @@ -218,4 +230,42 @@ var/mob/camera/imaginary_friend/I = owner I.hidden = !I.hidden I.Show() - update_status() \ No newline at end of file + update_status() + +//down here is the trapped mind +//like imaginary friend but a lot less imagination and more like mind prison// + +/datum/brain_trauma/special/imaginary_friend/trapped_owner + name = "Trapped Victim" + desc = "Patient appears to be targeted by an invisible entity." + gain_text = "" + lose_text = "" + random_gain = FALSE + +/datum/brain_trauma/special/imaginary_friend/trapped_owner/make_friend() + friend = new /mob/camera/imaginary_friend/trapped(get_turf(owner), src) + +/datum/brain_trauma/special/imaginary_friend/trapped_owner/reroll_friend() //no rerolling- it's just the last owner's hell + if(friend.client) //reconnected + return + friend_initialized = FALSE + QDEL_NULL(friend) + qdel(src) + +/datum/brain_trauma/special/imaginary_friend/trapped_owner/get_ghost() //no randoms + return + +/mob/camera/imaginary_friend/trapped + name = "figment of imagination?" + real_name = "figment of imagination?" + desc = "The previous host of this body." + +/mob/camera/imaginary_friend/trapped/greet() + to_chat(src, "You have managed to hold on as a figment of the new host's imagination!") + to_chat(src, "All hope is lost for you, but at least you may interact with your host. You do not have to be loyal to them.") + to_chat(src, "You cannot directly influence the world around you, but you can see what the host cannot.") + +/mob/camera/imaginary_friend/trapped/setup_friend() + real_name = "[owner.real_name]?" + name = real_name + human_image = icon('icons/mob/lavaland/lavaland_monsters.dmi', icon_state = "curseblob") diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm index c049a7db33..bacc171fbe 100644 --- a/code/datums/brain_damage/mild.dm +++ b/code/datums/brain_damage/mild.dm @@ -64,21 +64,21 @@ name = "Speech Impediment" desc = "Patient is unable to form coherent sentences." scan_desc = "communication disorder" - gain_text = "" //mutation will handle the text - lose_text = "" + gain_text = "You can't seem to form any coherent thoughts!" + lose_text = "Your mind feels more clear." /datum/brain_trauma/mild/speech_impediment/on_gain() ADD_TRAIT(owner, TRAIT_UNINTELLIGIBLE_SPEECH, TRAUMA_TRAIT) - . = ..() + ..() /datum/brain_trauma/mild/speech_impediment/on_lose() REMOVE_TRAIT(owner, TRAIT_UNINTELLIGIBLE_SPEECH, TRAUMA_TRAIT) - . = ..() + ..() /datum/brain_trauma/mild/concussion name = "Concussion" desc = "Patient's brain is concussed." - scan_desc = "a concussion" + scan_desc = "concussion" gain_text = "Your head hurts!" lose_text = "The pressure inside your head starts fading." @@ -157,54 +157,108 @@ gain_text = "Your muscles feel oddly faint." lose_text = "You feel in control of your muscles again." -/datum/brain_trauma/mild/muscle_spasms/on_life() - if(prob(7)) - switch(rand(1,5)) - if(1) - if(owner.canmove && !isspaceturf(owner.loc)) - to_chat(owner, "Your leg spasms!") - step(owner, pick(GLOB.cardinals)) - if(2) - if(owner.incapacitated()) - return - var/obj/item/I = owner.get_active_held_item() - if(I) - to_chat(owner, "Your fingers spasm!") - owner.log_message("used [I] due to a Muscle Spasm", LOG_ATTACK) - I.attack_self(owner) - if(3) - var/prev_intent = owner.a_intent - owner.a_intent = INTENT_HARM - - var/range = 1 - if(istype(owner.get_active_held_item(), /obj/item/gun)) //get targets to shoot at - range = 7 - - var/list/mob/living/targets = list() - for(var/mob/M in oview(owner, range)) - if(isliving(M)) - targets += M - if(LAZYLEN(targets)) - to_chat(owner, "Your arm spasms!") - owner.log_message(" attacked someone due to a Muscle Spasm") //the following attack will log itself - owner.ClickOn(pick(targets)) - owner.a_intent = prev_intent - if(4) - var/prev_intent = owner.a_intent - owner.a_intent = INTENT_HARM - to_chat(owner, "Your arm spasms!") - owner.log_message("attacked [owner.p_them()]self to a Muscle Spasm", LOG_ATTACK) - owner.ClickOn(owner) - owner.a_intent = prev_intent - if(5) - if(owner.incapacitated()) - return - var/obj/item/I = owner.get_active_held_item() - var/list/turf/targets = list() - for(var/turf/T in oview(owner, 3)) - targets += T - if(LAZYLEN(targets) && I) - to_chat(owner, "Your arm spasms!") - owner.log_message("threw [I] due to a Muscle Spasm", LOG_ATTACK) - owner.throw_item(pick(targets)) +/datum/brain_trauma/mild/muscle_spasms/on_gain() + owner.apply_status_effect(STATUS_EFFECT_SPASMS) ..() + +/datum/brain_trauma/mild/muscle_spasms/on_lose() + owner.remove_status_effect(STATUS_EFFECT_SPASMS) + ..() + +/datum/brain_trauma/mild/nervous_cough + name = "Nervous Cough" + desc = "Patient feels a constant need to cough." + scan_desc = "nervous cough" + gain_text = "Your throat itches incessantly..." + lose_text = "Your throat stops itching." + +/datum/brain_trauma/mild/nervous_cough/on_life() + if(prob(12) && !HAS_TRAIT(owner, TRAIT_SOOTHED_THROAT)) + if(prob(5)) + to_chat(owner, "[pick("You have a coughing fit!", "You can't stop coughing!")]") + owner.stun(20) + owner.emote("cough") + addtimer(CALLBACK(owner, /mob/.proc/emote, "cough"), 6) + addtimer(CALLBACK(owner, /mob/.proc/emote, "cough"), 12) + owner.emote("cough") + ..() + +/datum/brain_trauma/mild/expressive_aphasia + name = "Expressive Aphasia" + desc = "Patient is affected by partial loss of speech leading to a reduced vocabulary." + scan_desc = "inability to form complex sentences" + gain_text = "You lose your grasp on complex words." + lose_text = "You feel your vocabulary returning to normal again." + + var/static/list/common_words = world.file2list("strings/1000_most_common.txt") + +/datum/brain_trauma/mild/expressive_aphasia/handle_speech(datum/source, list/speech_args) + var/message = speech_args[SPEECH_MESSAGE] + if(message) + var/list/message_split = splittext(message, " ") + var/list/new_message = list() + + for(var/word in message_split) + var/suffix = copytext(word,-1) + + // Check if we have a suffix and break it out of the word + if(suffix in list("." , "," , ";" , "!" , ":" , "?")) + word = copytext(word,1,-1) + else + suffix = "" + + word = html_decode(word) + + if(lowertext(word) in common_words) + new_message += word + suffix + else + if(prob(30) && message_split.len > 2) + new_message += pick("uh","erm") + break + else + var/list/charlist = string2charlist(word) // Stupid shit code + shuffle_inplace(charlist) + charlist.len = round(charlist.len * 0.5,1) + new_message += html_encode(jointext(charlist,"")) + suffix + + message = jointext(new_message, " ") + + speech_args[SPEECH_MESSAGE] = trim(message) + +/datum/brain_trauma/mild/mind_echo + name = "Mind Echo" + desc = "Patient's language neurons do not terminate properly, causing previous speech patterns to occasionally resurface spontaneously." + scan_desc = "looping neural pattern" + gain_text = "You feel a faint echo of your thoughts..." + lose_text = "The faint echo fades away." + var/list/hear_dejavu = list() + var/list/speak_dejavu = list() + +/datum/brain_trauma/mild/mind_echo/handle_hearing(datum/source, list/hearing_args) + if(owner == hearing_args[HEARING_SPEAKER]) + return + if(hear_dejavu.len >= 5) + if(prob(25)) + var/deja_vu = pick_n_take(hear_dejavu) + var/static/regex/quoted_spoken_message = regex("\".+\"", "gi") + hearing_args[HEARING_MESSAGE] = quoted_spoken_message.Replace(hearing_args[HEARING_MESSAGE], "\"[deja_vu]\"") //Quotes included to avoid cases where someone says part of their name + return + if(hear_dejavu.len >= 15) + if(prob(50)) + popleft(hear_dejavu) //Remove the oldest + hear_dejavu += hearing_args[HEARING_RAW_MESSAGE] + else + hear_dejavu += hearing_args[HEARING_RAW_MESSAGE] + +/datum/brain_trauma/mild/mind_echo/handle_speech(datum/source, list/speech_args) + if(speak_dejavu.len >= 5) + if(prob(25)) + var/deja_vu = pick_n_take(speak_dejavu) + speech_args[SPEECH_MESSAGE] = deja_vu + return + if(speak_dejavu.len >= 15) + if(prob(50)) + popleft(speak_dejavu) //Remove the oldest + speak_dejavu += speech_args[SPEECH_MESSAGE] + else + speak_dejavu += speech_args[SPEECH_MESSAGE] \ No newline at end of file diff --git a/code/datums/brain_damage/phobia.dm b/code/datums/brain_damage/phobia.dm index f802555c7e..034f2baaaf 100644 --- a/code/datums/brain_damage/phobia.dm +++ b/code/datums/brain_damage/phobia.dm @@ -2,8 +2,8 @@ name = "Phobia" desc = "Patient is unreasonably afraid of something." scan_desc = "phobia" - gain_text = "" - lose_text = "" + gain_text = "You start finding default values very unnerving..." + lose_text = "You no longer feel afraid of default values." var/phobia_type var/next_check = 0 var/next_scare = 0 @@ -14,8 +14,10 @@ var/list/trigger_turfs var/list/trigger_species -/datum/brain_trauma/mild/phobia/New(specific_type) - phobia_type = specific_type +/datum/brain_trauma/mild/phobia/New(new_phobia_type) + if(new_phobia_type) + phobia_type = new_phobia_type + if(!phobia_type) phobia_type = pick(SStraumas.phobia_types) @@ -29,6 +31,11 @@ trigger_species = SStraumas.phobia_species[phobia_type] ..() + +/datum/brain_trauma/mild/phobia/on_clone() + if(clonable) + return new type(phobia_type) + /datum/brain_trauma/mild/phobia/on_life() ..() if(HAS_TRAIT(owner, TRAIT_FEARLESS)) @@ -44,6 +51,12 @@ if(is_type_in_typecache(O, trigger_objs)) freak_out(O) return + for(var/mob/living/carbon/human/HU in seen_atoms) //check equipment for trigger items + for(var/X in HU.get_all_slots() | HU.held_items) + var/obj/I = X + if(!QDELETED(I) && is_type_in_typecache(I, trigger_objs)) + freak_out(I) + return if(LAZYLEN(trigger_turfs)) for(var/turf/T in seen_atoms) @@ -51,45 +64,41 @@ freak_out(T) return - if(LAZYLEN(trigger_mobs) || LAZYLEN(trigger_objs)) + seen_atoms -= owner //make sure they aren't afraid of themselves. + if(LAZYLEN(trigger_mobs) || LAZYLEN(trigger_species)) for(var/mob/M in seen_atoms) if(is_type_in_typecache(M, trigger_mobs)) freak_out(M) return - else if(ishuman(M)) //check their equipment for trigger items + else if(ishuman(M)) //check their species var/mob/living/carbon/human/H = M if(LAZYLEN(trigger_species) && H.dna && H.dna.species && is_type_in_typecache(H.dna.species, trigger_species)) freak_out(H) + return - for(var/X in H.get_all_slots() | H.held_items) - var/obj/I = X - if(!QDELETED(I) && is_type_in_typecache(I, trigger_objs)) - freak_out(I) - return - -/datum/brain_trauma/mild/phobia/on_hear(message, speaker, message_language, raw_message, radio_freq) +/datum/brain_trauma/mild/phobia/handle_hearing(datum/source, list/hearing_args) if(!owner.can_hear() || world.time < next_scare) //words can't trigger you if you can't hear them *taps head* - return message + return if(HAS_TRAIT(owner, TRAIT_FEARLESS)) - return message + return for(var/word in trigger_words) - var/reg = regex("(\\b|\\A)[REGEX_QUOTE(word)]'?s*(\\b|\\Z)", "i") + var/regex/reg = regex("(\\b|\\A)[REGEX_QUOTE(word)]'?s*(\\b|\\Z)", "i") - if(findtext(raw_message, reg)) + if(findtext(hearing_args[HEARING_RAW_MESSAGE], reg)) addtimer(CALLBACK(src, .proc/freak_out, null, word), 10) //to react AFTER the chat message + hearing_args[HEARING_MESSAGE] = reg.Replace(hearing_args[HEARING_MESSAGE], "$1") break - return message /datum/brain_trauma/mild/phobia/handle_speech(datum/source, list/speech_args) if(HAS_TRAIT(owner, TRAIT_FEARLESS)) return for(var/word in trigger_words) - var/reg = regex("(\\b|\\A)[REGEX_QUOTE(word)]'?s*(\\b|\\Z)", "i") + var/regex/reg = regex("(\\b|\\A)[REGEX_QUOTE(word)]'?s*(\\b|\\Z)", "i") if(findtext(speech_args[SPEECH_MESSAGE], reg)) - to_chat(owner, "You can't bring yourself to say the word \"[word]\"!") + to_chat(owner, "You can't bring yourself to say the word \"[word]\"!") speech_args[SPEECH_MESSAGE] = "" /datum/brain_trauma/mild/phobia/proc/freak_out(atom/reason, trigger_word) @@ -125,6 +134,76 @@ owner.Jitter(10) owner.stuttering += 10 +// Defined phobia types for badminry, not included in the RNG trauma pool to avoid diluting. + +/datum/brain_trauma/mild/phobia/spiders + phobia_type = "spiders" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/space + phobia_type = "space" + random_gain = FALSE + /datum/brain_trauma/mild/phobia/security phobia_type = "security" random_gain = FALSE + +/datum/brain_trauma/mild/phobia/clowns + phobia_type = "clowns" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/greytide + phobia_type = "greytide" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/lizards + phobia_type = "lizards" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/skeletons + phobia_type = "skeletons" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/snakes + phobia_type = "snakes" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/robots + phobia_type = "robots" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/doctors + phobia_type = "doctors" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/authority + phobia_type = "authority" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/supernatural + phobia_type = "the supernatural" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/aliens + phobia_type = "aliens" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/strangers + phobia_type = "strangers" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/birds + phobia_type = "birds" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/falling + phobia_type = "falling" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/anime + phobia_type = "anime" + random_gain = FALSE + +/datum/brain_trauma/mild/phobia/conspiracies + phobia_type = "conspiracies" + random_gain = FALSE diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index 890e9cf903..0e08c4cd15 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -119,7 +119,7 @@ owner.update_disabled_bodyparts() /datum/brain_trauma/severe/paralysis/paraplegic - //can_gain = FALSE maybe breaks. + random_gain = FALSE paralysis_type = "legs" resilience = TRAUMA_RESILIENCE_ABSOLUTE @@ -149,7 +149,7 @@ /datum/brain_trauma/severe/monophobia name = "Monophobia" desc = "Patient feels sick and distressed when not around other people, leading to potentially lethal levels of stress." - scan_desc = "severe monophobia" + scan_desc = "monophobia" gain_text = "" lose_text = "You feel like you could be safe on your own." var/stress = 0 @@ -168,7 +168,7 @@ if(stress > 10 && (prob(5))) stress_reaction() else - stress -= 4 + stress = max(stress - 4, 0) /datum/brain_trauma/severe/monophobia/proc/check_alone() if(HAS_TRAIT(owner, TRAIT_BLIND)) diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm index d9e6f00643..b52c7d391c 100644 --- a/code/datums/brain_damage/special.dm +++ b/code/datums/brain_damage/special.dm @@ -22,6 +22,14 @@ 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) @@ -36,7 +44,7 @@ else message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral") - playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 200, 1, 5) + playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 200, TRUE, 5) voice_of_god(message, owner, list("colossus","yell"), 2.5, include_owner, FALSE) /datum/brain_trauma/special/bluespace_prophet @@ -134,7 +142,101 @@ /datum/brain_trauma/special/psychotic_brawling/bath_salts name = "Chemical Violent Psychosis" - random_gain = FALSE + clonable = FALSE + +/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 = "You suddenly stop feeling pain." + lose_text = "You realize you can feel pain again." + +/datum/brain_trauma/special/tenacity/on_gain() + ADD_TRAIT(owner, TRAIT_NOSOFTCRIT, TRAUMA_TRAIT) + ADD_TRAIT(owner, TRAIT_NOHARDCRIT, TRAUMA_TRAIT) + ..() + +/datum/brain_trauma/special/tenacity/on_lose() + REMOVE_TRAIT(owner, TRAIT_NOSOFTCRIT, TRAUMA_TRAIT) + REMOVE_TRAIT(owner, TRAIT_NOHARDCRIT, 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 = "You feel dead inside." + lose_text = "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/cease_whispering), rand(50, 300)) + +/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 = "You feel less real." + lose_text = "You feel more substantial again." + var/obj/effect/abstract/sync_holder/veil/veil + var/next_crisis = 0 + +/datum/brain_trauma/special/existential_crisis/on_life() + ..() + if(!veil && world.time > next_crisis && prob(3)) + 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(50, 450) + veil = new(owner.drop_location()) + to_chat(owner, "[pick("You stop thinking for a moment. Therefore you are not.",\ + "To be or not to be...",\ + "Why exist?",\ + "You stop keeping it real.",\ + "Your grip on existence slips.",\ + "Do you even exist?",\ + "You simply fade away.")]") + owner.forceMove(veil) + SEND_SIGNAL(owner, COMSIG_MOVABLE_SECLUDED_LOCATION) + for(var/thing in owner) + var/atom/movable/AM = thing + SEND_SIGNAL(AM, COMSIG_MOVABLE_SECLUDED_LOCATION) + next_crisis = world.time + 600 + addtimer(CALLBACK(src, .proc/fade_in), duration) + +/datum/brain_trauma/special/existential_crisis/proc/fade_in() + QDEL_NULL(veil) + to_chat(owner, "You fade back into reality.") + next_crisis = world.time + 600 + +//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" @@ -142,6 +244,7 @@ scan_desc = "criminal mind" gain_text = "Justice is coming for you." lose_text = "You were absolved for your crimes." + clonable = FALSE random_gain = FALSE var/obj/effect/hallucination/simple/securitron/beepsky @@ -201,4 +304,4 @@ /obj/effect/hallucination/simple/securitron/Destroy() STOP_PROCESSING(SSfastprocess,src) - return ..() \ No newline at end of file + return ..() diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm index 653b8a98c0..8766596191 100644 --- a/code/datums/brain_damage/split_personality.dm +++ b/code/datums/brain_damage/split_personality.dm @@ -13,6 +13,10 @@ var/mob/living/split_personality/owner_backseat /datum/brain_trauma/severe/split_personality/on_gain() + var/mob/living/M = owner + if(M.stat == DEAD) //No use assigning people to a corpse + qdel(src) + return ..() make_backseats() get_ghost() @@ -23,7 +27,7 @@ /datum/brain_trauma/severe/split_personality/proc/get_ghost() set waitfor = FALSE - var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", ROLE_PAI, null, null, 75, stranger_backseat) + var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", ROLE_PAI, null, null, 75, stranger_backseat, POLL_IGNORE_SPLITPERSONALITY) if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) stranger_backseat.key = C.key @@ -191,13 +195,13 @@ /datum/brain_trauma/severe/split_personality/brainwashing/on_life() return //no random switching -/datum/brain_trauma/severe/split_personality/brainwashing/on_hear(message, speaker, message_language, raw_message, radio_freq) - if(HAS_TRAIT(owner, TRAIT_DEAF) || owner == speaker) - return message +/datum/brain_trauma/severe/split_personality/brainwashing/handle_hearing(datum/source, list/hearing_args) + if(HAS_TRAIT(owner, TRAIT_DEAF) || owner == hearing_args[HEARING_SPEAKER]) + return + var/message = hearing_args[HEARING_MESSAGE] if(findtext(message, codeword)) - message = replacetext(message, codeword, "[codeword]") + hearing_args[HEARING_MESSAGE] = replacetext(message, codeword, "[codeword]") addtimer(CALLBACK(src, /datum/brain_trauma/severe/split_personality.proc/switch_personalities), 10) - return message /datum/brain_trauma/severe/split_personality/brainwashing/handle_speech(datum/source, list/speech_args) if(findtext(speech_args[SPEECH_MESSAGE], codeword)) diff --git a/code/datums/components/stationloving.dm b/code/datums/components/stationloving.dm index bbcb0d88a6..91928656e1 100644 --- a/code/datums/components/stationloving.dm +++ b/code/datums/components/stationloving.dm @@ -8,6 +8,7 @@ if(!ismovableatom(parent)) return COMPONENT_INCOMPATIBLE RegisterSignal(parent, list(COMSIG_MOVABLE_Z_CHANGED), .proc/check_in_bounds) + RegisterSignal(parent, list(COMSIG_MOVABLE_SECLUDED_LOCATION), .proc/relocate) RegisterSignal(parent, list(COMSIG_PARENT_PREQDELETED), .proc/check_deletion) RegisterSignal(parent, list(COMSIG_ITEM_IMBUE_SOUL), .proc/check_soul_imbue) src.inform_admins = inform_admins @@ -32,6 +33,7 @@ var/atom/movable/AM = parent AM.forceMove(targetturf) + to_chat(get(parent, /mob), "You can't help but feel that you just lost something back there...") // move the disc, so ghosts remain orbiting it even if it's "destroyed" return targetturf @@ -40,7 +42,6 @@ return else var/turf/currentturf = get_turf(src) - to_chat(get(parent, /mob), "You can't help but feel that you just lost something back there...") var/turf/targetturf = relocate() log_game("[parent] has been moved out of bounds in [loc_name(currentturf)]. Moving it to [loc_name(targetturf)].") if(inform_admins) diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index e930c77c36..7eb7d6b220 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -534,8 +534,7 @@ datum/status_effect/pacify tick_interval = 10 examine_text = "SUBJECTPRONOUN seems slow and unfocused." var/stun = TRUE - var/triggered = FALSE - alert_type = null + alert_type = /obj/screen/alert/status_effect/trance /obj/screen/alert/status_effect/trance name = "Trance" @@ -543,17 +542,6 @@ datum/status_effect/pacify icon_state = "high" /datum/status_effect/trance/tick() - if(HAS_TRAIT(owner, "hypnotherapy")) - if(triggered == TRUE) - UnregisterSignal(owner, COMSIG_MOVABLE_HEAR) - RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/hypnotize) - ADD_TRAIT(owner, TRAIT_MUTE, "trance") - if(!owner.has_quirk(/datum/quirk/monochromatic)) - owner.add_client_colour(/datum/client_colour/monochrome) - to_chat(owner, "[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...")]") - triggered = FALSE - else - return if(stun) owner.Stun(60, TRUE, TRUE) owner.dizziness = 20 @@ -561,47 +549,88 @@ datum/status_effect/pacify /datum/status_effect/trance/on_apply() if(!iscarbon(owner)) return FALSE - if(HAS_TRAIT(owner, "hypnotherapy")) - RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/listen) - return TRUE - alert_type = /obj/screen/alert/status_effect/trance RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/hypnotize) ADD_TRAIT(owner, TRAIT_MUTE, "trance") - if(!owner.has_quirk(/datum/quirk/monochromatic)) - owner.add_client_colour(/datum/client_colour/monochrome) + owner.add_client_colour(/datum/client_colour/monochrome/trance) 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, source_quirk = FALSE)//hypnoquirk makes no visible message, prevents self antag messages, and places phrase below objectives. +/datum/status_effect/trance/on_creation(mob/living/new_owner, _duration, _stun = TRUE) duration = _duration stun = _stun - if(source_quirk == FALSE && HAS_TRAIT(owner, "hypnotherapy")) - REMOVE_TRAIT(owner, "hypnotherapy", ROUNDSTART_TRAIT) return ..() /datum/status_effect/trance/on_remove() UnregisterSignal(owner, COMSIG_MOVABLE_HEAR) REMOVE_TRAIT(owner, TRAIT_MUTE, "trance") owner.dizziness = 0 - if(!owner.has_quirk(/datum/quirk/monochromatic)) - owner.remove_client_colour(/datum/client_colour/monochrome) + owner.remove_client_colour(/datum/client_colour/monochrome/trance) to_chat(owner, "You snap out of your trance!") -/datum/status_effect/trance/proc/listen(datum/source, message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) - to_chat(owner, "[speaker] accidentally sets off your implanted trigger, sending you into a hypnotic daze!") - triggered = TRUE - -/datum/status_effect/trance/proc/hypnotize(datum/source, message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) +/datum/status_effect/trance/proc/hypnotize(datum/source, list/hearing_args) if(!owner.can_hear()) return - if(speaker == owner) + if(hearing_args[HEARING_SPEAKER] == owner) return var/mob/living/carbon/C = owner C.cure_trauma_type(/datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY) //clear previous hypnosis - if(HAS_TRAIT(C, "hypnotherapy")) - addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, raw_message, TRUE), 10) - else - addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, raw_message), 10) + addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hearing_args[HEARING_RAW_MESSAGE]), 10) addtimer(CALLBACK(C, /mob/living.proc/Stun, 60, TRUE, TRUE), 15) //Take some time to think about it qdel(src) + +/datum/status_effect/spasms + id = "spasms" + status_type = STATUS_EFFECT_MULTIPLE + alert_type = null + +/datum/status_effect/spasms/tick() + if(prob(15)) + switch(rand(1,5)) + if(1) + if((!owner.lying && !owner.buckled) && isturf(owner.loc)) + to_chat(owner, "Your leg spasms!") + step(owner, pick(GLOB.cardinals)) + if(2) + if(owner.incapacitated()) + return + var/obj/item/I = owner.get_active_held_item() + if(I) + to_chat(owner, "Your fingers spasm!") + owner.log_message("used [I] due to a Muscle Spasm", LOG_ATTACK) + I.attack_self(owner) + if(3) + var/prev_intent = owner.a_intent + owner.a_intent = INTENT_HARM + + var/range = 1 + if(istype(owner.get_active_held_item(), /obj/item/gun)) //get targets to shoot at + range = 7 + + var/list/mob/living/targets = list() + for(var/mob/M in oview(owner, range)) + if(isliving(M)) + targets += M + if(LAZYLEN(targets)) + to_chat(owner, "Your arm spasms!") + owner.log_message(" attacked someone due to a Muscle Spasm", LOG_ATTACK) //the following attack will log itself + owner.ClickOn(pick(targets)) + owner.a_intent = prev_intent + if(4) + var/prev_intent = owner.a_intent + owner.a_intent = INTENT_HARM + to_chat(owner, "Your arm spasms!") + owner.log_message("attacked [owner.p_them()]self to a Muscle Spasm", LOG_ATTACK) + owner.ClickOn(owner) + owner.a_intent = prev_intent + if(5) + if(owner.incapacitated()) + return + var/obj/item/I = owner.get_active_held_item() + var/list/turf/targets = list() + for(var/turf/T in oview(owner, 3)) + targets += T + if(LAZYLEN(targets) && I) + to_chat(owner, "Your arm spasms!") + owner.log_message("threw [I] due to a Muscle Spasm", LOG_ATTACK) + owner.throw_item(pick(targets)) \ No newline at end of file diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 655863e0e0..cb2b4174b5 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -69,3 +69,17 @@ /datum/status_effect/in_love/tick() if(date) new /obj/effect/temp_visual/love_heart/invisible(get_turf(date.loc), owner) + +/datum/status_effect/throat_soothed + id = "throat_soothed" + duration = 60 SECONDS + status_type = STATUS_EFFECT_REFRESH + alert_type = null + +/datum/status_effect/throat_soothed/on_apply() + . = ..() + ADD_TRAIT(owner, TRAIT_SOOTHED_THROAT, "[STATUS_EFFECT_TRAIT]_[id]") + +/datum/status_effect/throat_soothed/on_remove() + . = ..() + REMOVE_TRAIT(owner, TRAIT_SOOTHED_THROAT, "[STATUS_EFFECT_TRAIT]_[id]") \ No newline at end of file diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm index c8bcd831e2..6684065cc8 100644 --- a/code/datums/status_effects/status_effect.dm +++ b/code/datums/status_effects/status_effect.dm @@ -63,6 +63,12 @@ owner = null qdel(src) +/datum/status_effect/proc/refresh() + var/original_duration = initial(duration) + if(original_duration == -1) + return + duration = world.time + original_duration + //clickdelay/nextmove modifiers! /datum/status_effect/proc/nextmove_modifier() return 1 @@ -91,6 +97,9 @@ if(S.id == initial(S1.id) && S.status_type) if(S.status_type == STATUS_EFFECT_REPLACE) S.be_replaced() + else if(S.status_type == STATUS_EFFECT_REFRESH) + S.refresh() + return else return var/list/arguments = args.Copy() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 7c9dc3f4fe..78a1869663 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -538,7 +538,7 @@ var/atom/L = loc if(!L) return null - return L.AllowDrop() ? L : get_turf(L) + return L.AllowDrop() ? L : L.drop_location() /atom/Entered(atom/movable/AM, atom/oldLoc) SEND_SIGNAL(src, COMSIG_ATOM_ENTERED, AM, oldLoc) diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 7d02d9d383..fb044b1ce7 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -313,6 +313,11 @@ randomdir = 0 duration = 6 +/obj/effect/temp_visual/desynchronizer + name = "desynchronizer field" + icon_state = "chronofield" + duration = 3 + /obj/effect/temp_visual/impact_effect icon_state = "impact_bullet" duration = 5 diff --git a/code/game/objects/items/devices/desynchronizer.dm b/code/game/objects/items/devices/desynchronizer.dm new file mode 100644 index 0000000000..4a6e2d5a46 --- /dev/null +++ b/code/game/objects/items/devices/desynchronizer.dm @@ -0,0 +1,87 @@ +/obj/item/desynchronizer + name = "desynchronizer" + desc = "An experimental device that can temporarily desynchronize the user from spacetime, effectively making them disappear while it's active." + icon = 'icons/obj/device.dmi' + icon_state = "desynchronizer" + item_state = "electronic" + w_class = WEIGHT_CLASS_SMALL + item_flags = NOBLUDGEON + lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' + materials = list(MAT_METAL = 250, MAT_GLASS = 500) + var/max_duration = 3000 + var/duration = 300 + var/last_use = 0 + var/next_use = 0 + var/obj/effect/abstract/sync_holder/sync_holder + +/obj/item/desynchronizer/attack_self(mob/living/user) + if(world.time < next_use) + to_chat(user, "[src] is still recharging.") + return + if(!sync_holder) + desync(user) + else + resync() + +/obj/item/desynchronizer/examine(mob/user) + . = ..() + if(world.time < next_use) + . += "Time left to recharge: [DisplayTimeText(next_use - world.time)]" + . += "Alt-click to customize the duration. Current duration: [DisplayTimeText(duration)]." + . += "Can be used again to interrupt the effect early. The recharge time is the same as the time spent in desync." + +/obj/item/desynchronizer/AltClick(mob/living/user) + if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) + return + var/new_duration = input(user, "Set the duration (5-300):", "Desynchronizer", duration / 10) as null|num + if(new_duration) + new_duration = new_duration SECONDS + new_duration = CLAMP(new_duration, 50, max_duration) + duration = new_duration + to_chat(user, "You set the duration to [DisplayTimeText(duration)].") + +/obj/item/desynchronizer/proc/desync(mob/living/user) + if(sync_holder) + return + sync_holder = new(drop_location()) + new /obj/effect/temp_visual/desynchronizer(drop_location()) + to_chat(user, "You activate [src], desynchronizing yourself from the present. You can still see your surroundings, but you feel eerily dissociated from reality.") + user.forceMove(sync_holder) + SEND_SIGNAL(user, COMSIG_MOVABLE_SECLUDED_LOCATION) + for(var/thing in user) + var/atom/movable/AM = thing + SEND_SIGNAL(AM, COMSIG_MOVABLE_SECLUDED_LOCATION) + last_use = world.time + icon_state = "desynchronizer-on" + addtimer(CALLBACK(src, .proc/resync), duration) + +/obj/item/desynchronizer/proc/resync() + new /obj/effect/temp_visual/desynchronizer(sync_holder.drop_location()) + QDEL_NULL(sync_holder) + icon_state = initial(icon_state) + next_use = world.time + (world.time - last_use) // Could be 2*world.time-last_use but that would just be confusing + +/obj/item/desynchronizer/Destroy() + resync() + return ..() + +/obj/effect/abstract/sync_holder + name = "desyncronized pocket" + desc = "A pocket in spacetime, keeping the user a fraction of a second in the future." + icon = null + icon_state = null + alpha = 0 + invisibility = INVISIBILITY_ABSTRACT + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + anchored = TRUE + resistance_flags = INDESTRUCTIBLE + +/obj/effect/abstract/sync_holder/Destroy() + for(var/I in contents) + var/atom/movable/AM = I + AM.forceMove(drop_location()) + return ..() + +/obj/effect/abstract/sync_holder/AllowDrop() + return TRUE //no dropping spaghetti out of your spacetime pocket \ No newline at end of file diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index e43c2f6254..933c32917c 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -49,6 +49,12 @@ A.malf_picker.remove_malf_verbs(A) qdel(A.malf_picker) +/datum/antagonist/traitor/proc/handle_hearing(datum/source, list/hearing_args) + var/message = hearing_args[HEARING_MESSAGE] + message = GLOB.syndicate_code_phrase_regex.Replace(message, "$1") + message = GLOB.syndicate_code_response_regex.Replace(message, "$1") + hearing_args[HEARING_MESSAGE] = message + SSticker.mode.traitors -= owner if(!silent && owner.current) to_chat(owner.current," You are no longer the [special_role]! ") diff --git a/code/modules/client/client_colour.dm b/code/modules/client/client_colour.dm index f1477fb4d2..22b15ea868 100644 --- a/code/modules/client/client_colour.dm +++ b/code/modules/client/client_colour.dm @@ -111,3 +111,6 @@ /datum/client_colour/monochrome colour = list(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0)) priority = INFINITY //we can't see colors anyway! + +/datum/client_colour/monochrome/trance + priority = 1 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/say.dm b/code/modules/mob/living/carbon/say.dm index 452c8f8b78..30c962f9a5 100644 --- a/code/modules/mob/living/carbon/say.dm +++ b/code/modules/mob/living/carbon/say.dm @@ -17,18 +17,4 @@ if(T) . = T.could_speak_in_language(dt) else - . = initial(dt.flags) & TONGUELESS_SPEECH - -/mob/living/carbon/hear_intercept(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) - . = ..() - if(!client) - return - for(var/T in get_traumas()) - var/datum/brain_trauma/trauma = T - message = trauma.on_hear(message, speaker, message_language, raw_message, radio_freq) - - if (src.mind.has_antag_datum(/datum/antagonist/traitor)) - message = GLOB.syndicate_code_phrase_regex.Replace(message, "$1") - message = GLOB.syndicate_code_response_regex.Replace(message, "$1") - - return message + . = initial(dt.flags) & TONGUELESS_SPEECH \ No newline at end of file diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 25d8c4d44c..c5c81e74ce 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -58,9 +58,9 @@ message = "coughs!" emote_type = EMOTE_AUDIBLE -/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE) +/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional) . = ..() - if(user.reagents && (user.reagents.get_reagent("menthol") || user.reagents.get_reagent("peppermint_patty"))) + if(HAS_TRAIT(user, TRAIT_SOOTHED_THROAT)) return FALSE /datum/emote/living/dance diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 88073ca5f3..6d7521c7a5 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -1741,6 +1741,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_desc = "A boozy minty hot cocoa that warms your belly on a cold night." /datum/reagent/consumable/ethanol/peppermint_patty/on_mob_life(mob/living/carbon/M) + M.apply_status_effect(/datum/status_effect/throat_soothed) M.adjust_bodytemperature(5 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL) ..() diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index dd51ce2bc7..ed90b975ae 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -785,6 +785,10 @@ glass_name = "glass of menthol" glass_desc = "Tastes naturally minty, and imparts a very mild numbing sensation." +/datum/reagent/consumable/menthol/on_mob_life(mob/living/L) + L.apply_status_effect(/datum/status_effect/throat_soothed) + ..() + /datum/reagent/consumable/grenadine name = "Grenadine" id = "grenadine" diff --git a/code/modules/research/designs/bluespace_designs.dm b/code/modules/research/designs/bluespace_designs.dm index c9d11a5a3e..ec4309b69e 100644 --- a/code/modules/research/designs/bluespace_designs.dm +++ b/code/modules/research/designs/bluespace_designs.dm @@ -65,6 +65,16 @@ category = list("Bluespace Designs") departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_CARGO +/datum/design/desynchronizer + name = "Desynchronizer" + desc = "A device that can desynchronize the user from spacetime." + id = "desynchronizer" + build_type = PROTOLATHE + materials = list(MAT_METAL = 1000, MAT_GLASS = 500, MAT_SILVER = 1500, MAT_BLUESPACE = 1000) + build_path = /obj/item/desynchronizer + category = list("Bluespace Designs") + departmental_flags = DEPARTMENTAL_FLAG_SCIENCE + /datum/design/miningsatchel_holding name = "Mining Satchel of Holding" desc = "A mining satchel that can hold an infinite amount of ores." diff --git a/code/modules/research/nanites/nanite_programs.dm b/code/modules/research/nanites/nanite_programs.dm index a06311f26f..2a6563fe52 100644 --- a/code/modules/research/nanites/nanite_programs.dm +++ b/code/modules/research/nanites/nanite_programs.dm @@ -208,9 +208,6 @@ datum/nanite_program/proc/on_mob_remove() /datum/nanite_program/proc/on_death() return -/datum/nanite_program/proc/on_hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) - return - /datum/nanite_program/proc/software_error(type) if(!type) type = rand(1,5) diff --git a/code/modules/research/nanites/nanite_programs/sensor.dm b/code/modules/research/nanites/nanite_programs/sensor.dm index d494ec8cdf..3ca634c708 100644 --- a/code/modules/research/nanites/nanite_programs/sensor.dm +++ b/code/modules/research/nanites/nanite_programs/sensor.dm @@ -378,15 +378,12 @@ target.sentence = sentence target.inclusive = inclusive -/datum/nanite_program/sensor/voice/on_hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) +/datum/nanite_program/sensor/voice/proc/on_hear(datum/source, list/hearing_args) if(!sentence) return - //To make it not case sensitive - var/low_message = lowertext(raw_message) - var/low_sentence = lowertext(sentence) if(inclusive) - if(findtext(low_message, low_sentence)) + if(findtextEx(hearing_args[HEARING_RAW_MESSAGE], sentence)) send_code() else - if(low_message == low_sentence) + if(hearing_args[HEARING_RAW_MESSAGE] == sentence) send_code() \ No newline at end of file diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 038a41b3cd..d7b652fb41 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -294,6 +294,15 @@ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 5000 +/datum/techweb_node/unregulated_bluespace + id = "unregulated_bluespace" + display_name = "Unregulated Bluespace Research" + description = "Bluespace technology using unstable or unbalanced procedures, prone to damaging the fabric of bluespace. Outlawed by galactic conventions." + prereq_ids = list("bluespace_travel", "syndicate_basic") + design_ids = list("desynchronizer") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + export_price = 2500 + /////////////////////////plasma tech///////////////////////// /datum/techweb_node/basic_plasma id = "basic_plasma" diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index 8142e034984437b14af803c2833f0a91b165c35c..d833966effcb6c2cce09b7e19a3b2590afb65bb9 100644 GIT binary patch delta 20958 zcmV)vK$XABv&pQihDpzIg}1V^p1Ie79a1 z&#BoroAs(==<)IQ3pCQNf*6G~{XPlFjQtQGOVh~oyG}CGD5E~gu#F7cf6A~c8Fnqh zb~5ZnhTXo7ZPzP<0Zz@nxovM>Xg*anH|@AKWktjA9!zCW;Xwk=j^^iJ{KKj_vvU+O@GqER%UAud( zs9RoBFm=ak3TDReljX14f2)b4gsc+ARBs9fJ1AksAe;5dQBDKpX5Vag?dPdO3>Rw! zMVD=%;S!JaVqkwjW6;pyC+gX(C-{(08bhd(9n_Q>QOu8V@At9pF}CW(1@~op{YO5fkwG!C-6ec_C9(QfnQgB{%44| zT$dP;L|r&iRv4*Rf2TApOmm`*K6CwypHt6{-U99HbUmjXfFYccub%}2jmV18&Ydp1 z%M#o6>AJ|dL^O{>L49VQz;$O$;QE$58-9}mL!;_ZFlr_ryru=OJ1GM{_-F-Ssh`*4 zWiyfLi++QF&&oI0_pDuP-m`MCbsr$w0$ks^5#cBpiAMC+f8~IJxoGssDa#Nu&a|Z| z%;2+21L}HUuN^T2l`{Bx#$CYVMD9J4|M_BY^J*uZ_%!$)6@!ll8k6%l_g38bG6>H%PipFgU0{4}ux!G(`GOb9~=?{c+daeZOD-1={p15NX_H>i_^C z07*naRCt{1gGd9nNCN?aPk-a=x~jYX@7|}}J~MZE(aflqkz`d{a+lnVEn~nI#>6C{ zBoO`~328h)8YF=b@&E}02q6JNs5Zq0cgw;}BinM3RYrBB>6&(DZol`Ov)A+DYGhU0 z5b}`E|MBn5x%ZrX&f0UOv)W$!w+`gf3^(RT6~-Z-Bbyf_9HTQ)&wt_zyXe`r=Y$bB z+53n8S_H86p-;j^mCyN9ie!8Hi6~(HMHj)uMLc`;ht7Hb+2o%!0svUNc=1^uaH2Hy z9M@)WvhqLq{HsL(#!1IkFK8zf3@LkFx}hilukluC>N=2$4+_qVSGd4SxtS1vEg!{}znaL8KZ`ym!S59Edlf`Ba-oUg$<)mcwdiJaiFB0$d)9IBu(f4dlxg+lbW_RVs&+l9Xv?G{Q2Z2CYTx=r0u-(;Gs{_Q};*bmhoC5fN;3N%A882NG6kK zJmhRf;MF|;neVR}0pt~j2h;4>pW&_VSi`TqsJXF95LVs`mgeIXMl$;X%WW z{eS6K9KU9vB9&MC>ko!wyuvgAb@o*V3TQi>kmXi5}ePq~}z5$<{Rr zlHiO9y7(fb-^PniZ(%|EBy-w5az&TtceV4})*;^edrgdQ-pPtX9jIzScPmDJAb&Jp z2g*`JR*F4&MCZi~pa$|r`5cZ;edh<>12_Mv*ATG~%SHJ>ZbW<19>66EVIqP)zIC-n=d9zEzxYu^oaJ*HT&-rx;DFn1P`x54UV{D0^e8%>f= zWUpb@-+zHshY#|u`Ehj32&P(4DX8rNe-F^Fc<~X1JI@`7w%{)5C^y&*XbwU78F%al zPcr+qkCr>?mIpF9p!3J}>5M%aw{xB!tqx1&9e4r!x}}JR2Nc>mu%QONroxMh`zrK6Yb#cmNQby76U!Ud)DBnkw4JFq?djW42;h(ZuE`Q*G z^_NU<5@mUR|MWlVw|~sqWLh%ArgV7No{m4G;5`C;5Y%^|{2151cn_Z%*+k9C0$&?k zPk6v%QGAegmBx-AW%)Y+f#Md>b-)<3TmbdOd~525Qm9=@%6EMhF;N=g}p0Sfq-UP6i(0kC`ASAXc?fJS+rDf#?#P#cv}x@>P^2JU7 zm_+60Eca@?w3u|Cq7@-}A^4$LNZT!ZVqYJl{wypd+%Ru9cRs(8^TWF!Iu}1Rmt8;G z$Eqoz?IIzt1uj;syFk%D=zG~8YeThXjrRIkZ<~y(OMhv&>U}CKrRV`24hoS&)Xlxt zYio++8n*vOdB6z(Utz_CV%wWZwEZF1z5jQa+v<@IT$*&6E9qg`l>;CvAYoI^2rP!w zU5a8Y&Y!C2Pk$?vEvO&`HP;dk{TtPxEc4Vj*?frUi4X@f&Aj!3225_6>1LsR0wN2*KLV@< z`w%1+OK3P1FzTwTHKx?UJbEG(*iEHZ=K`8p2dMk?O#m#vbso)j6UBmHiV?_z&cq1o zY9^;9dAO&-&-ML3`REz>fB5+$fW;G^rg6an4u3uQBrRQCrzriCBY)x7^?46a(&&i5Z3s3`O1 zFTAYK0j9oMIW~U*c+ZJ7f*t$QuW9^M>)P4(qjNW1IRC5B?fY(i?3{GZGf3C1jh)R1 zSbu)Ip|6Lft!XS5tS>L)1dHf#+>yR%*Pot71p&}}-+k+QZoav@F62;W6y?I1ymK?2 z{@izb9Du{$__J4=Y6VJRyEZih)C2(!+BTOT=O0r0ypPZ-1M7a%tA6~8;j7oZt=Q4} zUa6A3z@-o$2446aEW4SGYd3Nr`vrcur+#=-)x$7ngAmCB z4=auhf;-D9rH)FTtT7kgRBEZZO={Lo0WZo8Tq6zx>WkNYrhMCv{y6r%n{Li7$zQC? z#iO7~Li$OlyP^c~7nolQ^cjxm1}xt&Kbb+Ux(YS%H$+}MKxRm;AZ+7iOQ_Up1}Vt3Fnq`{4T(EQF@t2KD$F^3FFn<>}Up5<+bzm%o*K`?&zx*&wwUC@G_+vm`$Yd0?T_$SzN=0jYt28XR z!R0D^$8EkRnkv-~bO=h=+jwEHII&EHbK_Q_s7*{I1?7NJKI(zrr~AEOR7;HC{z^4F zhg)5ClAP~FnP!N(t``uO@_IiDxd*mz?6YmtA}2w-q>@(kr)K7R+v+m1Cmz^pp) zJ(oLocICwL&tV7}tJU!ZTlnUK%lWly&h+L1zWI$W0i3c%@LI+n9!yi=29hvv)=oAv z%$;zY&GR&z+z;S%BcS?^vxpuXVqIH?Y6U;~#)WJ<9tmuG;o4oCWfA(}TW;xIR4QTH zHsi&BGKQ0RS<{n~r++L0XS1)ZhxF0sDjrVY*nlDBX%-v9)xh1?UfX^70}rfMQ|7x_ zPwyKZcPCU-cl;SkBJvctj6g_truO6Mz;-@_!zL%}0*d56@ofB`&_I zkW(%yzR-jM3;2m5)F8-DEYz)C5bl8`DH?T}XGfY?d+iOVSOJFbL)vUg-G+n(y}J}^ z-zIoFp&W+(eeR?`L=c2Tt@>ksu2sNdRDmN))ezcmlF0B*>pcIMDn?eDM6pa@R|BJp z!jppC+>1~NgAn`-M!o>{G=E%tL%?$brh3(Ti!ITjxYniA z1oxTD^nHYDvV29_RrArDy6MQB;jSvh(ERgD^|1+D<)cW0)PrQI(ZipE#!sNKgXmzI z<#r!x{00~}1{*d}aNopK@8_XTNW>sn1zsFxxll^0aQw!=HAj%TsBvd6Av}4Ey5wvS zPf&|tqJKws_|qz9H)ByNR;~wRjzSwj#CNw$U(EDKcm>PuCE?w}RFw^lU$zw+BCY$4-`|)Twh^sGIhPQlr#a(EU4_)zv4i zw{&$;&gah>1-xc9&{s&!?_*%)3JH8 zYWVIqb^yoII>(jyHy>OMz<0l~gIhPw;^FNTZ~oSe?XNn1-mDsS?4RP&_074T>=+K8 zV}A-Kb^_0QJ{`en{Qyoj0!v%c_&tLlzXDMJ03ZNKL_t)X%pG*23)A2J^~g)Ne64V< zoxmR$ALl=7Ygur-u}fH9ma!d+1?4iwhF{*i_R<%AAK;X8LudJIw_~x_3+T{3#UQ{2 zcGxx}BD5b*(W%w``dFip)IY}js%TkgLVq%MQdO@H!euwT@G7q(Z$hBJ`#dMK_XXBgd&Q>?H2joBB~F93u<9*gbT832yJ@=nVv+s2AWi5!MFg7Kz$cD z2F#=obb`DfCfJAc@3B&LM3jG2>3@z@61G|qS;^lv+ChkCA>LrzsR>%{fOFr!$RTv|%ugO=igp!($Zba! z|HIq+V>3qJY~$z6s$unlI7;+u>KgV++&!mr{=>^gzz!)cIE_1KSzCrTISO^xZ$^@f z&wO6jh7H|5(3Q_KYJXW&8G~07hUrRxvU#=PdzYS1?O8T>os0umY+ilp0@PkFV5t+^ zKB5%WA)BULks4#TIta)Yi_~9nMYsP|b6)13tp3*3;&^4ntU;Hg{_e1Edr~*b{-g-mGfl!mMs7q(9q@PT5<63V(;Q&Q2i!f5g)9X~D?AL{P z#Ud(&u98b+drrxO z5>^p_2zxWB%?6?9{G^HTJ_t@rDa}=w9IQP6KoQKf}p;wxY`v4 z@BILdClvNU*@s}_9hf$77VIWI@GZP?C@)a7UmP zb4oegE7#$lsm!71tOgom!F%58aKnp-!{ilwHe&vH+kEl*6p>P}#w z(tpwGICE#}EZ0wu0A|qru5PR^FC*&9DcnIb{RCz@i?y^*p3-A@&(^K$t!uCCUREsf zXf#Ryq%$7%R8lydt1AX)=6Ej5Z2p=_`+V0ET0`;e(n%H9H#63 z``2H#|H@^(L;72*-)-h(wp!(bPg!H(<$n^&ACu_OzZE*Khx6YDb*;dcpt%90QK80x zf)JZfMBfdE_CP~><)v)6NOJ?E$Av=<}82}fW2 ze*ddD@>Z5e*Z9@+3@^14eqNa)V|MmUUo0#k018mM{dn(yp90rF!w0GCQuYKD1%K{S zn4G`?80iK3cF;v=voXvzF>4`8Wq<%O_o*Uf@egLL%&JYn?^4g5R;xr7xMgeKQ_iuu z<9>ar%_@alKN(C`D1#QP7pfeEGQc*lYXs&B>;daZ2wkE`Gy;PV%n_`p;=rRYZ;_Hv zNbE(In>w^%vR4aNg#_uPA|56`i@A^8nGkAA`GRapIstZj(bD0cs+;@TU9*u}uJAb)MDBKrua zPH+W=4p-)%9f!sXh1wLN55RR@%H{G2 zBXD|TaPas9X7EI@$R!tF{BuVDGhX-e`|~+)PT{;fGO9T;nm;G2=6^48&&k-cY3nlA zQ71ZioegJ;08ZThwyzg{^40a&4rj24&U6<0@xyiJ!|=e#_t~DugNXzKw$0K)frv4T zy0PusgWS3q#s0nL^jRdHij&7Qxbf}U2%;4lp{ZO(v?i}LTVgS8&Sn_{WFMb$#n(eS zt+bsLCm9Vwle^S(_kTUneJ!)|tHuJDV+=>PDxQ8?vGlD%A*aawJ2*Bhd$W*;L-9$) zXp3UvZm?o7|1x*bWP;Gp4m-VeX|Y{p3^iBgy2{PUJia3|e5oo%aahQHwW<6!?DOBL z+olfKnZ~SVU-iD?95ncOC`?1p2vHw$&5-n9>Il5}WzFU9G=F4c@Y4N?=4#m4r)XR& z%xe^M0uKGqo@@*S@zM**Z@k9D$w9G01ry`iTeUD~VW+y2Yd}vKRrdv!O#eWp4?SlO zH`NE#qrJ|M^1ar^1<=^62qKE?5yNO&G4_O_`k>JKMxm-jAxi`iMajUn&uT9GoRDbK z87nPuatd}DaDTvy;^k9VF_c>{Die!JoO;TkybdvKpaBe+s!0jCbwF8BiV5f4AedIr zVL^Hng*>FofTKv%8=NRyw%72JuV~7)V(p}mI&7s5-EWU(#&kJSZ=B*>%Ha?Z`hcTA z5~Nl^SU#)r{>Vc;v2^)Ms;A2-xe;*P1{JAU=GCQp6@Tq(gr9BI%vmQK=~c|?gwY8o zk3sEzXo*5NDx@w~1ocpNA&63_pTLl>(i1~gZuwfT1qG6Y=^yA4(V;q(hV-oplZVd5 zhO3ranSZ9Xpn7`3D%$HrM^_j-`n0m9daZ)VpyM|g`Hjlw zv&`e?jsQ+h1G&e~o$l@Daygz@dVEdwcn6$I!hhkPD*_nJ!or5v&g}V%Vx}eJ+2mhx z&xT$5Zhq{H{=GXkK5|N*-*X}GgeTsyjp;joBXYA1C-)P`rBq~5YnpdD`wI`BB!BlC z-q7vU*W-8|Mc*f@H6_bJjA7i0ZCA!n0xS_c5o(p9WN9!$Ac9s3F$QB-jc85G zn19L!Fu)P;EsK;=j4MS)5b(2b7 zExMdS?P7`aYhwpAQ6Z?g)kFnPz?907EX!z3BTzhj@DPcUpA15f> zg`bP-^2lMGO&`uNYK~SwrmVfAgJJm8fsDFyo zsKV4?L{Es0)`%0e(QOMP@I5CL=?H9zNyw`f_rQ;w@j07=WVBPj4ERBr|p$2S{fCDlBd%xj~gxbWe zn`5F*iQXP_T#D^iVvc(CpLVvp@T(wXI%YIE|!hPZ#E`(D4vv`G3<YY>!iqbBmgfJ@j*|&8dmd6*cLCwNr_JCYmCE);Mw1OexNe1s zFIg7E7}3}r)@VUV^ymR+Bv}(g!?S|gVu0QFCKEf_uczvw5>W?(s5gYk41eiTB#FCt ztru5MDExUM>F0G>w~AO7Q@!(B){o9x=r?uTflP-?F=824jw&AgZs^d$1ztn^JVG@K z(C4+NV*P9rRdJu44Oj>)0eioAI)a{j$|}t=l3+R1HU`mB0l)V< z&e*^+R<85XpuXcGKc@NxNq?Mb0A5Q+uIx;QuQm6asy|M2{`&d2czz!F&r(?jxOM(k zauXBeCMIa<>N-&p3b1w6yI*k*ziqi$dl!t+`o6@3)k+N>E!iVFcTf@d0VBQz<*3B$7 z@JEGMqd7(X(tGb+574k-L-z}@7?uc55MTl6AfN~s+d>J{C=0O^)s|t>fTN%_2$%$X zW2p5!`a&UMzE4Uv8+)AjW z){BpA)1ysSnWp@(DlfXoub;ivuiJCCGdvX2)1jjj7ccfY?D^VJ4;Vyg)GWjLEB!20 z{$DZ3w+DZ!rxNWZoH?M2B1lf*CmT&9(je||ug;bRbve}JCx7jW11E?h!4yW7lu`z% z?g*Ua3;jBtRL-$LPp^MxsiSt5iK#lkm>5am3E(^`y#OYFX@OA%EduL>pa!X~4#J7= zYis%iovwa+5Z?2cHP*I3s_Tb>Xr^ox8X8SJF=Xtv+k>PTM4q|F-6shNxz9>Hts)Is ziA|5IV*Cnm^?yMHSA&FL_y=mdX}Ki57^Zx$nW|qdQSOH8{?Pjb5q_`Ss}@iFOqGVe zt*7E^Bs?z&8cMa|o4Cl5S$@4~hoFebwd-=ur964RE=r9^^(={5EvQIb?ACCQu$!=2 zVx@TMu*yI5T=>YMtGzlqjFKkB^oN-4PC2Q$1D>aARDX2kUwXnMwAT8ny2^_;UuZ=w zjcU5uuaZ1uUR0$_MwR<^S?PhalU{X=-y{=Sya`iEwwPF8;ZGjWV}rxGc>XePcD)mX z?)tOn-rxFsZjIE7WQXxOT1{0ZP-SbbI8)zJC>RMSQPAjGaekx9U={sQi{?eqzqbpnj^TJbNKZvg&0HspI&0`1tc*IraN1 zdHtuz_$6=w-Nz-To|sY9b+0~;Uw94R)%F0KEq?-7vSi8GpM4UV!Y}9Lv(x{*-akOs znizDaNj5r+zHoN=GyQu{UJsbL|CDIpG@Q~CxE5wQi!E+R6YKe5!EeoQ)YU+6LjDYT zBN58+I9@)WwY`y%@+4{~O|?=up3iJck&Zyo*BtX8VGNDNkUQR8F|QOE$H5Aq&IEYA zPk-RLj4DOABgV);fn837M9AV$5P&fZ-f%;ArMIwb>-|z_el8l7!#m1Ton4{mruR>* z${tqb=N=0kt)&!dx*wl!fhG7Gvz-$^2u9mwY)e|aWJe`?HX3OQA zt=q~Z<^*m-DX?22Cd5W`XqMOvKsig09=5X8^MiQ(a*4;5N+?zYKQA8XKj7zkzQeIt9e-By zMlTv2#oqrpXRt8O)aXtV?%m={%vxq@*8WkjP|60;AVUhGU@t|aSxLDWW2KZz@6@GY zL96Lw#y393s@HM*CDC3xfm0*zCqlMVXPL;QxN{29n7B|v@|eb3D5hxX0;?5zK=30N zwGR_pB;n^?vicGwp?-4^(Ff4si+`{~27B8N-2N&8N@0R>TqNX*Lmluu3@mdz`zhDN zF7X@ZU*}g#UZLg)%#rK*{@ngn+a_s@&J7&;A(OYtew&!ql_pVBFyW&gbPqaHn1+Ic z_NA>USBz?n8mIoopsq8F9jPMp;@6zMu62F`&0vkA?S$y*5z0q;!;{M{EPpoj)P+hH z+*qt*LNV4&wqc&cIRbQXI6J7CtCyPSuyNASj3a)FW2FZQ#le3jRlm^0bpos!teQ!2 z=UnSG`vrWeaWf<2gMCVLN@;hcSlJ`0TzFpP58EmqtW{2|TAYT9OjPdzXO7qnOR?2h zWrJg8Qk6J~6uN3w6|33IV}A{=t-a#Ui_6B|{EF9q74pxB70$-xUo2LX``IdhX3{~Y zM*t@)|5KiOnjtt=ta#u6PxKbTAADC$ak#(y3zN2;3p3CB-(RhifTl)08sqTN_$l&R zKKQPh;o<%=ccgFHb!W>@mfbRZ<0)+%yV5u9`a<2%S?j;^- zU!l5FIHWYUAM_?pmJd`EvDVC;o~Fn5iSA1=9STwB`!rTpu{WI|B^s48#FU_c4AAa* zOxQLGnB#dAwWf=J13+L5bwF#W#DV=qW{HrrEb2?}yw-F*_+X_cz^)B4davG?8rQvT z)mc4Q^2<|4^Cj+}C4U`J#U+=h+Mn&T2CiH$vuhVhgedIzv^|iUz`y*1-fUW6VvEX6 zJfS8Vmjv|(br2EgDzNT6en}545s0)R#tyF+DfVRic zp<1!k&dNflS|FgnEr``#7esg-SOMOU3bHSeNslVkIVeBnZR&P%6c2yJy0R`|%I%*x?s`-wkLsC zg>C;-l_SIAh8o10yPO)?14jnzscc3{lLJ=zvWvrYqF(Aw@PV=2@S2>N10oxfbg@3qc)zYP>-r>4ubpHZQY!Y)%iV{wy zemEIBcIZ`SeFCK_I}}A2Rf<|5trR)irX~oe1MBlA8a4mJVqg>{|)^&RO#%Iksvm5kE zS;r(_BVY+Jh5Q8Q05w+-2RH)Kuh5-TbuRfgCXNei1C~(ffLW|mrpRtc zA0QWBNkj)|RVC0-=@T$f7V%YvV1HWK z<(73`GSJH84qL_Ci$QjH-13?hi4$!w&g^Sw=NZ`hpX{Enp*D$?MVYCL?Nt{8RbPWs z@{Ec`MSA+|{QPP^lCiYvQ>Zt7N)}@u|GVa>Cnd&;e79)VCT!KCrAZk*fL1*~qaah7 z=_gcn-w`z)43S>?o59@b3nk8d3V+TQh(c+S^1xGSJhDbbTd$NFMul=t`_?Y8w5^nK z1r`dVA#;dqVwB%u1Ir2cV`){4{0qk(e?*OURS}6aiq1!EB9TC;f>^2jPL`DCrE4tr zinp6ZJO%k{P0{Mt%9$2-UytfvvROLJa^a8T{`^5Q3xlE1QgfsTT+2RvXis!@-$1Xgl za$|>O%xT9>b`lH4B|I@iUUsW|VHT?8?KD`AAa+5?@S}`IVg_f4u5Wm^R7<_0utU7~ z1-K~SQK9LRtu!=LUi-1JbALCA`emY_r5$|#guGv+{8J);8O3}$PVNuzTCrx$8g}g1 z!Sl~Q|BB<9!W9oZHR|#EH`NtWqaMjd=f7n!c;>k?$Ik_L`#RJtKrn=!{9DeNE;b7sW!ad2=+|Ch59Z?ytTc?6!f#0#2mzrnE zruprjT}miFTrWD_g@4BrxOf$heB)igI$vY#3;7xWQKmRVf`4G2d`2x*3625JDCh$< zr&3}_v7-FR^F-evXJzL~|LXh~qu+^MpZ~|<0rla=rBdSuc%c^gEQk36HA{uI-{TCQ z-{{4YZKkn}6CI8|xNvk&MtYK3`wd z>iIR^i`t;D+TUmTxmldXeax<{4JHh#iB44rnk2k%o-ED}sZ8Rn`g3SncW+T|nNLt1 zYEl-*WRipAnxnzOaH}%(nx|JS=VGR)5S_(9G+$TU;>5bx#1WP;NE116$bsyd*$r!` zTBW+zt&*!GrGHW~hZq5nsdU$36hdQcnRm17$$EUC_YpnSTxaZX9dXqLQg4tRHKwL` zXzv5|6-(y%%^cwy>;!4Dp&@u*%kAm|o3G%@M7cyFY*wz%@HU-&{G0BPTmPkWJ}&n@ z^(|)!b_vdhXiA5Rc|10V)a(>Pmd*NU68lC&A98B~>wo-Y*>3wg^&uwkzV+qUXK&w_ zoo;-)>=;k$>s6-#i|;duE0(%djnm-vP-2}t*3hn=pUzsh=lYCS-DV<*CAc8II>_$w zQqD^(lLPfbdZATk?%VrCy>h|Drq)ghv3Kwvw6U62nIjt&>UmhO0f#pIweLI~yZW~3 z?A=V7cYnk^?MjtAPCpH5jyh$hYeP%>Fa4eWdGM={uQqmezH*mzV5+v3npbJ){)^u8 z7hnIndh2x?vNP$B(JUuYBfo5%{Or*zeE0sXae%j8x1sx2B!B(sV+L=yp}XxQ1r2cC z6<2isCl&sFs4$4mkjVX4art8#|B@mrsN!Z0$$w*emA!Dud;RxeSWYi*C(I%;R7h1U zpbL1BisD&8CG~KWPf*9dVOT|yT7(*&riB{`Q-x2CG=~^wA1`tNdueAG{k)qYE@dHK zU|dx(#fQmKq5StK(ZT~1*hE2&7M@ZVPAU!n038oWL_t*cqem#b;Uh9g51ogzx^`}- zJbz9gohaVV90bkf^zcyz2vcT|HvWtnHO#ooAcG2ZY?=R$){5$S=GoG3JZgeLmJ`3c)Smf zD2io7C=gO%x+TdHonx+gfl2uc`^;U8s(%sIkfl-2Cl_S+0rxVCr>Udwq0fXrcJ&>_ zA7gkc?KBYvUL<<&UFyK~e;_x?l-gJBkRar#yEv?FQkR%4lhl*v4jS3SD4S{EDTF^G z$6wLGUz1`&dR3W~>Kex7R<&C$pbnS|yr7_6{f0#3cgT_6{&{!a`akhLg2lZYV1FI8 z3}rse_Y)sxF=HSd0>^olQ1nsefEtw;hKDiaNOBn{n-sHYVF3=eP*nAlB(pj2u*jmih7%qMSec0L`s! z3=&4kh+05GeT5-ODNEiVO*E4SRew;>53)i~+tkx6<=c#K0jp#cix`n{j2ck$e%85V z_U6sES9G9$^-}9!CcgKbZz_OarF^w@>(*DCfKng=N~z=D71qo+r4SK}sq8=%G0d*t)n_rCY7_^ZkP@5KKE`F|TWZ1`1( zejTslb^H&2YHXe*4NYyYJV+@(&{`7;x%hs7)(Y3L35=m!@(GMVD@9;}Qw#=hP9rdO zY!Hme&E&w&Ci-RhptT|t3Mt?B(OToWwh96x<+3M1V9;6-1ZS0h)(M=RgZsaY{|WL( zM~D8K;+@y=I$p>BbeysVFn>1uGF9@)9yfsNI>h5K^64^(L;|#;P^$3Ll*=B)Vu@0z zgw`7052)<0sX%KB&wDwiey&{C*x1V?ZR)t-Gvw!|EAmkkj#DPTM)@aBG&HoFb$Rz> z`Tw2xpDO=#ypGrL{}xUdfU)6z5>-`P`JKxuRTWS`592r$Kgt;)7WtT8Af1iY&cw1RYiS$W0B*Yzt##7a2#7D5-}?X z0ttm&rIb>RW2!MBREzKu9d{K zt3f$<$A4TKjh29Nkf!WUQ4S{YO^ycrgHn}yT-Q+z4YgK2pQom#%61%E z`MyuNTsA=v*p{WFP$(GJbu1BMibY>?xq{JJDc=t;#)#JX#5#iGgo>Qlt#GFN>FH^V zF+95OnwJau$A3=J?*nUy z@j70||BrEs0jO%N;_-$bqD-Zx-zkJh9BQT*6KamMpnog}sZ*3jOOyuxPkU$fW9NC_ z_s_Gu>)B@`XSj%@M3GW#OO_YGb==5_6BI4b25?}sx$FNBAeX(!RRLf2zP%`l!hnJ1 zGKm+(vFq4|6e*T%S`@`aLvlFFnK|ow-sO3Iy?AFvq&P!Sc3d0c`CQG+IfL)>o&!A3 z^V=)jm47z@h+g~*tQ!2i7V#%y%H@bzYYN1aQHdyzE)8#`-{TAYe|PL+I-Sn`=3l#g zg21Xyr)dD1&4$rhDPs&pQIO{|?XSI|02N;PoC?E0v{ts+Y`DoJqbO>ZPgOY%Hvg)s zP)e(vovq{a4+F}FY&~LMfAikqA<*e`j(^{MXn(CaP9I^m zN+n55nkKl;A4s0(#BoHPm&!TEY?hnaC6u|@ESG~=LQxa~N|j|PL12$;>3MMbe}LES z!e>4_NIMt|9_s_wk4W|UJgZ!!AXE`abbpb7O?XFk$bk(MKSiLp4Q{h;t0=V>r%ym% zH$g8!u*yXpbB2;#GM2**3nrnO{gP*82CQ;}&Bt2noH=to-W=}4B0_tu?nY-SLp(}x zg+ayv#U?~s2^BzbklHCIEK%DcK-e+pJiyzWVhe)RMY1(Tk>u#opv#!a%7Avig@1^k z^#gmb5|P6jxYmj=4EM8sLc%bVG>vt=&f2FBV2mY->T2XL3@OX%plyX-T3VFJWa_J` z5~Y+jjj1@Nbz|Iy_C{P^X@Dyyv*83*b3~R5$4) zpWv>BZA$ut{7@>$e+ktskOD}k8-L<=sE6NF;3nX9pt{0UbB3$YWnR(=3PEhjsq`iG zvY&F<&$#heE1ffE&c~gHEP(bcAt()y6Hi+tSwu1kz~?Zs^zRI4_39GFtvfq}x3949 zg)b2%230A7C}zAng&%1apJ_8~3{XxJO`0T4VbmRCZ7r*{#(RI5?K2n*P=5-7AW*Ye zMv^2d2(!Nuew! zqw^HAqpQ8=%$f7#@lXsPZ^jhP5RVi5ZWFc9q)If~uMIIOfJ9M7f(f8^egV$^E3&-e z?u{MRE}y`ap5#Q6DlB1^5-&suLeVS?msu#+dzLFvH5qvaqs@b53ngYgeAButfiDI)}9gA&EgjUoBQb$r}mIGwR|;}(mni@dkB&V|ohWaD0+ zmGg^rPZtUB9S0JlDj^6A(Q-r_M-Od;#%Nlt7C~TjntvubjzbMF9*^|dvu6%lJM{az zD&Kk+W4lbJGj;REEtXc6e8jlva_?TPMladaO)_g5NiXx7aatFj7C#e>pvU^ zJ~9hvp94$a;OCEe^8s`bi|#+*Q5Ha7c}7J1wAzO1ZQvw-Mw=dvBsfbmewuYM-eX3A za8T}M@mTW1%%6W^c9WodkFV0@n|LVS;kDolU(pf$4;d~$XU?1_2Mb_L?T(pTpRhD; z(HL|A7+(=iu61GT5m8+Ir|XrD3cnjcwFJJoG+TVY~&Hu{zzdWoPxP1M;P5`ca@vq+h+kTzEBP{^Q`92!*H$g)F zEe%@a1i^o4%4n5;ejp=AgX`B%W*S^jA?Nlpe@;g$1eCPOb^eGh-w!o zMkbT7X}8;lKL6Xd@2ZOzpB1fY{kPw~rlL5ca*nFl&cFZrmGghu_+Z8Gl`sBPksL+}qdy6iJ#e9go;*;h#l0@2jk8=+1EtAQZrKKgQs*pLodcS%5pwh9ZB#R0uis}XIRHgg zlB6knvk@+Y&SHl=aClo1Bq1sh+*E&%P!lc$D5Z$waQ}9$iK0+xT@eJKSZj@lQ$Y}r zrYRzxvMjOIswj%&=FOWbh(h*u`;>WoefL#GlBA4B6O=M^dmX$8&NuWA7RAE{#aI16A;a`1bsaE=a&hFxQzEd`Fh$3XsL5aAEFz*B!zM73v& z=ZIP7DgI7wL;g$NOJAmmrx~82DArk$3P{0^7^|Zvx6PR|=gFhC0JNe6@~xb7W|@sk zLLCxJ6ytt|nF>J!*~S>135!XaVYZFV6nUOg0cs{R(gxFVMAIZ_lQ7F?w37r=YRCnQ zP`2ywklqWfs{QZAXjPU_mIZ%dXvy=6APDf@Gnq_r&I8C`Fu*xayVaz>wT1JZe3qjC z=Nyf+$#66vjzXd+CeJ4-NfI$eAEbqnWivU{ch#?L0UYu#Q88TJ0W_b)042tD*^&u+ z2;^76Z}9@>ILnMkH)(|DuqI`k-{54mNlKTgzsprAcp71sDU}ke)G>b){E$rMF@QO9 z=G0h#SzcnTC9FdFCmoVog2jjuA&6pj#zVTjMVh??zq7&SXq$Ms$#ioD;<0H=iKmJ@ zi%Sd4$jK;3mSX4`oPk-tgma$WETkw3TmjD4oAPW{h_zO=+ieXZK@h4&BL#$Jv%zRI zq>(mgqz$&W?y=k7rP+UJQ4~2&Ll`FjC@n1XdQ`5YstT3Fsf1x|X%t0?G1fO44R!C{ zJ)El^2mr&cW&!*v6~o8&0+Jj^X`_i$gTyZ48FCw4w|}6^Wi(Bl&})2-tBlETTud(G zMmt<4Sg0pyRnC#Cg6Mx*gyaxJ9xsAL(J~3M z?GegZWCG_`PxJ1(H(6;fF|`@9Y|6sY5@{o$92J~7f0kCWiAh0?>zlr|?2~#w$GXNFuf2IYBfXt7X;eZ^7Xh_NE zBR}DsIdeXaSb)G<`n%i2OA(VDgIS_Z77P`mdlS^6!K8m728&-;Y)*E0>Qm>qb7O;6 zJ7U2u5hW3Mp3~}fXs@*)PcmIEPA$*xHC`(E}(<=%*IRW56FVRpBH{zQ!XU>y}_1=>gC1DsanNEQm?!}mn zN9E9s6E<(|;&jR4T8HPKeVTE9N=!n$YS`@$=q`VC84tz;R&(amDw27a3J%9Kn-JR= zIW;AlZZgzs`=cA{`Mq8|d0t2u2JGz(#9AZP2FjQ^I2*@_Y;SL?ESu5m^|<)V(=wS% zR2(OqIlap6?tpHuE922vMRCm9+L}~Vh15Y{CX*>~98*=5-`nf^@pvll>pyq^{8}*p z9mR>6;M#%$R$HdiKn1G06Zl#W+Yg*OC%jy6cE2yr-jN4>?J-Ktk9L5E-`!g zbuuY=3js1PJrXG&p+9HNoF@qj;9MPSO~RPFpX$?j`vg8#^+YZp7{!E*fC(jGH$;~q z-oWm7Omeb?3l!b%A|}#|MmcFGVe{?|@yUMx(TedWhfL1zG474I&~I|EK_76SfAL~l z6-DX7Ftqh;zaB`RrYT_gKaDrrB2|Q=coPBIPF0r1gJBlVG zHw={wu)_w*DyX2{3K`v<(OznxGEXxN=x+>2C4#X717+ax%Af=W!(EonCb-HoS?E)` z5v)&X+!lu6@FCaBf&TjXUAMBbXh(mekx!CX9Soz7qEN=;scN^I)FU7R+1=e$VGvMN zrSjg3t13)k5P|LO9h%Lic<&jFrY_G5mu0!^TLtn#{R57&03Nr(_kJE#G5kmiK*c~t zA7McVj49&+(FPY(w1({uEI|(SqbQN0aIVuytO#<@ z^%GEOn)>m0s=M9#M!mAKBKLppZKAcJ-ELD9IU-=KrQL2xRaH!pkF)^7Gf@7Ne~_FDg!pQY6Tx|MW)NKfx4})f!#PfK&d(T4 ze@fdfv1qy|WpHjp;rh(n9vO!3Pyt(DpXI6W99=wXM^B@iGiS~dh&_Msgm~{6-5w#b zO{SogE#s;JuN2-^*nUj31cP_>=q|Pa&xxfvlc$_kBv_(uh}RBwp=wT%?E&E^BLtkT zaACnnJ(z1b;1qCMEr9gd;{?WS&~+z? zwC5E{UX6YavLEvIa)TS3;3e@i%5_Y+jzaJ#3KY8-{)PedAovpyKhLw0lVXV6JO^mb zoH;cQq=dB2wwSg8GC!iY9g++iWZelqa0Gcpy4gb39D8q02z7smFNL6C@v)G!BPtJA zL*B?J6GL$-ByTxHLEdzT4rmQpN3BBun$0FkDU?#)IZqtND$fhAltDyE90yt?bXk^} zFbpa7gV$PX;y4ySS&I}!B~cX9YPD1p)j`jqD1Cj{30qtD4mI!Rw>=a1yt3R5pN82# z@+QKUMUm&XIG=w$k7vs7n~?9PufXheZn`_%qzN>6j)(-!78UO?1%{w1u+KsKJb!|t zL%=0k^z+x@$gg0|oHdcHH^n&pQedEnAjyE zgkj)Yt%ep6uaweSoBaYW&2&0db)SE)s;Xiw60`0Oet2<82OWb7c>&KdLJIT=!sUVuR>I*Ewg-oF{_^4uEg}$M5mE zufKoD3+sOffUXpx1yOLT`W{{vsIsC`p2o%keqll|P?%kd3o=|#P?>@g_b%cV9If3I z=qr3!->Qdt$WQ*_jbj&c?b_9NX=!C-1olDwgWvz?xo=Ir{fn=BO_rDIjcse|?%@jugVPW8Dv^J> zZM29G#}TbolQgY+@ED`<-ZLDINs^e+Xu@z<2OG=%hWqz>U6xnRKvf;+P43e_Oi{7c zs>je*AJCU1iPdN{kt6gE7qGm%I=laQkJA55^1GzJxp}AgVeg+aXU@ly2P}Z))iV#g z`2N^LRkv+W3S%@PpaX-l5kX+d^Adl-(^*(1%W{HPvzW9FJ8&NDaetVDjp;sp^?<%s zhlhaHRw)&zAh0UW3lY(DItygkOoAYh#l_@){l{9t2lfAd^V`;+GiT0|g?jbXSNYo4 z{=D8Gk8oWmr5?DwE2R!cI9g*d)*QZGRR>Miz`43Be?_7tEwt!SQoZcycW9BgT|Lo7E(!4c6ixl2=)7;f zeEoL+qq+NjzkUEtfnu|7u0MQSuf|}rZ}!dAcD?ctoX?LxQq~!oee+IZfT+5_@NT`b zfm5?@HtSW#x`)T_FVIN83P2Rn^!p?vGxP)MEKMWR?>fm$qm23}!!|N(e=EbTWZ1O~ z+sUvS8Fu?Rwq36*pguMG=C-|kq4`wR+_X0nO+tX7n$7_bg9C<`UuUl`@i*fNq5UXUT>(NBbzGM0$=<<#!B^gz(iepNt-V|NY zY=e%<=$JBS%zlB!Yj*X=Kl4GngxBUM@R8T%7^2gIS#}nEaDp6yfAa%FN`;|*aHsUl z?#ySClw)n`mGqPanNY6V!&6?^KzxZ#(8xp7*+=-56hup7KYPNEQUt~+Z2*SGB1@SD80G^!p1qh<;i3@v!wNm=tlh)w{O`h6{4 zHWR77m^T>stbBug&)UW2Ju4Sm_d!QjG}pIo1bq~YL?Z;}e=~w$E*eAf%CU|aX4=ve zW*xFm1DJZ?U_7x#m9h@?j5~znMeaS5|M|z@=G9I*@hOHL6zdQVG$tQl?yck>P0AD@ z9R*MH$RDsk8ngjLZ;*7IU~o`K53`5qee?ClU32&Se*G7PVjuNe=9{bl03ZNKL_t(| zob0`McpTN4gH!{zR09EgPk#gKy2^9^-&(tzK4;GKqM1=IBgv|^&Z zl59gr_~PfwK4_q(R-x2<V{|1NSbuzBH@(~ToHPQb zdjIfWivZR>^eMQg`nix!lj`U=83oM0=pvZ7h-a_<$T{ynoBXpz004^@FFxx7PL_tA zIGNb$1s$ZPrg`qbseKZvne@848RHP=IdU<8)eGVr9;$l!Qw5kR zK;PKQ_s(e)=C;Rqcz<#r2C-i{rS#ur1b$pwODYIhFje4b*TsY!oJ#qe-!?AWd+=O4}{10^kp{xF?<1R`E3}BA!-&@Xn!|$7w~&9>qQ8*Xp93d98h%K zCWX2vk@9vYP&L|eY{xdw8<;kzyp*jz&z{xkMdE#aCbLo}`kxI=HSP3R&;s5dB!-@X z`UjEh^ANw7pFg#Pm{&o5>u*s9AA{Ww6Hc^IX{q*KnA{Ibej8L#sHuQ8B$1aM3>{Mj znf?3OxqtQ|w2UfLTJBdq-J^%CoTUMUXkXmgB|3iW5n!uO*$;{RkHex%z?6VEFCAS( zEE0mui*Q~EXvUp%sk=bKoB;nRDD8#Bd|3H=kjn(MgFV(%I!nPSNW?p?{hFG<lxa)liK!nV)gZm9Xv?m{Q2Z3CYTx;qW!${;Gs{^TmQ%BmhpNbfN;3V%A8K8Nu^R} zJmhRf;I%yeneVR|0TdL6hcfKgpXKfETElO=>-})-gVl>IUj$&&Rqq2}a&j7g!$XE0 z`+qa9I)2SUMY^E)w;ztgc$IwsuZ3T=5!iP9^*ytqQPQOn{aRCYEov+a&a$Dp>8*cu zn)09fu1}E5jQB4LzW;-AjXdFRB8oEP80ClbKWFrP|gg zNP#mZ=+cXjc?T~(y@drGlg#Px$d_E6-_^l$TZei7?>95Pc_%9lb)u4j?oo{XP=9E- z4wR*ctQ33lh%Sg5KrIxE@;Mxx`tA?C2X6i|uQ6gFmW%R%{4woGM*x>7lrL3=(!)M@ z!~CQ_%;=FG=EWl1u=*vY(l+IaqUnk!sT}?zhVS3T?6*S0B*-(sW#ELMGEHD!R0JR- zKzylIB0XV{#hT`8{J0zvBtTl{27k$;FGR+c{6VIk?}Bom)N&KC%Hup#F7oYz*RZ?L zN;F#GJ!3IOhYk1qPB;3ot;}t%E^PkjLz?T}D@2Y#J_n_vVSjviCI8fekt1*ZXlWUi z2bS>gL;C3Q6>5I+nDVm2o-`~ZIeO5U*1j9;dQ7oky}=uVVD2oWV1w1i_(mf5V#?uL!P$h%?}#&LSgqlot?MRj#EBe*}hf; z;1rJ&aqF2IE7KkhP!bTgG%435Zik3jLb-T)^Y&jw1hDp@Ptmks0r`mu+-Q_oeLeY! z38JYK`H2Z)_4O3eY4Q^jG%Z*F2R?JoNZ@tt1n%waJ!b@PDn8c#BY)QXsGskzdRghu z93AK7n)lJsQF?oOPwoajml4=GRgA4~;ALfg%}b{%^V;`7Zmut26>LoxP4-e|^uS>*7=@q>ZBSzdp^AP`;0<7|O1N_5$82!oTElT>iiV z>o1w!B+Bys@#%loZ-1M$$+TuiO!@GLJsp2W!TSXIA!z7C`7y42@g6>XY!kIBi+p`( zJ>fx*Me!jzR0cbKl;!UR1WH>#*8^kFdI2<)3T^2hNwIDzk^gs7bo(v8UtF|bXDe$X z>b8b!f;tLJZuzwPw<|C6yTXluHImiY*aId}qZMuoIFEk>7JvN_v91RQM+3Yui`|FX zs4wSvdtnqt9;T-60sMA@Q-o{&$lwhrXb>hIg*-afQ13<62=s}bEdDk9<2RO??)Xyh ze2i zViHxDv)rrmGGa3QiZ+Dkh2V!~A?>&D$$kBd`m?Z_KSqT7Pwfk?gGWYkniPwq76yU8twCQ-ZmLmmw(cD)dy5q%FzQl926smsGobS z*WMh-H*Wur%AgYfzQT$NrS`XyX#XRw`{3^}x6PvvxHRhwSJKO}D+fVVK*FYy6<7@E zyA-85pamAMg=52kV_uTr#XkF3TR-vGgvtH9Y$|trDrn;nSb_d=PETNHfz^JQo)|gTY3+Rb-U^kavn+s@W9iaXk841kbToJ*k7#J8JpU+cUduG|Jz4_*z`jA7tQB;a&^3Kh8 z`g7m)2>=d%^Uq&vs#Pe3?b_55P#Xk1Xxm(Vf`3Tu^FBtK46gfaFZuYF!dI_*N2#;z z{Zb=)flDDi0=)2fSavg=*KXuM?u-0rPk%cXcK5OThJS$V?}Bj!DIrsUnulS|1|d=a z9#$M50(X{GP9K#5Ib$xqsoYv~o7AqI0$!9GxJDcX)t9dQY~{8e|4HooH{G0DQn*-G zN=HGJh0K#se?=MMFEGCj=r)5?kJ>p!*K~ z@bh0{U_8Z3|9c-4-vfb9>FS#~`mIm1Di9XmEVyOhPT{d$NW0EZ<02Ee_SWLOiO1B` zzPP2XyulCDq*$mz-psQ`FZm1aFU>x=zh+vwSN%<8?t>pxun?O67pTYAAb%Hqn)`pR z0|_4H_HQlYhWWd=`LfxloC9NNyynX|{FR4ku7lKU!5;$(LN=?Y>o!r#S1MZTTjdeS z4=q>WJ8ttm(bT8`pi@x7-lhwK#ffDqoFBJ}C2e9VB`61!@=*``0X^>zqgrG9udgQA zInu^|Y_5S~3WguY3Nlz;^?z?JKDblB1Jxy{Op4O^2GXJrBEQz)O2$E>ydxf2w-S(@(kr)Ie!Pq+m1Cmz^pp? zJ)b{!cID*r&tV9flIp~QEqv?2<^0AqXL|Dh-}>g40Zv;Zcs=6}4`rxw14$S-YbTo- z=1w@l=J^Vo+7IBBMnDamU=cky%)0h0Nd-Ut=7nrK5eaO3;o4oCWfA(}TW;xDR4!xN zHshs$3Wig8Su>N9r++O1=W?&FhxF0ssvb_@*nlDJX%-v9)xh1?UfXl|0}rfMQ|5a) zPwyKUcPCU-);?^FhOki-88JX^=aA0yhh!qnzJ$m|1QXskk6Y z{g*t$=8qX_<4~H0aU(?P6mA>tSl-U>ctj6f_x55Z6Mz;-@qa#q%}0*d56@ofB`&_I zm{%?;zR-jM3;3xb)F{YLE!3^u5blK~X_|C~XOA_r_Szdzu_BDzhqT+2dkhH+`gSSS zzC-YKLM03X``k%?m>>v=TJERm6&)_MMMRf?=OiBg5YP6DHf z;*)~i(uYj^0DrYdkhu!q3K%;OrOAmPp_gD}j9BfLS@m`hQLLOT)Y?!=!DMfM(_~q( zgt%4?6@1ACLu z@;J|rB>2F>9pFqt=RX4$rTW=)Uhxm`VF-Q>$G!;mG=E%tL%?%`Cb{bUrPgRkTek2hS&tI@=;_!8bGp1^vLI->65735IUG< zx!sQ%zX1l1!-h>1-M28+_XVgI5-~{CfER~ZE|fDW9KSJe%@L$NYTVgN2u~iTJ~bP} z6Vzgu=zrCn{v2D=V4DmSPT*h?fVg7j5&k*Yns_{>d)SI#Q z{RPEiARbJoplLY-6Pmnl=zB1HTn#~bmo9ownCWIlo8*uz2D#xX~!B-QDEI$A3>6fa3Ht$<|gH=g$XVdSrx1GI{cP zYj-!5LgB1Y!0ToMeXTUmg%@7P`%WwaY~H;2oa3H-_E`#r!pnR@uYyn^oZqoO6Pq`y zmhXLY2XG>-b3&Pa>%rv!eD9k(xOL+!9^PK{=5O8D@tWi3&8lU`{wXe9-;)37j*;*= zrhjm9C-BVYS0Z>tKY&w>z|z(Xe(w-r>eayj03ZNKL_t)iatGb$!t{53GxE|cUoW0( zC-8^H$NA5?Iu@L0>=KrjWo*Y{L8Zd+k(W2Gz4XOD066X3@L7Jh+p*Z|1$1hkQV?JR zJ8YX{B6OTc(W%w``dE{Z^gqY^nrKC6Mt`z*Q=B>o=j~LKHwZ=h3Sz%Ig}q}Zx~V`- z=pXTi{}H+K67tJFOc4Jt#j!1{{jH~AHDt!1v=a(T70HMp5%Qy!ZLGN~sIS=|F*5Mt zKZb@^ys7duMfv{hl^!_I7z$!Iz!uN}P!>D`rSNR*;m4t~9%IeLk-2QTtQqgY|9`-; zkD$&sc%6-;+s0`yQl;KFCiJBh<84AsS71326DoEo&jJevNDI{P4RRbOkkrq=6&<|k zj@-OlpYqzmK_XvNgd&Q>?G}Z;5~?493+iBQgbQ+O2yJ@=nVv+s2AWlM!MF$jEt~4AzrdWBA zQ2YiZ{{@U}(zr?7^iFDq|2;H((N*O?QY+2dJL`kZwePe#C!Znx>~rpb_kWBSZFvi2 z5+3=GX6~0iK|{Slj}H(T?BNUV{W!5__E8)e(}4LU!`zrC*wJAa>}Qmm(9L8ZKy;|*UYZ`}fpaQqRlrv>}kfc`YBSXXL| z*Nf|oVMejC`HYmq2Q9?~LGsl1dvyk>r@=TV)N?L7ohff0ZX0O z_G3zs4B0g2OVk>})j>d^RHEUED|-B|ne(#$VhyyduEZKw`kmts=0kbXvLVqxDk0O;8_Lqe2Rd#yM z6ZT}X7ONrZIq^A4N76)=tSL8`EH`Qe38b0v}Mt?s7qhZaZT>`towxQt$7}z0f z`={_8Itax(B*Zo#uUJuM8q5buDMn%Zeew}|wHmOOOY6K=X`RakVQ9 z-TNUNPblt#iVwlWyD;tGEZ9wa@Y{IfP+6epxI*A4j69`i4hi-(hK8rDvNr;gj?Sm% z7>gl%HGd*r^Gc~9PnDpm2J*wIeDrB6UE6IUlhaPIwabgK2rjA-_I~oCgz5$BHlcK< zLM;Mki9ibUJ&#hj7ls1ORUZ}D1>ux}0byLjviYi%2urxKn;=)C3+)Xi=`~2fnrB>P zb6PpwtJmS5sm!WzFaHUWn z+1h%V$A9X5uO|Q8{Q%CgA0QTsou=eZt^7Hg^8fskPxAX0Ukru9>+Uv|9`)EVI-S4b zl4NX7V?f{7%Pg348Us?bNwz#Oo!8Wy^w2dm`7KXObL+-gvGmmRS?-Cm<%#Ln+zAX+ zJAZneVD3zx<@zflfEo0>rw8jR%ZU1N8h6l4KY^LfVyzvMr}Y@#vvuow>)LC3mX%68 z8jTVFnXE?x)f7(G>Z-w+Ii3qMo4;n#KHu|%worWgG>WhYS)=j7VbaE6@_C*Qhv~lm z{`Hsbzj9gMu>SVy_nJA`tybmWQ`T5`xqpNT$0d67?}e`G;rtIkeH-v)XlVp#QmApD zD8wcd(f7ikJn6(h4vOoaY`&5aF_y==VcGaff_h{fwt4$&c+={jDDd+gy zalawmZk0o>p9&_cltByD3pI{H8DJaOwE}Ym_JH*ygf3Aent&k)<_K0)ao|yyw@67S zB=(}qO+DH$*{6%r2+9YuL(mJ<pF+)C zki8oEg{TP85Y^p+pM~~Dc6*u$ADn|)?qkbibnm3;(M z7q|k$hpY3?jYHFgLR}i_Rw`tL3FRKv6+2>FdmZ6ORN2xck?Gx(ld~y^ja~jBuF*1i zWS=#$bdI#P$1ABsr=mOvp-Y6^5k({+@Lh1zASocMP)ET^3r%lQT(Q=m{s{_ihFC%I z;4o}hZKa)AL1KK1Rj@n7ntupe<=9*=Qh5OrNhzDc>F@HZ)#0Bl3YfvE(ZH*D|L}{i z0qk2{rFmHU&}UAbYd`P2ljWc@<)32*4+7P+krNJ6KYKP$UHqXl=J8AS18`lJN~Lnr z2)r^fICx?LGkBs@;*yIm{)Hoe8L#{K{e?U@r*U2$8PyyaEu528^M9AQ=Tz+3v~`*5 zsFR(%&W5u^04MK%$2W>U{n~nLhcj42XF7}hs`)tqS!9;>V+h%F8NW>UM z-Prc+L4MtgV*mbg`YaMp$Ejl)-S~EG1knnO&|Ik?T2s)PEwLCk=W>hzvX4)@;_Km^ zR>sbWlZpnR$z5u?=YO8)zSh}=Rbv6nF@~dC6;D5{So(IMm{;Wg9UL2$y;VrWq4cC; zv{f;2H&`*4f0;XEvO#Eghn-owwA7)phT1Fh-IW$)9^Vlfxm1;+I4oqp+En>F_WAGD z?NbNrY*Ws&ulhh~4jTLd6sI9*f~XJq7D#z8bp&4gistfn8-H>!cbWE1K2{ z^O^*mfI~mBC!0b+y!?Xlo31f&@=)qj!Nj=sRxJ!#*{Sa28qiZl)qjyC(?68yL(kbG z%?&|vw9gq#aDHv+EPs3Nt?y!uR^qJLwJ@bj&jIqQTYeTrFKFggL1 zF{s-Qtx*U^h4kf$paJSH1W^k0QyBJDW@6aNFJJ4mqCj#m{X<=5+GM$kO|+_i9`2`s zEA8ZhS!UMUs7Xm9puw+&u>r-{K6tF65e<#2puS5O*`aWUq3tqAE(Gf^WNuZM0(31l zT(#WFHh;GV$>|BJWUmt)U199#)5@Cavx+8*j^AXES1{_n)=u2QSAqB418{~R_`#ok z{KS|uD}PRt@k{Ol=&k=_7Ee@-z|OnxCYnmoe%^VE?AgQ4yYHs8yBmObLj%vsZ&g2^ zWgfq91aN8^$USlHmEL|npXZ6CC)QL?bilbJ9Dn|WB7o5xENp!J%$~n2W?Dj?P5veK zY}mE$=Eu(H-@9YuBd7KGJr@E`c;a2#n7;G3A~)M`YCnN|T16JMWq7x5ZB4L%QGZ~NclO+6U+xt{BbT=2J6gKS3F8U=I6?6) z{Cr$jjvdyy%yC_5O$PC#NZ9W*q1p`U^1m@q3*oHDtQ%Bj|C6DK(k$^0?NmY}s5`pX z9#1s{(ZrC6RN)uv*c7IE_W}ym}{f5eh`^7n245j^N@rt9$pS#X)IPZF| z#Y$5BXBY&3x00Rx)-mS7iaUbVmjBO=lMS+a9#T1X0pWtD&Cns0&h&yG-Y_ORtbfaq6z<}+ zUR*t)@aKtSp4S!KCSqMoa_6_LAD_3-Z|=MUnGTs!#4@fNRXqB=(4mD3yvF!>glZR{ z&udkshS?^n;!2ecNTsGkxarM;>QzWPun<@R_I~kn1U>nbRi0%e!E&f;3ZmsAe&2VU zvB77oeAlHxL+3?)ObrN-??c zCnm^GOwiiheX=AJVC$;)zUmx)=?LIdoUIh}lHDh?+KIzV1h8bu5_as^@v0HP$Uudr zIK-3A>+;n9E7-Fme@08lQ{|u9zjxyc*Y29>JzIN0D22mO{%dq}RKSz!K z*9`HUp`YogM287y59pEzl2`btCKHJ?iaXM$bLAmj2{rpE`+wrV3F1gFg;8atltGf6 zfwO#}U(b`uIUeZg_3tis*3B|8RSy^wBLzGGoJX}6zyvTYFsh(cV7(C3BFSVBPW(Vy z(=X^u@|{6=&tukD`vOTe3p8B~ek9%=#4ktMVI2GapS36t;8mAp%3@_t>CT9M=|iCL|vNL=i;aFDQ@v07v0 zc>1s^JoH@n$fB#gdOM7gX2tYJnC?kC>A8cRr)yPo<$qs!!X&iS`6^lC#ak}4qLxNA zU+vdO0kSWuayF|f{kyEpV8+R;y2fvo2`%1)DW_UZEU@q=59qO>5nVcenK!$^2|{=M zd35jZd?CL^8bop#ZQhlj0sHU;zgwPPQ!lRRgz~6(98g4K z;!IDevezoU*D1y>pmSSwxl~eq>oPwvXJybZRZ^b45G6VFGKbU&{33k(g|D9e{nfnw z(`5V#xPb2ClG9JjsOtLHp2sh}2Jl*Y0L~TxEPq+DmO~#Nv(Ot2i6j{f?3ZUKuc)m~I zx_^u+MYuD@vB4s{oCt}K#i1YoV;H*OhMsC~VcFLA<mAtLn zD@BYykWV-V@o9zs}t9)7prNOi4ueCsHz-z z$evvNF0TaztftCx8h~sC)eICEr<+Io47XN(W(UPu9Wxc!o7uY3=bz@cpe6qIiCHLYhsu9 zP4lnwlTuKqIRbO!y8gegzumq`nxb<9hXKeItcu?*rfsE3)D}(n=!e~d&J?DxD4~5B zYswX)+M>p3xG|{j3S&oV2)+1qr@woh-$)Bs<7hh}diofZBYok?Wfzv3dw=Ugmk=TPvRT_x;dO1QZ31)COTrAOf>6=-|ASI!D4CX|B`N4XyQ5nRxMWTq_}gg z^;-NQK1tl{F$%#xB|5FNyHc#&5mhNZuL_54RS4E9Czcea@gft|yTF+vcH>fPHCEl= zn4MH*P9cS^nN`DTHuG5H>wjyn_>1DQvA4eJ^@Ur zp4yR-feLqIZrXKc>ra>6GIHZ-Z5+EZH|_dj{qR}qzwXG~^oo{`lYh_L{c!#H4Z*%* zvP(FmG`Ao0CQg+PR28w-%$=U5*Y}C;OEVn`QSbXSC2QE5$&wb0${S)z&_EXG@H{4L z8wJeqJW5*AO~3&lFot@dtz727{t~l9NLdyQWq4j|x*vS7+7n>c1{u9qZ%mKtzV>8J z50(AO)X_qjJ7~>BRDWs7C93Y{JFUSh*URj>g%TkOJ3eC%<|ptk|FAckR+!kL@)J*} z$)+ViJa|rJm@VPmKT^Z#3A=dN`wO!O!Gc@8#y>nS-6#uHm4jx#xsM*M=PgptarJI8 zu-`YKipxxzpcVXJT{L1%LIS5Vn;Lum;igI671( zw%S=;2vrLN6u3pPI_iT6&jTyK8&*N?C9;`OrMiaXXS_q*PM*@?uUc2uCrrh?E>QYG zqiSR6sJhsSR0gHulwAMkpS1edZ<6-T+bUhdFInl9lyQb%v~ulpq{eSh$_kXShs2@{ zJV#ahe&pznn13M9Rx)PnV`(Wj*9DFu(&lSxBJaO%jBbasPYWK z!98l!ovWR~<1*dxrc%ANP}G`Sxyh|jT4F+D8~0J+R_eL?&{q4R!l;^By2Oiw+k7Xx z&7aoOzJIe~jo%b%6ni41ih;p6_bHR@r5w5iCl)3&T_(pdtZ0k4r4q%dqsmV$6RR?X zUGAY0%4(@u8t715EGv#O8VP=&0{c2;t9D2ryQ#Vb06cQrW1Rn)m8=}R>Wp{$pxpnu zb0Vg+!xu--4r&2$h ziXA(4yxeE_1fJi$8-R^nT|9d9X#O8Q*viO2h0onRaWXsJ9OjHv%`b~rKI=Ev*OXFC z4v#!F!As-pIz@i#x$gND%O9DM|1WoLT@T=H+}N{2YZd}=5z?U$3D3hbh9DFoTrM+U z+kdo(5cYinrK&p=MHp3zIv}GIdE2Ho2&e}N#!zDnhaHDb&tt-}=ml09L*>y&*8^NW zyUZB%F}(6^fdnD5mgxNw+r1@`>oN1IDeVPCD(W@^|qs2=D^l-$Y3v2_HQ0;(Os#d1RZpa)U zA74pC2WV9z&{^#hFmZ(G=k8{#eN=+(zhQ(1HsDzO^aVo`&$2jMRLU*kt1Q8^vVSYB z>%3H;mB}BrO8FOq+{n1)H7^n;+Gw2F*U-T;u=hXNJz+y#3M+>)Q(4kDb4f~ zD!1>58V`oaEdA|ZZt_BjbDx6q1%IMYo}@DPlp2q$QPH+5rIt~llGnbqODt_GrCfo9 z0vX62B9|EDciF&l0{%qW6vzIRN(DRnJ z^fZ*qTwN}c-m+!=7_j}8TY3_A-nm`_$s2Cysr>9`Cp&`4fc;Yyn0(uMNwx*Dj%&~| z$-2H#Nn4j#O)4I!Mls38zv1v>-w6i`Hx=(mt>$))K>CQvdObQF91r}?&AikyOE%5# z@a%Fz`QZl9@oqexz<>ElR{B>Lz7+j#^!ma-j|{4hHZ7G}KfnvM%I7%DAF5d@wEZ4u_Js&iYpV@1=%^!mCv~VcA0+a8z2UsK2YrvwyLE5f{lZddKJMi`qQD z)_YMK6jsLv%m6ow)3lG-b#=jnK{eB*ib1o47tWK#g<+LVyj_1DP227*>TUB0lA&g0 zaa<-jNWLW+EDX0PL!Wti)p9OoiYn1r3`Fw{)gw-H8ACLa7l%B^u9@AihMHBX zXWc5fO42GVbAN~t0NHAHEk+?U#+G?E%buLahx#7TQ!Vwz4%ZV`?H~;X=~ZKDiih?- zU|+Fhp5MX|zR6CIW*ZuV547H{KD7A?zCx5sB*JFp`iyMTxyQfd9=Y{j%je^A?^EA) zmSC6Re2AuXxKzMngGlX8G33~+pC++yH1rX-Hn7f5Re$XEe^4J`0`J>jiGA+&jk)Qj zcgl|OjJ{rV8L;>Plel83Th%y?ZZBol$zzQj>iOxMb$hK zVwoIh7}g7|dUN02FX@#FE;e;`N{GFS|Dc`Kw8#u+J>Dbk`C3AN( zY2Fq0w0|o#@;C!DsyXVkovw|o9l!E-{ujZoL%!PB)%EIK(t)YEI%;2|q5Cg;&tHDy z8|v-XZOF}}Lq>C)OpW}iaq6>2bMU?Ux5fe9e%*$iUz7axuN*UU!wo&{rzmKE^RBp} z=Rc|P_d}IIbcRIkzlzHr+xS#!y%od>k?eAI0MXctlYw zBSMjo3ezJgmgqcl)eB6@XW3`&VpJVt4SzYB^nCI`mLGC2vv`_%`XBmi_;0Shqx2ID zZ>NK1!oZ6}@4ZVMxc(32MwwFkDxDI9Jard`)lKRWlVg$w3fw^xn;2y?jXZ_$=j8co zI{91DOh})quu@&axZJ9C%LUW}bAcBWbg18wi2N>jGTXo4&RhSd-p8=GmjkS$j(_3o zXZS(lqbz0&q*LGo&k~A$DjZOw62tH?hCC@Q17(wDHmxkc;TB4&fwH_0Pt_AMv*`c^ z6pYEAu}lAhTnijvSUt)&au>^o;|V?`DgKg1D%cE3j?QBTRk3xx{FEr?k32w2TRTI9 zQF2TzAfdj>u%wkG?~-O(D1a&|7=Hj+A*gNYX_oRGj&T92WEG1zCgT`2sOJ5=Ys>7- zn{Th`K>gaK*1t-8|GVE(0KZQ8YU|dmuQ~yxKm?RhC%!AJnQ=-XA{bNMfhuB{VKGpr zTz|C*0BqiT`#H&Nlu}AWPM2@Z%=1;`tCQEyIf3tg|J(7`lK@qY~)HvBq7 zzkxUK2HpUwsb!WlHn+d}Af*67YfUKR;`;$wD_qAWFosImCol%B6oCm&GZ?@*jlkIP zAuuLClLI@O=$GY#){0OlqkyB}C}b)m5(&_XV!6ssQ>l2AN@dFB zGFoeVKcKq9rV6bsJn!Y4`nhslV`DFqw5bz<&yZi3uF6MIJVBZKI^~}{(b(8}*5%z( z<^Ol$T=L(*8+Ze6;C~V)4ZzsQ0EwC!uKez0)v5}p9u=q(sNrgrg@4K_2*6AktOkvQ zfV@DRLL!2M1wf>;=)M;#F;0z-$HZ~Hjsi~o%p{c|P&tGeW2snW$C13LSqS0C@-w!axh}Qb#I)dYbN}SxSaHjm}>1m8HJi70imkavG zPSNkDeqPZGz_#uW#}+^N=dWo5wAQaG{|&r>H}D4jCvlnqsA;R=@x~vaOtq%pDTYWK zYM~SpYLB#{EPn^7SCmJ~l!ttR-WLG~ty}}G7Up<@@Uk#oV~A3s0EF>E9-<7|v)C1V zj0-1kIOk-N$>a&;UrqZsj;)f(xCIc8$1JUtvMh^Ar9!z}(&o?$3Q+E%^Ofs5qP4Q) z@mP@07pYXLDIebtm{I<|@1vAf6BA?Sl7DhR`6R|(MSriqc>JUhNG6l#9(M|~)|^ZJ z8+Ze6;0^pw;-mpkN|71L5FZHm|Jysa9=nqBJU?Gmt>ZrSk?bCl9!f*a*hnN9PAnvb z5;-w)9Uz8a_;(oaWiEUbK$rOmfe{Q4Ah|VUSP&8fvN4DQ$TmGQoEb7a_IdBU_F)~W zzFe%{J%4PnIm3}M4im5Eirt&QTfHx;>aFjDf@@;pRg9DihNrtY?}L`0_3DeVCO&N)fb zM9$8FZf=fjUDui<5lz!bmZju*h9CWNEz6QLO@AoMTD%8sH#dq zq^@g?B6np=&-Ly95+6K)-}v$%@nkZ2tuNgC9jAJAbaZsQii@3CRT=KL-RNv%NoP5} zvS<-e9YAuJ(EwEI)J{ckBtwS+@yKGzh~P@9Lx}daSndl|R$^+4sZ-{=6NV=PR25?` z?SH|dsuwqKV}v-4&$E7F;yBhkPffed_DvtaT1S$!)yQ!iQ`gP9ZH3w1-qQJe5t^n^ z5fKq1%jGH<(>egtF5psj(DM%9U;pOM=KuN6zt`Ji@TG^q_kRAPdFKE+Iy(Me<0S_$ ze4s?N1xnJzfNYtN%_9gU%p50=Ck!^)5`V_S$H&Bv?y~t$zE7N4q!FSdr8r%{&kS4d z3|aIhh&LqjK3QLxjSHM>WsNa}5H7NPCX)#w5Ji!!R!g!hlPEG0LXg#}L`3A|Q2 zaZCt$NgrMj1K5$@iYdPiA) z;Mx1mbub_*9Dg>YeEKON9Wh<3IQ;AZTYFplufvCY<2UZ`^w|l!x3}7!E*cR=9yCQ7 zC5kM`PC}X{FKvX@8U}*_QRGaXXC_T!15gw*bL-a4i`EV&C#O;#et&{>V-|~*-2dzW z+q>KPxc;ITtotL^{Dyl*1x~AVB8DmU1e<}iA?Eu#N_Pc-5zV}~o^MAj4`wuVb2HyMh-^~H; z{?;FT{=4%!fzAPRbacEaI1wReAj?t){Q;+LKsiv#{|3FAIduvW3{U>{fVcnAH!xmU zt>%36*PoK45w#C2O^vMPq^aN&m>qvizW*Jx79;^_6L<&>WW9{hXoU9xYYmMEAt+gv zvbD8o@;ni1t$)tvg&huu7jOQL9zBsecfO@YTKx|{yeCN-(|AwQ1m?wpzO@7+tPVbr z(fGTnp|t?UtlLT$`u(1aMkDb)sI`XYI#hh21Nb6-_UFITw z^}hG>AI&=l(9zNHrr-dqwWMiE`Jlv65g(*9s~TG1$-~a7b${OnE=;-*maO)1ACPbvW z3Hs@fGJy0P?s`nMgoP;qL)?qGfBzBEk2pIyVWA}e)v_kbbIw*Xd<>(l5oP2Ft|rQ2 zBvbrC(by1gMu-S$8lT_J4M`Gn(dWoWlJkNho4b*jwb54>Z(fjxBOO(W% zot{va?e#r04Ox~`%;tz##v3DoD&BiF##}UrbIywQA+-95h+IAdeo+Sie5H!v&H;3E zbi4_)4!{UCP#%`#E61v+iA_v27mAZ5cA-QGET0ybrLvU`nJ$koOQ9@F8bDS`FYmFa zXY_4`u^E4>a>X#qu(g3w!7BBz9S<3T;+yvU-C84c4Ru`+$BwdWh@yxP0`vI-?*o8N zCKJ353~W+fHG_;w`LBYIr-av5Kjx3SWT_?WVk1RqC9R;c#d`HHu>C z^>RSz_j}A{Q+j!iUf$#A@ENBkr}Reys;a~rh|>%JG0Nt~292+2no6=X*EnvSMpe~V z>q398*OO<@p5c9SDF6(=m;?AlDuz1;(9zNHCg7l*q}6y&DHX}R1T7&-0znmrFt8b` zqZ#5II)~ePH~8d}`|J+4S-2&u<$}%aZSr15J*&8R`xb+KADe>|?M>e`U>_S+dnJ>} zjI=+#ScIx-(|DauXWH-QwjJ!!sA}8FCrN)2CesPV8mdOQaburP@84&0bCbnl$!fJ^ zb8Cydms3?0H*Vcx*z2n~zxjLLoV$odrqjYtCNqZqxStiG|s-IkIK3d5pyo9tsEZQ-0;!Z}a%GrwoP(n{JyVODKQK zlEHYyaDNDq5P(K2%DM&%{#Tc5Y$VL*3$npR+xG_{ikzIBoO1K#O^u>xU8O4`qO;jd z(ljAS5{$7JV>p|f@y&O>!Q+QdNwS>CwL$DvwPIsDW@}?Z*F|1U(@@vV`DjZCsuJe& z1z9%Wxh@dEFBb!N-HPEZ3#g-`<4u3Tg%BvKnmCS_FBU)v&r<9tASH~`jD!29cvG{r zKjPQE^-YSC1t}Tnp5^pp!gza3F)4_g;pSU==rX`U@pu-?IjKw0w-ziH2TaZW`RK-W zes9n~Symdy5oc!;b~=9Y;fnDZ|ZzLmo&||d1HT%)6)s# zjjG)-xmCY+s}grZpJ=lYiqfL|&G!0S~EcMhPVqvK7% z0eIgATeCRj$+u4!eRz$KN;{DYh-N8qFJewjJdQDSOt5fT6lB*2_(&L!x3Gy}HY>?T z83#{}Nv}t!5sH5}Wq$jNVxxcH8z+6%8}ypB{+&BRsjAw?aqQaLemjsp&vW89rfC|I z^8l|ghGM>8G#aV3mff8lwUMP28M%}*^?E+?H+%!4D|Delcy7M zO`z~#p^gGUETS-(p0a%_!#9EX<_Wc*!NUc;N6IvwzV!66)_?f$iQnDbah?-rGIy-8g3ZulEUcg{0u>2vm`q%E^Z_ z#+ySx8E=d^{NxxhhI}`tTGoV>;KssWt52gf)3+xS*9z*iLXE{o4TI_Mg(c{Pev)Kb zRo;(AnNvmAT|WWI^E?#A!i>l5je2)?SD!sQz!+gT98y&!s^EW|V>ldW(=;p=D{qVo zQG_}d<9$$7*mE9_$%uGzG{W<>&yg(&H;3Ebi6rSng=krHDED_ScVzZqnK>kV>zA^ zB2QE{}(ed|*OCuqt52s|I#5NIL5ApL7SDY71nH6aBUA2mdkvYJd8e7s3`r$p`r zToWU^iX1x1ObNZfVtPg!3#O z4IyBy)es=dQfrLyA$Vi0lQ@npipE5YhCmn$`cf1N?_8wAVMJZm+UxaERXsX-bqoO7 z=dgdTVem+w6M7XX+>P@|~8gXX6MQz3OjBZ1!2 zO~U4!Xd>8ChmV%{sG_kI*Ph+MZ+Zr&yKo|exV=?R&6L0RgTH*`V(#7hDBa%PU0G`d z&?s`^eF$x)l1KFd2pwQU=%s-$VcV9+Pe+a5gD8bSz6rv+J-GMmkrPTOE_eco{Y`B#^ny_?W9YrTK@ zbNcCX`tln3@`Ao*St_&HT(8i-SisKC-s<_k_bUCbljrph4j%Wv?EiOkbaZ?jTyg+A zdp9qA`1#mGY1=l4V68zFOk@$45Jir%tWg4^%^jA@k|;H7WrK?joL9fNzs!1Ld`@33 z=^ME?1dMSa5=j&}Da%S#4WrQ}%jJJcqbSp@t?YUI*IL1g`W+n|9sfTgKl#Z|_~8$K zzuh3Oc)AdgOSg9sxftQ-tiw8c@p;p%o34TP4IozreAm4HAOC{@{P2grU%YaGBJxUo z=VW~#oa^i7`s>aA)eCt4{Xg!1nf}+w`|tm8{|7(#!T$~Ej*gBF{x`0PH7yX#8Wb=9 O0000+Z_j3x=+CP@~CSf*U%2Ypjc?DOtPcZjj7 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 Cpr+UW delta 5768 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 diff --git a/tgstation.dme b/tgstation.dme index cceeb1f915..38834b6b60 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -859,6 +859,7 @@ #include "code\game\objects\items\devices\camera_bug.dm" #include "code\game\objects\items\devices\chameleonproj.dm" #include "code\game\objects\items\devices\compressionkit.dm" +#include "code\game\objects\items\devices\desynchronizer.dm" #include "code\game\objects\items\devices\dogborg_sleeper.dm" #include "code\game\objects\items\devices\doorCharge.dm" #include "code\game\objects\items\devices\electroadaptive_pseudocircuit.dm"