From 709e9d130c15066dba605e7db2d54606ebcf5469 Mon Sep 17 00:00:00 2001
From: Will <7099514+Willburd@users.noreply.github.com>
Date: Thu, 15 May 2025 03:17:39 -0400
Subject: [PATCH] Hallucination Refactor (#17661)
* begone accursed beast
* cleanup and notes
* screen object fix
* varset clear
* don't raw send sounds, spark on door sound, pain hallucination
* lengthen this a bit
* more pain messages, become jittery
* note
* lets clean that up to
* Revert "lets clean that up to"
This reverts commit 2409e4187006d9d0e29a5385a7037f17f07f0f1d.
* cleanup and define
* use accessors
* death isn't working so have toxins instead, it's scarier
* don't actually clean these up, because of how xenochi works
* additional protection
* hunger joke
* Use get_component instead of a cache
* empty scope removed
* Updated xenochi code to use hallu component
---------
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
---
code/__defines/hallucination.dm | 8 +
code/controllers/subsystems/motion_tracker.dm | 8 +-
code/datums/components/species/xenochimera.dm | 192 +------
code/game/machinery/doors/airlock.dm | 1 +
.../game/objects/effects/client_only_image.dm | 23 +
code/game/objects/effects/motion_echo.dm | 23 +-
code/modules/flufftext/Hallucination.dm | 497 ++++--------------
code/modules/flufftext/fake_attacker.dm | 218 ++++++++
.../modules/flufftext/hallucination_events.dm | 302 +++++++++++
code/modules/mob/living/carbon/human/life.dm | 22 +-
code/modules/mob/living/living_defines.dm | 1 -
vorestation.dme | 4 +
12 files changed, 689 insertions(+), 610 deletions(-)
create mode 100644 code/__defines/hallucination.dm
create mode 100644 code/game/objects/effects/client_only_image.dm
create mode 100644 code/modules/flufftext/fake_attacker.dm
create mode 100644 code/modules/flufftext/hallucination_events.dm
diff --git a/code/__defines/hallucination.dm b/code/__defines/hallucination.dm
new file mode 100644
index 0000000000..8bd739f1ac
--- /dev/null
+++ b/code/__defines/hallucination.dm
@@ -0,0 +1,8 @@
+#define HALLUCINATION_THRESHOLD 20
+#define XENOCHIFERAL_THRESHOLD 10
+
+#define HUD_HALLUCINATION_NONE 0
+#define HUD_HALLUCINATION_CRIT 1
+#define HUD_HALLUCINATION_TOXIN 2
+#define HUD_HALLUCINATION_OXY 3
+#define HUD_HALLUCINATION_ONFIRE 4
diff --git a/code/controllers/subsystems/motion_tracker.dm b/code/controllers/subsystems/motion_tracker.dm
index 2d3127143b..5cd4b1459a 100644
--- a/code/controllers/subsystems/motion_tracker.dm
+++ b/code/controllers/subsystems/motion_tracker.dm
@@ -43,10 +43,12 @@ SUBSYSTEM_DEF(motiontracker)
if(Rt && At && count)
while(count-- > 0)
// Place at root turf offset from signal responder's turf using px offsets. So it will show up over visblocking.
- var/image/motion_echo/E = new /image/motion_echo('icons/effects/effects.dmi', Rt, "motion_echo", OBFUSCATION_LAYER, SOUTH)
+ var/image/client_only/motion_echo/E = new /image/client_only/motion_echo('icons/effects/effects.dmi', Rt, "motion_echo", OBFUSCATION_LAYER, SOUTH)
E.place_from_root(At)
- for(var/datum/weakref/C in clients)
- E.append_client(C)
+ for(var/datum/weakref/CW in clients)
+ var/client/C = CW?.resolve()
+ if(C)
+ E.append_client(C)
currentrun.Remove(key)
expended_echos[key] = data
if(MC_TICK_CHECK)
diff --git a/code/datums/components/species/xenochimera.dm b/code/datums/components/species/xenochimera.dm
index 1bfe5e77b3..b6927b16dd 100644
--- a/code/datums/components/species/xenochimera.dm
+++ b/code/datums/components/species/xenochimera.dm
@@ -237,196 +237,10 @@
if(!owner.stat)
owner.emote("twitch")
-
/datum/component/xenochimera/proc/handle_feral()
- if(owner.handling_hal) return
- owner.handling_hal = 1
-
- if(owner.client && feral >= 10) // largely a copy of handle_hallucinations() without the fake attackers. Unlike hallucinations, only fires once - if they're still feral they'll get hit again anyway.
- spawn(rand(200,500)/(feral/10))
- if(!feral) return //just to avoid fuckery in the event that they un-feral in the time it takes for the spawn to proc
- var/halpick = rand(1,100)
- switch(halpick)
- if(0 to 15) //15% chance
- //Screwy HUD
- //to_chat(src, "Screwy HUD")
- owner.hal_screwyhud = pick(1,2,3,3,4,4)
- spawn(rand(100,250))
- owner.hal_screwyhud = 0
- if(16 to 25) //10% chance
- //Strange items
- //to_chat(src, "Traitor Items")
- if(!owner.halitem)
- owner.halitem = new
- var/list/slots_free = list(ui_lhand,ui_rhand)
- if(owner.l_hand) slots_free -= ui_lhand
- if(owner.r_hand) slots_free -= ui_rhand
- if(!owner.belt) slots_free += ui_belt
- if(!owner.l_store) slots_free += ui_storage1
- if(!owner.r_store) slots_free += ui_storage2
- if(slots_free.len)
- owner.halitem.screen_loc = pick(slots_free)
- owner.halitem.layer = 50
- switch(rand(1,6))
- if(1) //revolver
- owner.halitem.icon = 'icons/obj/gun.dmi'
- owner.halitem.icon_state = "revolver"
- owner.halitem.name = "Revolver"
- if(2) //c4
- owner.halitem.icon = 'icons/obj/assemblies.dmi'
- owner.halitem.icon_state = "plastic-explosive0"
- owner.halitem.name = "Mysterious Package"
- if(prob(25))
- owner.halitem.icon_state = "c4small_1"
- if(3) //sword
- owner.halitem.icon = 'icons/obj/weapons.dmi'
- owner.halitem.icon_state = "sword1"
- owner.halitem.name = "Sword"
- if(4) //stun baton
- owner.halitem.icon = 'icons/obj/weapons.dmi'
- owner.halitem.icon_state = "stunbaton"
- owner.halitem.name = "Stun Baton"
- if(5) //emag
- owner.halitem.icon = 'icons/obj/card.dmi'
- owner.halitem.icon_state = "emag"
- owner.halitem.name = "Cryptographic Sequencer"
- if(6) //flashbang
- owner.halitem.icon = 'icons/obj/grenade.dmi'
- owner.halitem.icon_state = "flashbang1"
- owner.halitem.name = "Flashbang"
- if(owner.client) owner.client.screen += owner.halitem
- spawn(rand(100,250))
- if(owner.client)
- owner.client.screen -= owner.halitem
- owner.halitem = null
- if(26 to 35) //10% chance
- //Flashes of danger
- //to_chat(src, "Danger Flash")
- if(!owner.halimage)
- var/list/possible_points = list()
- for(var/turf/simulated/floor/F in view(owner,world.view))
- possible_points += F
- if(possible_points.len)
- var/turf/simulated/floor/target = pick(possible_points)
-
- switch(rand(1,3))
- if(1)
- //to_chat(src, "Space")
- owner.halimage = image('icons/turf/space.dmi',target,"[rand(1,25)]",TURF_LAYER)
- if(2)
- //to_chat(src, "Fire")
- owner.halimage = image('icons/effects/fire.dmi',target,"1",TURF_LAYER)
- if(3)
- //to_chat(src, "C4")
- owner.halimage = image('icons/obj/assemblies.dmi',target,"plastic-explosive2",OBJ_LAYER+0.01)
-
-
- if(owner.client) owner.client.images += owner.halimage
- spawn(rand(10,50)) //Only seen for a brief moment.
- if(owner.client) owner.client.images -= owner.halimage
- owner.halimage = null
-
- if(36 to 55) //20% chance
- //Strange audio
- //to_chat(src, "Strange Audio")
- switch(rand(1,12))
- if(1) owner << 'sound/machines/door/old_airlock.ogg'
- if(2)
- if(prob(50))owner << 'sound/effects/Explosion1.ogg'
- else owner << 'sound/effects/Explosion2.ogg'
- if(3) owner << 'sound/effects/explosionfar.ogg'
- if(4) owner << 'sound/effects/Glassbr1.ogg'
- if(5) owner << 'sound/effects/Glassbr2.ogg'
- if(6) owner << 'sound/effects/Glassbr3.ogg'
- if(7) owner << 'sound/machines/twobeep.ogg'
- if(8) owner << 'sound/machines/door/windowdoor.ogg'
- if(9)
- //To make it more realistic, I added two gunshots (enough to kill)
- owner << 'sound/weapons/Gunshot1.ogg'
- spawn(rand(10,30))
- owner << 'sound/weapons/Gunshot2.ogg'
- if(10) owner << 'sound/weapons/smash.ogg'
- if(11)
- //Same as above, but with tasers.
- owner << 'sound/weapons/Taser.ogg'
- spawn(rand(10,30))
- owner << 'sound/weapons/Taser.ogg'
- //Rare audio
- if(12)
- //These sounds are (mostly) taken from Hidden: Source
- var/list/creepyasssounds = list('sound/effects/ghost.ogg', 'sound/effects/ghost2.ogg', 'sound/effects/Heart Beat.ogg', 'sound/effects/screech.ogg',\
- 'sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', 'sound/hallucinations/far_noise.ogg', 'sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg',\
- 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\
- 'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\
- 'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg')
- owner << pick(creepyasssounds)
- if(56 to 60) //5% chance
- //Flashes of danger
- //to_chat(src, "Danger Flash")
- if(!owner.halbody)
- var/list/possible_points = list()
- for(var/turf/simulated/floor/F in view(owner,world.view))
- possible_points += F
- if(possible_points.len)
- var/turf/simulated/floor/target = pick(possible_points)
- switch(rand(1,4))
- if(1)
- owner.halbody = image('icons/mob/human.dmi',target,"husk_l",TURF_LAYER)
- if(2,3)
- owner.halbody = image('icons/mob/human.dmi',target,"husk_s",TURF_LAYER)
- if(4)
- owner.halbody = image('icons/mob/alien.dmi',target,"alienother",TURF_LAYER)
- // if(5)
- // halbody = image('xcomalien.dmi',target,"chryssalid",TURF_LAYER)
-
- if(owner.client) owner.client.images += owner.halbody
- spawn(rand(50,80)) //Only seen for a brief moment.
- if(owner.client) owner.client.images -= owner.halbody
- owner.halbody = null
- if(61 to 85) //25% chance
- //food
- if(!owner.halbody)
- var/list/possible_points = list()
- for(var/turf/simulated/floor/F in view(owner,world.view))
- possible_points += F
- if(possible_points.len)
- var/turf/simulated/floor/target = pick(possible_points)
- switch(rand(1,10))
- if(1)
- owner.halbody = image('icons/mob/animal.dmi',target,"cow",TURF_LAYER)
- if(2)
- owner.halbody = image('icons/mob/animal.dmi',target,"chicken",TURF_LAYER)
- if(3)
- owner.halbody = image('icons/obj/food.dmi',target,"bigbiteburger",TURF_LAYER)
- if(4)
- owner.halbody = image('icons/obj/food.dmi',target,"meatbreadslice",TURF_LAYER)
- if(5)
- owner.halbody = image('icons/obj/food.dmi',target,"sausage",TURF_LAYER)
- if(6)
- owner.halbody = image('icons/obj/food.dmi',target,"bearmeat",TURF_LAYER)
- if(7)
- owner.halbody = image('icons/obj/food.dmi',target,"fishfillet",TURF_LAYER)
- if(8)
- owner.halbody = image('icons/obj/food.dmi',target,"meat",TURF_LAYER)
- if(9)
- owner.halbody = image('icons/obj/food.dmi',target,"meatstake",TURF_LAYER)
- if(10)
- owner.halbody = image('icons/obj/food.dmi',target,"monkeysdelight",TURF_LAYER)
-
- if(owner.client) owner.client.images += owner.halbody
- spawn(rand(50,80)) //Only seen for a brief moment.
- if(owner.client) owner.client.images -= owner.halbody
- owner.halbody = null
- if(86 to 100) //15% chance
- //hear voices. Could make the voice pick from nearby creatures, but nearby creatures make feral hallucinations rare so don't bother.
- var/list/hiddenspeakers = list("Someone distant", "A voice nearby","A familiar voice", "An echoing voice", "A cautious voice", "A scared voice", "Someone around the corner", "Someone", "Something", "Something scary", "An urgent voice", "An angry voice")
- var/list/speakerverbs = list("calls out", "yells", "screams", "exclaims", "shrieks", "shouts", "hisses", "snarls")
- var/list/spookyphrases = list("It's over here!","Stop it!", "Hunt it down!", "Get it!", "Quick, over here!", "Anyone there?", "Who's there?", "Catch that thing!", "Stop it! Kill it!", "Anyone there?", "Where is it?", "Find it!", "There it is!")
- to_chat(owner, span_game(span_say(span_name(pick(hiddenspeakers)) + " [pick(speakerverbs)], \"[pick(spookyphrases)]\"")))
-
-
- owner.handling_hal = 0
- return
+ if(QDELETED(owner) || owner.get_hallucination_component() || !owner.client || feral < XENOCHIFERAL_THRESHOLD)
+ return
+ owner.LoadComponent(/datum/component/hallucinations/xenochimera)
/obj/screen/xenochimera
icon = 'icons/mob/chimerahud.dmi'
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index d40fab23a8..2e70cac02b 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -672,6 +672,7 @@ About the new airlock wires panel:
return
else if(user.hallucination > 50 && prob(10) && src.operating == 0)
to_chat(user, span_danger("You feel a powerful shock course through your body!"))
+ user.playsound_local(get_turf(user), get_sfx("sparks"), vol = 75)
user.halloss += 10
user.stunned += 10
return
diff --git a/code/game/objects/effects/client_only_image.dm b/code/game/objects/effects/client_only_image.dm
new file mode 100644
index 0000000000..3b87c721c1
--- /dev/null
+++ b/code/game/objects/effects/client_only_image.dm
@@ -0,0 +1,23 @@
+/*
+* Sending images to clients can cause memory leaks if not handled safely.
+* This is a wrapper for handling it safely. Mostly used by self deleting effects.
+*/
+/image/client_only
+ var/list/clients = list()
+
+/image/client_only/proc/append_client(var/client/C)
+ C.images += src
+ clients.Add(WEAKREF(C))
+
+/image/client_only/Destroy(force)
+ . = ..()
+ for(var/datum/weakref/CW in clients)
+ var/client/C = CW?.resolve()
+ if(C)
+ C.images -= src
+
+// Mostly for motion echos, but someone will probably find another use for it... So parent type gets it instead!
+/image/client_only/proc/place_from_root(var/turf/At)
+ var/rand_limit = 12
+ pixel_x += ((At.x - loc.x) * 32) + rand(-rand_limit,rand_limit)
+ pixel_y += ((At.y - loc.y) * 32) + rand(-rand_limit,rand_limit)
diff --git a/code/game/objects/effects/motion_echo.dm b/code/game/objects/effects/motion_echo.dm
index 19face9b88..211af8975c 100644
--- a/code/game/objects/effects/motion_echo.dm
+++ b/code/game/objects/effects/motion_echo.dm
@@ -1,27 +1,8 @@
-/image/motion_echo
+/image/client_only/motion_echo
plane = PLANE_FULLSCREEN
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
appearance_flags = (RESET_COLOR|PIXEL_SCALE|KEEP_APART)
- var/list/clients = list()
-/image/motion_echo/New(icon, loc, icon_state, layer, dir)
+/image/client_only/motion_echo/New(icon, loc, icon_state, layer, dir)
. = ..()
QDEL_IN(src, 2 SECONDS)
-
-/image/motion_echo/proc/place_from_root(var/turf/At)
- var/rand_limit = 12
- pixel_x += ((At.x - loc.x) * 32) + rand(-rand_limit,rand_limit)
- pixel_y += ((At.y - loc.y) * 32) + rand(-rand_limit,rand_limit)
-
-/image/motion_echo/proc/append_client(var/datum/weakref/C)
- var/client/CW = C?.resolve()
- if(CW)
- CW.images += src
- clients.Add(C)
-
-/image/motion_echo/Destroy(force)
- . = ..()
- for(var/datum/weakref/C in clients)
- var/client/CW = C?.resolve()
- if(CW)
- CW.images -= src
diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index 50ef7ee243..a5c3204dc3 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -8,407 +8,132 @@ Brief flashes of fire/space/bombs/c4/dangerous shit (done)
Items that are rare/traitorous/don't exist appearing in your inventory slots (done)
Strange audio (should be rare) (done)
Gunshots/explosions/opening doors/less rare audio (done)
-
*/
-/mob/living/carbon/var
- image/halimage
- image/halbody
- obj/halitem
- hal_screwyhud = 0 //1 - critical, 2 - dead, 3 - oxygen indicator, 4 - toxin indicator
- handling_hal = 0
- hal_crit = 0
+/datum/component/hallucinations
+ dupe_mode = COMPONENT_DUPE_UNIQUE // First come first serve
-/mob/living/carbon/proc/handle_hallucinations()
- if(handling_hal) return
- handling_hal = 1
- while(client && hallucination > 20)
- sleep(rand(200,500)/(hallucination/25))
- var/halpick = rand(1,100)
- switch(halpick)
- if(0 to 15)
- //Screwy HUD
- //to_chat(src, "Screwy HUD")
- hal_screwyhud = pick(1,2,3,3,4,4)
- spawn(rand(100,250))
- hal_screwyhud = 0
- if(16 to 25)
- //Strange items
- //to_chat(src, "Traitor Items")
- if(!halitem)
- halitem = new
- var/list/slots_free = list(ui_lhand,ui_rhand)
- if(l_hand) slots_free -= ui_lhand
- if(r_hand) slots_free -= ui_rhand
- if(ishuman(src))
- var/mob/living/carbon/human/H = src
- if(!H.belt) slots_free += ui_belt
- if(!H.l_store) slots_free += ui_storage1
- if(!H.r_store) slots_free += ui_storage2
- if(slots_free.len)
- halitem.screen_loc = pick(slots_free)
- halitem.hud_layerise()
- switch(rand(1,6))
- if(1) //revolver
- halitem.icon = 'icons/obj/gun.dmi'
- halitem.icon_state = "revolver"
- halitem.name = "Revolver"
- if(2) //c4
- halitem.icon = 'icons/obj/assemblies.dmi'
- halitem.icon_state = "plastic-explosive0"
- halitem.name = "Mysterious Package"
- if(prob(25))
- halitem.icon_state = "c4small_1"
- if(3) //sword
- halitem.icon = 'icons/obj/weapons.dmi'
- halitem.icon_state = "sword1"
- halitem.name = "Sword"
- if(4) //stun baton
- halitem.icon = 'icons/obj/weapons.dmi'
- halitem.icon_state = "stunbaton"
- halitem.name = "Stun Baton"
- if(5) //emag
- halitem.icon = 'icons/obj/card.dmi'
- halitem.icon_state = "emag"
- halitem.name = "Cryptographic Sequencer"
- if(6) //flashbang
- halitem.icon = 'icons/obj/grenade.dmi'
- halitem.icon_state = "flashbang1"
- halitem.name = "Flashbang"
- if(client) client.screen += halitem
- spawn(rand(100,250))
- if(client)
- client.screen -= halitem
- halitem = null
- if(26 to 40)
- //Flashes of danger
- //to_chat(src, "Danger Flash")
- if(!halimage)
- var/list/possible_points = list()
- for(var/turf/simulated/floor/F in view(src,world.view))
- possible_points += F
- if(possible_points.len)
- var/turf/simulated/floor/target = pick(possible_points)
+ VAR_PRIVATE/mob/living/carbon/human/our_human = null
+ VAR_PRIVATE/datum/weakref/halimage
+ VAR_PRIVATE/datum/weakref/halbody
+ VAR_PRIVATE/list/halitem = list() // weakref pair of obj-key, client-value
- switch(rand(1,3))
- if(1)
- //to_chat(src, "Space")
- halimage = image('icons/turf/space.dmi',target,"[rand(1,25)]",TURF_LAYER)
- if(2)
- //to_chat(src, "Fire")
- halimage = image('icons/effects/fire.dmi',target,"1",TURF_LAYER)
- if(3)
- //to_chat(src, "C4")
- halimage = image('icons/obj/assemblies.dmi',target,"plastic-explosive2",OBJ_LAYER+0.01)
+ VAR_PRIVATE/hal_crit = FALSE
+ VAR_PRIVATE/hal_screwyhud = HUD_HALLUCINATION_NONE
+/datum/component/hallucinations/Initialize()
+ if(!ishuman(parent))
+ return COMPONENT_INCOMPATIBLE
+ our_human = parent
+ make_timer()
- if(client) client.images += halimage
- spawn(rand(10,50)) //Only seen for a brief moment.
- if(client) client.images -= halimage
- halimage = null
-
-
- if(41 to 65)
- //Strange audio
- //to_chat(src, "Strange Audio")
- switch(rand(1,12))
- if(1) src << 'sound/machines/door/old_airlock.ogg'
- if(2)
- if(prob(50))src << 'sound/effects/Explosion1.ogg'
- else src << 'sound/effects/Explosion2.ogg'
- if(3) src << 'sound/effects/explosionfar.ogg'
- if(4) src << 'sound/effects/Glassbr1.ogg'
- if(5) src << 'sound/effects/Glassbr2.ogg'
- if(6) src << 'sound/effects/Glassbr3.ogg'
- if(7) src << 'sound/machines/twobeep.ogg'
- if(8) src << 'sound/machines/door/windowdoor.ogg'
- if(9)
- //To make it more realistic, I added two gunshots (enough to kill)
- src << 'sound/weapons/Gunshot1.ogg'
- spawn(rand(10,30))
- src << 'sound/weapons/Gunshot2.ogg'
- if(10) src << 'sound/weapons/smash.ogg'
- if(11)
- //Same as above, but with tasers.
- src << 'sound/weapons/Taser.ogg'
- spawn(rand(10,30))
- src << 'sound/weapons/Taser.ogg'
- //Rare audio
- if(12)
-//These sounds are (mostly) taken from Hidden: Source
- var/list/creepyasssounds = list('sound/effects/ghost.ogg', 'sound/effects/ghost2.ogg', 'sound/effects/Heart Beat.ogg', 'sound/effects/screech.ogg',\
- 'sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', 'sound/hallucinations/far_noise.ogg', 'sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg',\
- 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\
- 'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\
- 'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg')
- src << pick(creepyasssounds)
- if(66 to 70)
- //Flashes of danger
- //to_chat(src, "Danger Flash")
- if(!halbody)
- var/list/possible_points = list()
- for(var/turf/simulated/floor/F in view(src,world.view))
- possible_points += F
- if(possible_points.len)
- var/turf/simulated/floor/target = pick(possible_points)
- switch(rand(1,4))
- if(1)
- halbody = image('icons/mob/human.dmi',target,"husk_l",TURF_LAYER)
- if(2,3)
- halbody = image('icons/mob/human.dmi',target,"husk_s",TURF_LAYER)
- if(4)
- halbody = image('icons/mob/alien.dmi',target,"alienother",TURF_LAYER)
- // if(5)
- // halbody = image('xcomalien.dmi',target,"chryssalid",TURF_LAYER)
-
- if(client) client.images += halbody
- spawn(rand(50,80)) //Only seen for a brief moment.
- if(client) client.images -= halbody
- halbody = null
- if(71 to 72)
- //Fake death
-// src.sleeping_willingly = 1
- SetSleeping(20)
- hal_crit = 1
- hal_screwyhud = 1
- spawn(rand(50,100))
-// src.sleeping_willingly = 0
- SetSleeping(0)
- hal_crit = 0
- hal_screwyhud = 0
- handling_hal = 0
-
-
-
-
-/*obj/machinery/proc/mockpanel(list/buttons,start_txt,end_txt,list/mid_txts)
-
- if(!mocktxt)
-
- mocktxt = ""
-
- var/possible_txt = list("Launch Escape Pods","Self-Destruct Sequence","\[Swipe ID\]","De-Monkify",\
- "Reticulate Splines","Plasma","Open Valve","Lockdown","Nerf Airflow","Kill Traitor","Nihilism",\
- "OBJECTION!","Arrest Stephen Bowman","Engage Anti-Trenna Defenses","Increase Site Manager IQ","Retrieve Arms",\
- "Play Charades","Oxygen","Inject BeAcOs","Ninja Lizards","Limit Break","Build Sentry")
-
- if(mid_txts)
- while(mid_txts.len)
- var/mid_txt = pick(mid_txts)
- mocktxt += mid_txt
- mid_txts -= mid_txt
-
- while(buttons.len)
-
- var/button = pick(buttons)
-
- var/button_txt = pick(possible_txt)
-
- mocktxt += "[button_txt]
"
-
- buttons -= button
- possible_txt -= button_txt
-
- return start_txt + mocktxt + end_txt + "