diff --git a/code/__HELPERS/trait_helpers.dm b/code/__HELPERS/trait_helpers.dm index 6fa0ea9d42d..4b23a6c59af 100644 --- a/code/__HELPERS/trait_helpers.dm +++ b/code/__HELPERS/trait_helpers.dm @@ -244,6 +244,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_EMP_RESIST "emp_resist" //The mob will take less damage from EMPs #define TRAIT_MINDFLAYER_NULLIFIED "flayer_nullified" //The mindflayer will not be able to activate their abilities, or drain swarms from people #define TRAIT_FLYING "flying" +#define TRAIT_MED_MACHINE_HALLUCINATING "med_machine_hallucinating" // medical machines (currently just scanners) will look strange. /// This mob is antimagic, and immune to spells / cannot cast spells #define TRAIT_ANTIMAGIC "anti_magic" /// This allows a person who has antimagic to cast spells without getting blocked diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 925dd2d981c..afd12fa9612 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -106,6 +106,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CANNOT_PULL" = TRAIT_CANNOT_PULL, "TRAIT_BSG_IMMUNE" = TRAIT_BSG_IMMUNE, "TRAIT_FLYING" = TRAIT_FLYING, + "TRAIT_MED_MACHINE_HALLUCINATING" = TRAIT_MED_MACHINE_HALLUCINATING, "TRAIT_UNKNOWN" = TRAIT_UNKNOWN, "TRAIT_ANTIMAGIC" = TRAIT_ANTIMAGIC, "TRAIT_ANTIMAGIC_NO_SELFBLOCK" = TRAIT_ANTIMAGIC_NO_SELFBLOCK, diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index c1ff7e1a0b6..96693c0c401 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -81,12 +81,37 @@ SLIME SCANNER if(!ishuman(M)) return + var/hallucinating = HAS_TRAIT(user, TRAIT_MED_MACHINE_HALLUCINATING) + var/mob/living/carbon/human/H = M + var/has_real_or_fake_reagents = FALSE if(length(H.reagents.reagent_list)) + has_real_or_fake_reagents = TRUE msgs += "Subject contains the following reagents:" for(var/datum/reagent/R in H.reagents.reagent_list) - msgs += "[R.volume]u of [R.name][R.overdosed ? " - OVERDOSING" : "."]" - else + var/volume = R.volume + var/overdosing = R.overdosed + + if(hallucinating) + if(prob(20)) + // make reagents look like they may exist in really crazy amounts, but also disappear + volume = max(rand(hallucinating - 10, hallucinating + 100), 0) + if(!volume) + continue + if(!overdosing) + overdosing = prob(10) + + msgs += "[volume]u of [R.name][overdosing ? " - OVERDOSING" : "."]" + + if(hallucinating && prob(10)) + has_real_or_fake_reagents = TRUE + if(!length(H.reagents.reagent_list)) + msgs += "Subject contains the following reagents:" + for(var/i in 1 to rand(1, 2)) + var/reagent_name = pick(GLOB.chemical_reagents_list) + msgs += "[rand(5, 100)]u of [GLOB.chemical_reagents_list[reagent_name]][prob(30) ? " - OVERDOSING" : "."]" + + if(!has_real_or_fake_reagents) msgs += "Subject contains no reagents." if(length(H.reagents.addiction_list)) @@ -94,6 +119,14 @@ SLIME SCANNER for(var/datum/reagent/R in H.reagents.addiction_list) msgs += "[R.name] Stage: [R.addiction_stage]/5" + if(hallucinating && prob(10)) + if(!length(H.reagents.addiction_list)) + msgs += "Subject is addicted to the following reagents:" + // try to add two random chems + for(var/i in 1 to rand(1, 2)) + var/reagent_name = pick(GLOB.chemical_reagents_list) + msgs += "[GLOB.chemical_reagents_list[reagent_name]] Stage: [rand(1, 5)]/5" + return msgs /proc/chemscan(mob/living/user, mob/living/M) @@ -154,9 +187,21 @@ SLIME SCANNER // Used by the PDA medical scanner too. /proc/healthscan(mob/user, mob/living/M, mode = DETAILED_HEALTH_SCAN, advanced = FALSE) var/list/msgs = list() + + var/scanned_name = "[M]" + + var/probably_dead = (M.stat == DEAD) + + // show your own health, evil + if(HAS_TRAIT(user, TRAIT_MED_MACHINE_HALLUCINATING) && prob(5)) + M = user + + if(HAS_TRAIT(user, TRAIT_MED_MACHINE_HALLUCINATING) && prob(10) && IS_HORIZONTAL(M)) + probably_dead = TRUE + if(issimple_animal(M)) // No box here, keep it simple. - if(M.stat == DEAD) + if(probably_dead) to_chat(user, "Analyzing Results for [M]:\nOverall Status: Dead") return @@ -165,7 +210,7 @@ SLIME SCANNER return // These sensors are designed for organic life. - if(!ishuman(M) || ismachineperson(M)) + if(!ishuman(M) || ismachineperson(M) || (HAS_TRAIT(user, TRAIT_MED_MACHINE_HALLUCINATING) && prob(5))) msgs += "Analyzing Results for ERROR:\nOverall Status: ERROR" msgs += "Key: Suffocation/Toxin/Burns/Brute" msgs += "Damage Specifics: ? - ? - ? - ?" @@ -177,10 +222,24 @@ SLIME SCANNER var/mob/living/carbon/human/H = M var/fake_oxy = max(rand(1,40), H.getOxyLoss(), (300 - (H.getToxLoss() + H.getFireLoss() + H.getBruteLoss()))) - var/OX = H.getOxyLoss() > 50 ? "[H.getOxyLoss()]" : H.getOxyLoss() - var/TX = H.getToxLoss() > 50 ? "[H.getToxLoss()]" : H.getToxLoss() - var/BU = H.getFireLoss() > 50 ? "[H.getFireLoss()]" : H.getFireLoss() - var/BR = H.getBruteLoss() > 50 ? "[H.getBruteLoss()]" : H.getBruteLoss() + var/OX = H.getOxyLoss() + var/TX = H.getToxLoss() + var/BU = H.getFireLoss() + var/BR = H.getBruteLoss() + + // adjust health randomly if hallucinating + if(HAS_TRAIT(user, TRAIT_MED_MACHINE_HALLUCINATING) && prob(5)) + var/list/healths = list(OX, TX, BU, BR) + shuffle_inplace(healths) + OX = healths[1] + TX = healths[2] + BU = healths[3] + BR = healths[4] + + OX = OX > 50 ? "[OX]" : OX + TX = TX > 50 ? "[TX]" : TX + BU = BU > 50 ? "[BU]" : BU + BR = BR > 50 ? "[BR]" : BR var/status = "Dead" // Dead by default to make it simpler var/DNR = !H.ghost_can_reenter() // If the ghost can't reenter @@ -188,18 +247,19 @@ SLIME SCANNER if(DNR) status = "Dead (DNR)" else // Alive or unconscious - if(HAS_TRAIT(H, TRAIT_FAKEDEATH)) // status still shows as "Dead" + if(HAS_TRAIT(H, TRAIT_FAKEDEATH) || probably_dead) // status still shows as "Dead" OX = fake_oxy > 50 ? "[fake_oxy]" : fake_oxy else status = "[H.health]% Healthy" - msgs += "Analyzing Results for [H]:\nOverall Status: [status]" + msgs += "Analyzing Results for [scanned_name]:\nOverall Status: [status]" msgs += "Key: Suffocation/Toxin/Burns/Brute" msgs += "Damage Specifics: [OX] - [TX] - [BU] - [BR]" - if(H.timeofdeath && (H.stat == DEAD || (HAS_TRAIT(H, TRAIT_FAKEDEATH)))) - msgs += "Time of Death: [station_time_timestamp("hh:mm:ss", H.timeofdeath)]" - var/tdelta = round(world.time - H.timeofdeath) + if(H.timeofdeath && (H.stat == DEAD || (HAS_TRAIT(H, TRAIT_FAKEDEATH)) || probably_dead)) + var/tod = probably_dead || (HAS_TRAIT(user, TRAIT_MED_MACHINE_HALLUCINATING) && prob(10)) ? world.time - rand(10, 5000) : H.timeofdeath // Sure let's blow it out + msgs += "Time of Death: [station_time_timestamp("hh:mm:ss", tod)]" + var/tdelta = round(world.time - tod) if(H.is_revivable() && !DNR) msgs += "Subject died [DisplayTimeText(tdelta)] ago, defibrillation may be possible!" else @@ -234,10 +294,10 @@ SLIME SCANNER else if(!heart) msgs += "Subject has no heart." - if(H.getStaminaLoss()) + if(H.getStaminaLoss() || HAS_TRAIT(user, TRAIT_MED_MACHINE_HALLUCINATING) && prob(5)) msgs += "Subject appears to be suffering from fatigue." - if(H.getCloneLoss()) + if(H.getCloneLoss() || (HAS_TRAIT(user, TRAIT_MED_MACHINE_HALLUCINATING) && prob(5))) msgs += "Subject appears to have [H.getCloneLoss() > 30 ? "severe" : "minor"] cellular damage." // Brain. @@ -276,6 +336,21 @@ SLIME SCANNER if(burn_wound) msgs += "Critical burn detected. Examine patient's body for location." + if(HAS_TRAIT(user, TRAIT_MED_MACHINE_HALLUCINATING) && prob(5)) + var/list/spooky_conditions = list( + "Patient appears to be infested.", + "Patient's bones are hollow.", + "Patient has limited attachment to this physical plane.", + "Patient is aggressive. Immediate sedation recommended.", + "Patient's vitamin D levels are dangerously low.", + "Patient's spider levels are dangerously low.", + "Subject is ready for experimentation.", + ) + msgs += pick(spooky_conditions) + + if(HAS_TRAIT(user, TRAIT_MED_MACHINE_HALLUCINATING) && prob(5) && (H.stat == DEAD || (HAS_TRAIT(H, TRAIT_FAKEDEATH)))) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), user, "[H]'s head snaps to look at you."), rand(1 SECONDS, 3 SECONDS)) + // Blood. var/blood_id = H.get_blood_id() if(blood_id) diff --git a/code/modules/hallucinations/effects/weird_machinery.dm b/code/modules/hallucinations/effects/weird_machinery.dm new file mode 100644 index 00000000000..4c96e0a47aa --- /dev/null +++ b/code/modules/hallucinations/effects/weird_machinery.dm @@ -0,0 +1,18 @@ + +/obj/effect/hallucination/trait_applier + /// The trait to apply + var/trait_applied + + +/obj/effect/hallucination/trait_applier/Initialize(mapload, mob/living/carbon/hallucination_target) + . = ..() + // add a single one per datum in case it gets invoked multiple times + ADD_TRAIT(hallucination_target, trait_applied, UNIQUE_TRAIT_SOURCE(src)) + +/obj/effect/hallucination/trait_applier/Destroy() + REMOVE_TRAIT(target, trait_applied, UNIQUE_TRAIT_SOURCE(src)) + return ..() + +/obj/effect/hallucination/trait_applier/medical_machinery + duration = list(40 SECONDS, 60 SECONDS) + trait_applied = TRAIT_MED_MACHINE_HALLUCINATING diff --git a/code/modules/hallucinations/hallucinations.dm b/code/modules/hallucinations/hallucinations.dm index ddf8e15cd1c..9e705cc6320 100644 --- a/code/modules/hallucinations/hallucinations.dm +++ b/code/modules/hallucinations/hallucinations.dm @@ -6,6 +6,7 @@ GLOBAL_LIST_INIT(hallucinations, list( /obj/effect/hallucination/speech = 15, /obj/effect/hallucination/audio = 25, /obj/effect/hallucination/audio/localized = 25, + /obj/effect/hallucination/trait_applier/medical_machinery = 25, /obj/effect/hallucination/examine_hallucination = 25, ), HALLUCINATE_MODERATE = list( diff --git a/paradise.dme b/paradise.dme index 90e5468b426..0d4c052efc1 100644 --- a/paradise.dme +++ b/paradise.dme @@ -2001,6 +2001,7 @@ #include "code\modules\hallucinations\effects\minor.dm" #include "code\modules\hallucinations\effects\moderate.dm" #include "code\modules\hallucinations\effects\waves_hallucination.dm" +#include "code\modules\hallucinations\effects\weird_machinery.dm" #include "code\modules\hallucinations\effects\xeno_pounce.dm" #include "code\modules\holiday\christmas.dm" #include "code\modules\holiday\holiday.dm"