mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-20 19:44:46 +01:00
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 2409e41870.
* 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>
This commit is contained in:
@@ -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 += "<a href='byond://?src=\ref[src];[button]'>[button_txt]</a><br>"
|
||||
|
||||
buttons -= button
|
||||
possible_txt -= button_txt
|
||||
|
||||
return start_txt + mocktxt + end_txt + "</TT></BODY></HTML>"
|
||||
|
||||
/proc/check_panel(mob/M)
|
||||
if (ishuman(M) || isAI(M))
|
||||
if(M.hallucination < 15)
|
||||
return 1
|
||||
return 0*/
|
||||
|
||||
/obj/effect/fake_attacker
|
||||
icon = null
|
||||
icon_state = null
|
||||
name = ""
|
||||
desc = ""
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
opacity = 0
|
||||
var/mob/living/carbon/human/my_target = null
|
||||
var/weapon_name = null
|
||||
var/obj/item/weap = null
|
||||
var/image/stand_icon = null
|
||||
var/image/currentimage = null
|
||||
var/icon/base = null
|
||||
var/s_tone
|
||||
var/mob/living/clone = null
|
||||
var/image/left
|
||||
var/image/right
|
||||
var/image/up
|
||||
var/collapse
|
||||
var/image/down
|
||||
|
||||
var/health = 100
|
||||
|
||||
/obj/effect/fake_attacker/attackby(var/obj/item/P as obj, mob/user as mob)
|
||||
step_away(src,my_target,2)
|
||||
for(var/mob/M in oviewers(world.view,my_target))
|
||||
to_chat(M, span_bolddanger("[my_target] flails around wildly."))
|
||||
my_target.show_message(span_bolddanger("[src] has been attacked by [my_target] "), 1) //Lazy.
|
||||
|
||||
src.health -= P.force
|
||||
|
||||
|
||||
return
|
||||
|
||||
/obj/effect/fake_attacker/Crossed(var/mob/M, somenumber)
|
||||
if(M == my_target)
|
||||
step_away(src,my_target,2)
|
||||
if(prob(30))
|
||||
for(var/mob/O in oviewers(world.view , my_target))
|
||||
to_chat(O, span_bolddanger("[my_target] stumbles around."))
|
||||
|
||||
/obj/effect/fake_attacker/Initialize(mapload)
|
||||
/datum/component/hallucinations/Destroy(force)
|
||||
if(halitem.len)
|
||||
remove_hallucination_item()
|
||||
our_human = null
|
||||
. = ..()
|
||||
QDEL_IN(src, 30 SECONDS)
|
||||
step_away(src,my_target,2)
|
||||
addtimer(CALLBACK(src, PROC_REF(attack_loop)), rand(5, 10), TIMER_DELETE_ME)
|
||||
|
||||
/obj/effect/fake_attacker/Destroy()
|
||||
if(my_target)
|
||||
my_target.hallucinations -= src
|
||||
return ..()
|
||||
/datum/component/hallucinations/proc/make_timer()
|
||||
PROTECTED_PROC(TRUE)
|
||||
addtimer(CALLBACK(src, PROC_REF(trigger)), ((rand(20,50) SECONDS) / (min(our_human.hallucination,100)/25)), TIMER_DELETE_ME)
|
||||
|
||||
/datum/component/hallucinations/proc/get_fakecrit()
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
return hal_crit
|
||||
|
||||
/obj/effect/fake_attacker/proc/updateimage()
|
||||
// qdel(src.currentimage)
|
||||
/datum/component/hallucinations/proc/get_hud_state()
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
return hal_screwyhud
|
||||
|
||||
|
||||
if(src.dir == NORTH)
|
||||
qdel(src.currentimage)
|
||||
src.currentimage = new /image(up,src)
|
||||
else if(src.dir == SOUTH)
|
||||
qdel(src.currentimage)
|
||||
src.currentimage = new /image(down,src)
|
||||
else if(src.dir == EAST)
|
||||
qdel(src.currentimage)
|
||||
src.currentimage = new /image(right,src)
|
||||
else if(src.dir == WEST)
|
||||
qdel(src.currentimage)
|
||||
src.currentimage = new /image(left,src)
|
||||
my_target << currentimage
|
||||
|
||||
|
||||
/obj/effect/fake_attacker/proc/attack_loop()
|
||||
if(src.health < 0)
|
||||
collapse()
|
||||
addtimer(CALLBACK(src, PROC_REF(attack_loop)), rand(5, 10), TIMER_DELETE_ME)
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Traditional hallucinations
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/mob/living/carbon/proc/handle_hallucinations()
|
||||
if(get_hallucination_component() || !client)
|
||||
return
|
||||
if(get_dist(src,my_target) > 1)
|
||||
src.set_dir(get_dir(src,my_target))
|
||||
step_towards(src,my_target)
|
||||
updateimage()
|
||||
else
|
||||
if(prob(15))
|
||||
if(weapon_name)
|
||||
my_target << sound(pick('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg'))
|
||||
my_target.show_message(span_bolddanger("[my_target] has been attacked with [weapon_name] by [src.name]!"), 1)
|
||||
my_target.halloss += 8
|
||||
if(prob(20)) my_target.eye_blurry += 3
|
||||
if(prob(33))
|
||||
if(!locate(/obj/effect/overlay) in my_target.loc)
|
||||
fake_blood(my_target)
|
||||
LoadComponent(/datum/component/hallucinations)
|
||||
|
||||
/mob/living/carbon/proc/get_hallucination_component()
|
||||
RETURN_TYPE(/datum/component/hallucinations)
|
||||
return GetComponent(/datum/component/hallucinations)
|
||||
|
||||
/datum/component/hallucinations/proc/trigger()
|
||||
PROTECTED_PROC(TRUE)
|
||||
if(QDELETED(our_human))
|
||||
qdel(src)
|
||||
return
|
||||
if(!our_human.client)
|
||||
qdel(src)
|
||||
return
|
||||
if(our_human.hallucination < HALLUCINATION_THRESHOLD)
|
||||
qdel(src)
|
||||
return
|
||||
handle_hallucinating()
|
||||
make_timer()
|
||||
|
||||
/datum/component/hallucinations/proc/handle_hallucinating()
|
||||
PROTECTED_PROC(TRUE)
|
||||
var/halpick = rand(1,100)
|
||||
switch(halpick)
|
||||
if(0 to 15)
|
||||
event_hudscrew()
|
||||
if(16 to 25)
|
||||
event_fake_item()
|
||||
if(26 to 40)
|
||||
event_flash_environmental_threats()
|
||||
if(41 to 65)
|
||||
event_strange_sound()
|
||||
if(66 to 70)
|
||||
if(prob(20) && our_human.nutrition < 100)
|
||||
event_hunger() // Hungi, meant for xenochi but this is too funny to pass up
|
||||
else
|
||||
my_target << sound(pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg'))
|
||||
my_target.show_message(span_bolddanger("[src.name] has punched [my_target]!"), 1)
|
||||
my_target.halloss += 4
|
||||
if(prob(33))
|
||||
if(!locate(/obj/effect/overlay) in my_target.loc)
|
||||
fake_blood(my_target)
|
||||
event_flash_monsters()
|
||||
if(71 to 72)
|
||||
event_sleeping()
|
||||
if(73 to 75) // If you don't want hallucination beatdowns, comment this out
|
||||
event_attacker()
|
||||
if(76 to 80)
|
||||
event_painmessage()
|
||||
|
||||
if(prob(15))
|
||||
step_away(src,my_target,2)
|
||||
addtimer(CALLBACK(src, PROC_REF(attack_loop)), rand(5, 10), TIMER_DELETE_ME)
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Xenochimera hallucinations
|
||||
// Unlike normal hallucinations this one is triggered from handle_feral randomly.
|
||||
// So it destroys itself after it triggers, freeing up space for the next run of it.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/datum/component/hallucinations/xenochimera/make_timer()
|
||||
var/datum/component/xenochimera/XC = our_human.GetComponent(/datum/component/xenochimera)
|
||||
var/F = XC ? (XC.feral / 10) : 1
|
||||
addtimer(CALLBACK(src, PROC_REF(trigger)), ((rand(20,50) SECONDS) / F), TIMER_DELETE_ME)
|
||||
|
||||
/obj/effect/fake_attacker/proc/collapse()
|
||||
collapse = 1
|
||||
updateimage()
|
||||
|
||||
/proc/fake_blood(var/mob/target)
|
||||
var/obj/effect/overlay/O = new/obj/effect/overlay(target.loc)
|
||||
O.name = "blood"
|
||||
var/image/I = image('icons/effects/blood.dmi',O,"floor[rand(1,7)]",O.dir,1)
|
||||
target << I
|
||||
QDEL_IN(O, 30 SECONDS)
|
||||
|
||||
var/list/non_fakeattack_weapons = list(/obj/item/gun/projectile, /obj/item/ammo_magazine/s357,\
|
||||
/obj/item/gun/energy/crossbow, /obj/item/melee/energy/sword,\
|
||||
/obj/item/storage/box/syndicate, /obj/item/storage/box/emps,\
|
||||
/obj/item/cartridge/syndicate, /obj/item/clothing/under/chameleon,\
|
||||
/obj/item/clothing/shoes/syndigaloshes, /obj/item/card/id/syndicate,\
|
||||
/obj/item/clothing/mask/gas/voice, /obj/item/clothing/glasses/thermal,\
|
||||
/obj/item/chameleon, /obj/item/card/emag,\
|
||||
/obj/item/storage/toolbox/syndicate, /obj/item/aiModule,\
|
||||
/obj/item/radio/headset/syndicate, /obj/item/plastique,\
|
||||
/obj/item/powersink, /obj/item/storage/box/syndie_kit,\
|
||||
/obj/item/toy/syndicateballoon, /obj/item/gun/energy/captain,\
|
||||
/obj/item/hand_tele, /obj/item/rcd, /obj/item/tank/jetpack,\
|
||||
/obj/item/clothing/under/rank/captain, /obj/item/aicard,\
|
||||
/obj/item/clothing/shoes/magboots, /obj/item/areaeditor/blueprints, /obj/item/disk/nuclear,\
|
||||
/obj/item/clothing/suit/space/void, /obj/item/tank)
|
||||
|
||||
/proc/fake_attack(var/mob/living/target)
|
||||
var/list/possible_clones = new/list()
|
||||
var/mob/living/carbon/human/clone = null
|
||||
var/clone_weapon = null
|
||||
|
||||
for(var/mob/living/carbon/human/H in living_mob_list)
|
||||
if(H.stat || H.lying)
|
||||
continue
|
||||
possible_clones += H
|
||||
// clone = H
|
||||
// break //changed the code a bit. Less randomised, but less work to do. Should be ok, world.contents aren't stored in any particular order.
|
||||
|
||||
if(!possible_clones.len)
|
||||
/datum/component/hallucinations/xenochimera/trigger()
|
||||
if(QDELETED(our_human))
|
||||
qdel(src)
|
||||
return
|
||||
clone = pick(possible_clones)
|
||||
if(!clone)
|
||||
if(!our_human.client)
|
||||
qdel(src)
|
||||
return
|
||||
var/datum/component/xenochimera/XC = our_human.GetComponent(/datum/component/xenochimera)
|
||||
if(!XC || XC.feral < XENOCHIFERAL_THRESHOLD)
|
||||
qdel(src)
|
||||
return
|
||||
handle_hallucinating()
|
||||
QDEL_IN(src,rand(3,9)SECONDS)
|
||||
|
||||
//var/obj/effect/fake_attacker/F = new/obj/effect/fake_attacker(outside_range(target))
|
||||
var/obj/effect/fake_attacker/F = new/obj/effect/fake_attacker(target.loc)
|
||||
if(clone.l_hand)
|
||||
if(!(locate(clone.l_hand) in non_fakeattack_weapons))
|
||||
clone_weapon = clone.l_hand.name
|
||||
F.weap = clone.l_hand
|
||||
else if (clone.r_hand)
|
||||
if(!(locate(clone.r_hand) in non_fakeattack_weapons))
|
||||
clone_weapon = clone.r_hand.name
|
||||
F.weap = clone.r_hand
|
||||
|
||||
F.name = clone.name
|
||||
F.my_target = target
|
||||
F.weapon_name = clone_weapon
|
||||
target.hallucinations += F
|
||||
|
||||
|
||||
F.left = image(clone,dir = WEST)
|
||||
F.right = image(clone,dir = EAST)
|
||||
F.up = image(clone,dir = NORTH)
|
||||
F.down = image(clone,dir = SOUTH)
|
||||
|
||||
// F.base = new /icon(clone.stand_icon)
|
||||
// F.currentimage = new /image(clone)
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
F.left = new /icon(clone.stand_icon,dir=WEST)
|
||||
for(var/icon/i in clone.overlays)
|
||||
F.left.Blend(i)
|
||||
F.up = new /icon(clone.stand_icon,dir=NORTH)
|
||||
for(var/icon/i in clone.overlays)
|
||||
F.up.Blend(i)
|
||||
F.down = new /icon(clone.stand_icon,dir=SOUTH)
|
||||
for(var/icon/i in clone.overlays)
|
||||
F.down.Blend(i)
|
||||
F.right = new /icon(clone.stand_icon,dir=EAST)
|
||||
for(var/icon/i in clone.overlays)
|
||||
F.right.Blend(i)
|
||||
|
||||
target << F.up
|
||||
*/
|
||||
|
||||
F.updateimage()
|
||||
/datum/component/hallucinations/xenochimera/handle_hallucinating()
|
||||
var/halpick = rand(1,100)
|
||||
switch(halpick)
|
||||
if(0 to 15) //15% chance
|
||||
//Screwy HUD
|
||||
event_hudscrew()
|
||||
if(16 to 25) //10% chance
|
||||
event_fake_item()
|
||||
if(26 to 35) //10% chance
|
||||
event_flash_environmental_threats()
|
||||
if(36 to 55) //20% chance
|
||||
event_strange_sound()
|
||||
if(56 to 60) //5% chance
|
||||
event_flash_monsters()
|
||||
if(61 to 85) //25% chance
|
||||
event_hunger()
|
||||
if(86 to 100) //15% chance
|
||||
event_hear_voices()
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
/obj/effect/fake_attacker // I did want to use /image/client_only but this needs to be somewhat more complex
|
||||
name = ""
|
||||
desc = ""
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
opacity = 0
|
||||
VAR_PRIVATE/list/clients = list()
|
||||
VAR_PRIVATE/list/image/dir_images = list()
|
||||
|
||||
/obj/effect/fake_attacker/process()
|
||||
. = ..()
|
||||
// Passive cleanup
|
||||
for(var/datum/weakref/C in clients)
|
||||
var/client/CW = C?.resolve()
|
||||
if(isnull(CW))
|
||||
clients.Remove(C)
|
||||
if(!clients.len)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/fake_attacker/set_dir(newdir)
|
||||
if(!(newdir in GLOB.cardinal))
|
||||
newdir &= ~(EAST|WEST) // Don't allow diagonals, prefer north/south
|
||||
if(!newdir)
|
||||
newdir = SOUTH
|
||||
var/updatesprite = (dir != newdir)
|
||||
. = ..()
|
||||
if(updatesprite)
|
||||
for(var/datum/weakref/C in clients)
|
||||
var/client/CW = C?.resolve()
|
||||
clear_images_from_client(CW)
|
||||
assign_image_to_client(CW)
|
||||
|
||||
/obj/effect/fake_attacker/Moved(atom/old_loc, direction, forced, movetime)
|
||||
. = ..()
|
||||
var/turf_move = isturf(loc) && isturf(old_loc)
|
||||
for(var/img in dir_images)
|
||||
var/image/G = dir_images[img]
|
||||
G.loc = loc
|
||||
if(turf_move)
|
||||
var/MT = 0.7 SECONDS
|
||||
G.pixel_x = (old_loc.x - loc.x) * WORLD_ICON_SIZE
|
||||
G.pixel_y = (old_loc.y - loc.y) * WORLD_ICON_SIZE
|
||||
animate(G, pixel_x = 0, time = MT, flags = ANIMATION_PARALLEL)
|
||||
animate(G, pixel_y = 0, time = MT, flags = ANIMATION_PARALLEL)
|
||||
|
||||
/obj/effect/fake_attacker/Destroy(force)
|
||||
. = ..()
|
||||
clear_every_clients_images()
|
||||
qdel_all_images()
|
||||
|
||||
/obj/effect/fake_attacker/proc/create_images_from(var/atom/clone)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
dir_images["[NORTH]"] = image(clone,dir = NORTH)
|
||||
dir_images["[SOUTH]"] = image(clone,dir = SOUTH)
|
||||
dir_images["[EAST]"] = image(clone,dir = EAST)
|
||||
dir_images["[WEST]"] = image(clone,dir = WEST)
|
||||
for(var/img in dir_images)
|
||||
var/image/G = dir_images[img]
|
||||
G.layer = clone.layer
|
||||
G.plane = clone.plane
|
||||
G.appearance_flags = clone.appearance_flags
|
||||
G.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
G.loc = loc
|
||||
|
||||
/obj/effect/fake_attacker/proc/append_client(var/client/C)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
clients.Add(WEAKREF(C))
|
||||
assign_image_to_client(C)
|
||||
|
||||
/obj/effect/fake_attacker/proc/assign_image_to_client(var/client/C)
|
||||
PRIVATE_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
if(!C)
|
||||
return
|
||||
if(!dir_images.len)
|
||||
return
|
||||
var/image/I = dir_images["[dir]"]
|
||||
if(I)
|
||||
C.images += I
|
||||
|
||||
/obj/effect/fake_attacker/proc/clear_every_clients_images()
|
||||
for(var/datum/weakref/C in clients)
|
||||
clear_images_from_client(C?.resolve())
|
||||
|
||||
/obj/effect/fake_attacker/proc/clear_images_from_client(var/client/C)
|
||||
PRIVATE_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
if(!C)
|
||||
return
|
||||
if(!dir_images.len)
|
||||
return
|
||||
for(var/img in dir_images)
|
||||
C.images -= dir_images[img]
|
||||
|
||||
/obj/effect/fake_attacker/proc/qdel_all_images()
|
||||
PRIVATE_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
for(var/img in dir_images)
|
||||
qdel_null(dir_images[img])
|
||||
dir_images.Cut()
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Hallucination attackers with AI behaviors
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/mob/proc/create_hallucination_attacker(var/turf/T = null,var/mob/living/carbon/human/clone = null, var/forced_type = null)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
if(!client)
|
||||
return null
|
||||
|
||||
if(!clone)
|
||||
// Get a randomized clone from the living mob's list, must be standing
|
||||
var/list/possible_clones = new/list()
|
||||
for(var/mob/living/carbon/human/H in living_mob_list)
|
||||
if(H.stat || H.lying)
|
||||
continue
|
||||
possible_clones += H
|
||||
if(!possible_clones.len)
|
||||
return null
|
||||
clone = pick(possible_clones)
|
||||
if(!clone)
|
||||
return null
|
||||
|
||||
if(!T)
|
||||
// Get the target's turf, then make some random steps to get away from them, respecting walls
|
||||
T = get_turf(clone)
|
||||
var/turf/CT = T
|
||||
for(var/i = 0 to 8)
|
||||
var/Cdir = pick(GLOB.cardinal)
|
||||
if(prob(30))
|
||||
Cdir = clone.dir // Results in hallucinations somewhat being in front of you
|
||||
var/turf/NT = get_step(CT,Cdir)
|
||||
if(!NT.density)
|
||||
CT = NT
|
||||
T = CT
|
||||
|
||||
if(!forced_type)
|
||||
// Picking from all available options
|
||||
var/list/get_types = subtypesof(/obj/effect/fake_attacker/human)
|
||||
forced_type = pick(get_types)
|
||||
// Finally! After a thousand years I'm finally free to conquer EARTH!
|
||||
return new forced_type(T,src,clone)
|
||||
|
||||
/obj/effect/fake_attacker/human
|
||||
VAR_PROTECTED/datum/weakref/target = null
|
||||
var/requires_hallucinating = TRUE // Mob will qdel if the target is not hallucinating if this is true
|
||||
|
||||
/obj/effect/fake_attacker/human/Initialize(mapload,var/mob/targeting_mob,var/atom/clone_appearance_from)
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
set_target(targeting_mob)
|
||||
create_images_from(clone_appearance_from)
|
||||
append_client(targeting_mob.client)
|
||||
name = clone_appearance_from.name
|
||||
// Usually we want to face our target for maximum spooky effect
|
||||
set_dir(get_dir(src,targeting_mob))
|
||||
|
||||
/obj/effect/fake_attacker/human/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/fake_attacker/human/process()
|
||||
// check if valid
|
||||
var/mob/living/M = target?.resolve()
|
||||
if(!M)
|
||||
qdel(src)
|
||||
return null
|
||||
if(requires_hallucinating)
|
||||
if(!ishuman(M))
|
||||
qdel(src)
|
||||
return null
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(!H.hallucination)
|
||||
qdel(src)
|
||||
return null
|
||||
|
||||
return M
|
||||
|
||||
/obj/effect/fake_attacker/human/proc/set_target(var/mob/M)
|
||||
target = WEAKREF(M)
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Attacker: Performs hostile shoves and attacks
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/obj/effect/fake_attacker/human/attacker/process()
|
||||
var/mob/living/M = ..()
|
||||
|
||||
if(get_dist(src,M) > 1)
|
||||
step_towards(src,M)
|
||||
|
||||
else if(prob(15))
|
||||
M << sound(pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg'))
|
||||
M.show_message(span_bolddanger("\The [src] has punched \the [M]!"), 1)
|
||||
M.halloss += 4
|
||||
|
||||
if(prob(15))
|
||||
step_away(src,M)
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Fleeing: Runs away when you get close
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/obj/effect/fake_attacker/human/fleeing
|
||||
VAR_PRIVATE/flee = FALSE
|
||||
|
||||
/obj/effect/fake_attacker/human/fleeing/process()
|
||||
var/mob/living/M = ..()
|
||||
set_dir(get_dir(src,M))
|
||||
|
||||
if(get_dist(src,M) < 6 || flee)
|
||||
flee = TRUE
|
||||
step_away(src,M)
|
||||
|
||||
if(get_dist(src,M) > 10 || get_dist(src,M) < 2 || (flee && prob(10)))
|
||||
target = null
|
||||
qdel(src)
|
||||
@@ -0,0 +1,302 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Hallucination events
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/datum/component/hallucinations/proc/event_hudscrew()
|
||||
PROTECTED_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
//Screwy HUD
|
||||
//to_chat(our_human, "Screwy HUD")
|
||||
hal_screwyhud = pick(list(
|
||||
HUD_HALLUCINATION_CRIT,
|
||||
HUD_HALLUCINATION_TOXIN,
|
||||
HUD_HALLUCINATION_OXY,
|
||||
HUD_HALLUCINATION_ONFIRE
|
||||
))
|
||||
VARSET_IN(src, hal_screwyhud, HUD_HALLUCINATION_NONE, rand(15,35) SECONDS)
|
||||
|
||||
/datum/component/hallucinations/proc/event_painmessage()
|
||||
PROTECTED_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
//Fake pain messages
|
||||
//to_chat(our_human, "fake messages")
|
||||
var/list/pain_message = list("The inside of your head hurts...",
|
||||
"Your stomach hurts.",
|
||||
"You feel sick.",
|
||||
"Your upper body hurts.",
|
||||
"Your head hurts.",
|
||||
"Your arm hurts.",
|
||||
"Your leg hurts.",
|
||||
"Your lower body hurts.",
|
||||
"Your foot hurts.",
|
||||
"Your hand hurts.",
|
||||
"The pain is excruciating!",
|
||||
"Your whole body is going numb!",
|
||||
"You feel like you could die any moment now!",
|
||||
"Please, just end the pain!",
|
||||
"You feel a sudden pain across your body.",
|
||||
"You cringe as a violent pain takes over your body.",
|
||||
"It feels like your body is eating itself inside out.",
|
||||
"IT HURTS.",
|
||||
"Your body feels as if it's trying to rip itself open..."
|
||||
)
|
||||
if(prob(20) && our_human.jitteriness < 50)
|
||||
our_human.make_jittery(120)
|
||||
to_chat(our_human, span_danger(pick(pain_message)))
|
||||
|
||||
/datum/component/hallucinations/proc/event_fake_item()
|
||||
PROTECTED_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
//Strange items
|
||||
//to_chat(our_human, "Traitor Items")
|
||||
if(halitem.len)
|
||||
return
|
||||
|
||||
var/list/slots_free = list(ui_lhand,ui_rhand)
|
||||
if(our_human.l_hand)
|
||||
slots_free -= ui_lhand
|
||||
if(our_human.r_hand)
|
||||
slots_free -= ui_rhand
|
||||
if(!our_human.belt)
|
||||
slots_free += ui_belt
|
||||
if(!our_human.l_store)
|
||||
slots_free += ui_storage1
|
||||
if(!our_human.r_store)
|
||||
slots_free += ui_storage2
|
||||
|
||||
if(!slots_free.len)
|
||||
return
|
||||
|
||||
var/obj/CI = new()
|
||||
CI.screen_loc = pick(slots_free)
|
||||
CI.hud_layerise()
|
||||
switch(rand(1,6))
|
||||
if(1) //revolver
|
||||
CI.icon = 'icons/obj/gun.dmi'
|
||||
CI.icon_state = "revolver"
|
||||
CI.name = "Revolver"
|
||||
if(2) //c4
|
||||
CI.icon = 'icons/obj/assemblies.dmi'
|
||||
CI.icon_state = "plastic-explosive0"
|
||||
CI.name = "Mysterious Package"
|
||||
if(prob(25))
|
||||
CI.icon_state = "c4small_1"
|
||||
if(3) //sword
|
||||
CI.icon = 'icons/obj/weapons.dmi'
|
||||
CI.icon_state = "longsword"
|
||||
CI.name = "Sword"
|
||||
if(4) //stun baton
|
||||
CI.icon = 'icons/obj/weapons.dmi'
|
||||
CI.icon_state = "stunbaton"
|
||||
CI.name = "Stun Baton"
|
||||
if(5) //emag
|
||||
CI.icon = 'icons/obj/card.dmi'
|
||||
CI.icon_state = "emag"
|
||||
CI.name = "Cryptographic Sequencer"
|
||||
if(6) //flashbang
|
||||
CI.icon = 'icons/obj/grenade.dmi'
|
||||
CI.icon_state = "flashbang1"
|
||||
CI.name = "Flashbang"
|
||||
halitem[WEAKREF(CI)] = WEAKREF(our_human.client)
|
||||
our_human.client.screen += CI
|
||||
addtimer(CALLBACK(src, PROC_REF(remove_hallucination_item)), rand(10,25) SECONDS, TIMER_DELETE_ME)
|
||||
|
||||
/datum/component/hallucinations/proc/remove_hallucination_item()
|
||||
// I can't manage this with /image/client_only due to screenloc, so key-value weakref pair it is! Called on both timer and destroying this component.
|
||||
PRIVATE_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
var/datum/weakref/first = halitem[1]
|
||||
var/obj/itm = first?.resolve()
|
||||
var/datum/weakref/CW = halitem[first]
|
||||
var/client/C = CW?.resolve()
|
||||
C.screen -= itm
|
||||
qdel(itm)
|
||||
halitem.Cut()
|
||||
|
||||
/datum/component/hallucinations/proc/event_strange_sound()
|
||||
PROTECTED_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
|
||||
//Strange audio
|
||||
var/send_sound
|
||||
switch(rand(1,12))
|
||||
if(1)
|
||||
send_sound = 'sound/machines/door/old_airlock.ogg'
|
||||
if(2)
|
||||
if(prob(50))
|
||||
send_sound = 'sound/effects/Explosion1.ogg'
|
||||
else
|
||||
send_sound = 'sound/effects/Explosion2.ogg'
|
||||
if(3)
|
||||
send_sound = 'sound/effects/explosionfar.ogg'
|
||||
if(4)
|
||||
send_sound = 'sound/effects/Glassbr1.ogg'
|
||||
if(5)
|
||||
send_sound = 'sound/effects/Glassbr2.ogg'
|
||||
if(6)
|
||||
send_sound = 'sound/effects/Glassbr3.ogg'
|
||||
if(7)
|
||||
send_sound = 'sound/machines/twobeep.ogg'
|
||||
if(8)
|
||||
send_sound = 'sound/machines/door/windowdoor.ogg'
|
||||
if(9)
|
||||
//To make it more realistic, I added two gunshots (enough to kill)
|
||||
send_sound = 'sound/weapons/Gunshot1.ogg'
|
||||
addtimer(CALLBACK(src, PROC_REF(secondary_sound), 'sound/weapons/Gunshot2.ogg'), rand(1,3) SECONDS, TIMER_DELETE_ME)
|
||||
if(10)
|
||||
send_sound = 'sound/weapons/smash.ogg'
|
||||
if(11)
|
||||
//Same as above, but with tasers.
|
||||
send_sound = 'sound/weapons/Taser.ogg'
|
||||
addtimer(CALLBACK(src, PROC_REF(secondary_sound), 'sound/weapons/Taser.ogg'), rand(1,3) SECONDS, TIMER_DELETE_ME)
|
||||
//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')
|
||||
send_sound = pick(creepyasssounds)
|
||||
|
||||
our_human.playsound_local(get_turf(our_human), send_sound, vol = 75, channel = CHANNEL_AMBIENCE_FORCED)
|
||||
|
||||
/datum/component/hallucinations/proc/secondary_sound(var/sound_path)
|
||||
PRIVATE_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
our_human.playsound_local(get_turf(our_human), sound_path, vol = 75, channel = CHANNEL_AMBIENCE_FORCED)
|
||||
|
||||
/datum/component/hallucinations/proc/event_flash_environmental_threats()
|
||||
PROTECTED_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
//Flashes of danger
|
||||
//to_chat(our_human, "Danger Flash")
|
||||
if(halimage?.resolve())
|
||||
return
|
||||
|
||||
var/list/possible_points = list()
|
||||
for(var/turf/simulated/floor/F in view(our_human,world.view))
|
||||
possible_points += F
|
||||
if(!possible_points.len)
|
||||
return
|
||||
|
||||
var/turf/simulated/floor/target = pick(possible_points)
|
||||
var/image/client_only/CI
|
||||
switch(rand(1,3))
|
||||
if(1)
|
||||
//to_chat(our_human, "Space")
|
||||
CI = new('icons/turf/space.dmi',target,"[rand(1,25)]",TURF_LAYER)
|
||||
if(2)
|
||||
//to_chat(our_human, "Fire")
|
||||
CI = new('icons/effects/fire.dmi',target,"1",TURF_LAYER)
|
||||
if(3)
|
||||
//to_chat(our_human, "C4")
|
||||
CI = new('icons/obj/assemblies.dmi',target,"plastic-explosive2",OBJ_LAYER+0.01)
|
||||
halimage = WEAKREF(CI)
|
||||
CI.append_client(our_human.client)
|
||||
QDEL_IN(CI, rand(1,5) SECONDS) //Only seen for a brief moment.
|
||||
|
||||
/datum/component/hallucinations/proc/event_flash_monsters()
|
||||
PROTECTED_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
//Flashes of danger
|
||||
//to_chat(our_human, "Danger Flash")
|
||||
if(halbody?.resolve())
|
||||
return
|
||||
|
||||
var/list/possible_points = list()
|
||||
for(var/turf/simulated/floor/F in view(our_human,world.view))
|
||||
possible_points += F
|
||||
if(!possible_points.len)
|
||||
return
|
||||
|
||||
var/turf/simulated/floor/target = pick(possible_points)
|
||||
var/image/client_only/CI
|
||||
switch(rand(1,4))
|
||||
if(1)
|
||||
CI = new('icons/mob/human.dmi',target,"husk_l",TURF_LAYER)
|
||||
if(2,3)
|
||||
CI = new('icons/mob/human.dmi',target,"husk_s",TURF_LAYER)
|
||||
if(4)
|
||||
CI = new('icons/mob/alien.dmi',target,"alienother",TURF_LAYER)
|
||||
// if(5)
|
||||
// CI = new('xcomalien.dmi',target,"chryssalid",TURF_LAYER)
|
||||
halbody = WEAKREF(CI)
|
||||
CI.append_client(our_human.client)
|
||||
QDEL_IN(CI, rand(5,8) SECONDS) //Only seen for a brief moment.
|
||||
|
||||
/datum/component/hallucinations/proc/event_sleeping()
|
||||
PROTECTED_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
//Fake death
|
||||
//to_chat(our_human, "fake death")
|
||||
our_human.SetSleeping(20)
|
||||
hal_crit = TRUE
|
||||
hal_screwyhud = HUD_HALLUCINATION_CRIT
|
||||
addtimer(CALLBACK(src, PROC_REF(reset_hallucination_sleeping)), rand(5,10) SECONDS, TIMER_DELETE_ME)
|
||||
|
||||
/datum/component/hallucinations/proc/reset_hallucination_sleeping()
|
||||
PRIVATE_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
our_human.SetSleeping(0)
|
||||
hal_crit = FALSE
|
||||
hal_screwyhud = HUD_HALLUCINATION_NONE
|
||||
|
||||
/datum/component/hallucinations/proc/event_attacker()
|
||||
PROTECTED_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
var/attacker = our_human.create_hallucination_attacker(forced_type = /obj/effect/fake_attacker/human/attacker) // Currently just uses the attacker type for now, remove argument to use any other subtype
|
||||
if(attacker)
|
||||
QDEL_IN(attacker, rand(25,30) SECONDS)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Xenochimera feral events
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/datum/component/hallucinations/proc/event_hunger()
|
||||
PROTECTED_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
//food
|
||||
if(halbody?.resolve())
|
||||
return
|
||||
|
||||
var/list/possible_points = list()
|
||||
for(var/turf/simulated/floor/F in view(our_human,world.view))
|
||||
possible_points += F
|
||||
if(!possible_points.len)
|
||||
return
|
||||
|
||||
var/turf/simulated/floor/target = pick(possible_points)
|
||||
var/image/client_only/CI
|
||||
switch(rand(1,10))
|
||||
if(1)
|
||||
CI = new('icons/mob/animal.dmi',target,"cow",TURF_LAYER)
|
||||
if(2)
|
||||
CI = new('icons/mob/animal.dmi',target,"chicken",TURF_LAYER)
|
||||
if(3)
|
||||
CI = new('icons/obj/food.dmi',target,"bigbiteburger",TURF_LAYER)
|
||||
if(4)
|
||||
CI = new('icons/obj/food.dmi',target,"meatbreadslice",TURF_LAYER)
|
||||
if(5)
|
||||
CI = new('icons/obj/food.dmi',target,"sausage",TURF_LAYER)
|
||||
if(6)
|
||||
CI = new('icons/obj/food.dmi',target,"bearmeat",TURF_LAYER)
|
||||
if(7)
|
||||
CI = new('icons/obj/food.dmi',target,"fishfillet",TURF_LAYER)
|
||||
if(8)
|
||||
CI = new('icons/obj/food.dmi',target,"meat",TURF_LAYER)
|
||||
if(9)
|
||||
CI = new('icons/obj/food.dmi',target,"meatstake",TURF_LAYER)
|
||||
if(10)
|
||||
CI = new('icons/obj/food.dmi',target,"monkeysdelight",TURF_LAYER)
|
||||
|
||||
halbody = WEAKREF(CI)
|
||||
CI.append_client(our_human.client)
|
||||
QDEL_IN(CI, rand(5,8) SECONDS) //Only seen for a brief moment.
|
||||
|
||||
/datum/component/hallucinations/proc/event_hear_voices()
|
||||
PROTECTED_PROC(TRUE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
//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(our_human, span_game(span_say(span_name(pick(hiddenspeakers)) + " [pick(speakerverbs)], \"[pick(spookyphrases)]\"")))
|
||||
Reference in New Issue
Block a user