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"