diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index e3aa865a141..0c1b40f9ce0 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -176,30 +176,296 @@ Gunshots/explosions/opening doors/less rare audio (done)
src.sleeping = 0
hal_crit = 0
hal_screwyhud = 0
- if(73 to 75)
- fake_attack()
+ if(73 to 75) //severe hallucinations
+ hallucinate(pick("fake","flood","xeno","singulo","delusion","battle"))
handling_hal = 0
+/obj/effect/hallucination
+ invisibility = INVISIBILITY_OBSERVER
+ var/mob/living/carbon/target = null
-/mob/living/carbon/proc/fake_attack()
-// var/list/possible_clones = new/list()
+/obj/effect/hallucination/simple
+ var/image_icon = 'icons/mob/alien.dmi'
+ var/image_state = "alienh_pounce"
+ var/px = 0
+ var/py = 0
+ var/col_mod = null
+ var/image/current_image = null
+ var/image_layer = MOB_LAYER
+ var/active = 1 //qdelery
+
+/obj/effect/hallucination/simple/New(loc,var/mob/living/carbon/T)
+ target = T
+ current_image = GetImage()
+ if(target.client) target.client.images |= current_image
+ return
+
+/obj/effect/hallucination/simple/proc/GetImage()
+ var/image/I = image(image_icon,loc,image_state,image_layer,dir=src.dir)
+ I.pixel_x = px
+ I.pixel_y = py
+ if(col_mod)
+ I.color = col_mod
+ return I
+
+/obj/effect/hallucination/simple/proc/Show(var/update=1)
+ if(active)
+ if(target.client) target.client.images.Remove(current_image)
+ if(update)
+ current_image = GetImage()
+ if(target.client) target.client.images |= current_image
+
+/obj/effect/hallucination/simple/update_icon(var/new_state,var/new_icon,var/new_px=0,var/new_py=0)
+ image_state = new_state
+ if(new_icon)
+ image_icon = new_icon
+ else
+ image_icon = initial(image_icon)
+ px = new_px
+ py = new_py
+ Show()
+
+/obj/effect/hallucination/simple/Moved(atom/OldLoc, Dir)
+ Show()
+ return
+
+/obj/effect/hallucination/simple/Destroy()
+ if(target.client) target.client.images.Remove(current_image)
+ active = 0
+
+#define FAKE_FLOOD_EXPAND_TIME 30
+#define FAKE_FLOOD_MAX_RADIUS 7
+
+/obj/effect/hallucination/fake_flood
+ //Plasma/N2O starts flooding from the nearby vent
+ var/list/flood_images = list()
+ var/list/turf/flood_turfs = list()
+ var/image_icon = 'icons/effects/tile_effects.dmi'
+ var/image_state = "plasma"
+ var/radius = 0
+ var/next_expand = 0
+
+/obj/effect/hallucination/fake_flood/New(loc,var/mob/living/carbon/T)
+ ..()
+ target = T
+ for(var/obj/machinery/atmospherics/unary/vent_pump/U in orange(7,target))
+ if(!U.welded)
+ src.loc = U.loc
+ break
+ image_state = pick("plasma","sleeping_agent")
+ flood_images += image(image_icon,src,image_state,MOB_LAYER)
+ flood_turfs += get_turf(loc)
+ if(target.client) target.client.images |= flood_images
+ next_expand = world.time + FAKE_FLOOD_EXPAND_TIME
+ SSobj.processing |= src
+
+/obj/effect/hallucination/fake_flood/process()
+ if(next_expand <= world.time)
+ radius += 1
+ if(radius > FAKE_FLOOD_MAX_RADIUS)
+ qdel(src)
+ Expand()
+ next_expand = world.time + FAKE_FLOOD_EXPAND_TIME
+ return
+
+/obj/effect/hallucination/fake_flood/proc/Expand()
+ for(var/turf/T in circlerangeturfs(loc,radius)) //Todo : Make it do actual flood
+ if((T in flood_turfs)|| T.blocks_air)
+ continue
+ flood_images += image(image_icon,T,image_state,MOB_LAYER)
+ flood_turfs += T
+ if(target.client) target.client.images |= flood_images
+ return
+
+/obj/effect/hallucination/fake_flood/Destroy()
+ SSobj.processing.Remove(src)
+ del(flood_turfs)
+ if(target.client) target.client.images.Remove(flood_images)
+ target = null
+ del(flood_images)
+ return
+
+/obj/effect/hallucination/simple/xeno
+ image_icon = 'icons/mob/alien.dmi'
+ image_state = "alienh_pounce"
+
+/obj/effect/hallucination/simple/xeno/New(loc,var/mob/living/carbon/T)
+ ..()
+ name = "alien hunter ([rand(1, 1000)])"
+ return
+
+/obj/effect/hallucination/simple/xeno/throw_at(atom/target, range, speed) // TODO : Make diagonal trhow into proc/property
+ if(!target || !src || (flags & NODROP)) return 0
+
+ src.throwing = 1
+
+ var/dist_x = abs(target.x - src.x)
+ var/dist_y = abs(target.y - src.y)
+ var/dist_travelled = 0
+ var/dist_since_sleep = 0
+
+ var/tdist_x = dist_x;
+ var/tdist_y = dist_y;
+
+ if(dist_x <= dist_y)
+ tdist_x = dist_y;
+ tdist_y = dist_x;
+
+ var/error = tdist_x/2 - tdist_y
+ while(target && (((((dist_x > dist_y) && ((src.x < target.x) || (src.x > target.x))) || ((dist_x <= dist_y) && ((src.y < target.y) || (src.y > target.y))) || (src.x > target.x)) && dist_travelled < range) || !has_gravity(src)))
+
+ if(!src.throwing) break
+ if(!istype(src.loc, /turf)) break
+
+ var/atom/step = get_step(src, get_dir(src,target))
+ if(!step)
+ break
+ src.Move(step, get_dir(src, step))
+ hit_check()
+ error += (error < 0) ? tdist_x : -tdist_y;
+ dist_travelled++
+ dist_since_sleep++
+ if(dist_since_sleep >= speed)
+ dist_since_sleep = 0
+ sleep(1)
+
+
+ src.throwing = 0
+ src.throw_impact(get_turf(src))
+
+ return 1
+
+/obj/effect/hallucination/simple/xeno/throw_impact(A)
+ update_icon("alienh_pounce")
+ if(A == target)
+ target.Weaken(5)
+ target << "[name] pounces on you!" //Todo : make this flailing for observers ?
+
+/obj/effect/hallucination/xeno_attack
+ //Xeno crawls from nearby vent,jumps at you, and goes back in
+ var/obj/machinery/atmospherics/unary/vent_pump/pump = null
+ var/obj/effect/hallucination/simple/xeno/xeno = null
+
+/obj/effect/hallucination/xeno_attack/New(loc,var/mob/living/carbon/T)
+ target = T
+ for(var/obj/machinery/atmospherics/unary/vent_pump/U in orange(7,target))
+ if(!U.welded)
+ pump = U
+ break
+ xeno = new(pump.loc,target)
+ sleep(10)
+ xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32)
+ xeno.throw_at(target,7,1)
+ sleep(10)
+ xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32)
+ xeno.throw_at(pump,7,1)
+ sleep(10)
+ var/xeno_name = xeno.name
+ target << "[xeno_name] begins climbing into the ventilation system..."
+ sleep(10)
+ qdel(xeno)
+ target << "[xeno_name] scrambles into the ventilation ducts!"
+ qdel(src)
+
+/obj/effect/hallucination/singularity_scare
+ //Singularity moving towards you.
+ //todo Hide where it moved with fake space images
+ var/obj/effect/hallucination/simple/singularity/s = null
+
+/obj/effect/hallucination/singularity_scare/New(loc,var/mob/living/carbon/T)
+ target = T
+ var/turf/start = T.loc
+ var/screen_border = pick(SOUTH,EAST,WEST,NORTH)
+ for(var/i = 0,i<11,i++)
+ start = get_step(start,screen_border)
+ s = new(start,target)
+ for(var/i = 0,i<11,i++)
+ sleep(5)
+ s.loc = get_step(get_turf(s),get_dir(s,target))
+ s.Show()
+ s.Eat()
+ qdel(s)
+
+/obj/effect/hallucination/simple/singularity
+ image_icon = 'icons/effects/224x224.dmi'
+ image_state = "singularity_s7"
+ image_layer = 6
+ px = -96
+ py = -96
+
+/obj/effect/hallucination/simple/singularity/proc/Eat(atom/OldLoc, Dir)
+ var/target_dist = get_dist(src,target)
+ if(target_dist<=3) //"Eaten"
+ target.sleeping = 20
+ target.hal_crit = 1
+ target.hal_screwyhud = 1
+ spawn(rand(50,100))
+ target.sleeping = 0
+ target.hal_crit = 0
+ target.hal_screwyhud = 0
+
+/obj/effect/hallucination/battle
+
+/obj/effect/hallucination/battle/New(loc,var/mob/living/carbon/T)
+ target = T
+ var/hits = rand(3,5)
+ switch(rand(1,3))
+ if(1) //Laser fight
+ for(var/i=0,i[my_target] has attacked [src]!")
src.health -= P.force
-
-
return
/obj/effect/fake_attacker/Crossed(var/mob/M, somenumber)
@@ -266,20 +529,18 @@ Gunshots/explosions/opening doors/less rare audio (done)
for(var/mob/O in oviewers(world.view , my_target))
O << "[my_target] stumbles around."
-/obj/effect/fake_attacker/New()
+/obj/effect/fake_attacker/New(loc,var/mob/living/carbon/T)
..()
+ my_target = T
spawn(300)
- if(my_target)
- my_target.hallucinations -= src
qdel(src)
step_away(src,my_target,2)
- spawn attack_loop()
+ spawn(0)
+ attack_loop()
/obj/effect/fake_attacker/proc/updateimage()
// del src.currentimage
-
-
if(src.dir == NORTH)
del src.currentimage
src.currentimage = new /image(up,src)
@@ -356,3 +617,18 @@ var/list/non_fakeattack_weapons = list(/obj/item/weapon/gun/projectile, /obj/ite
/obj/item/clothing/under/rank/captain, /obj/item/device/aicard,\
/obj/item/clothing/shoes/magboots, /obj/item/areaeditor/blueprints, /obj/item/weapon/disk/nuclear,\
/obj/item/clothing/suit/space/nasavoid, /obj/item/weapon/tank)
+
+/mob/living/carbon/proc/hallucinate(var/hal_type) // Todo -> proc / defines
+ switch(hal_type)
+ if("xeno")
+ new /obj/effect/hallucination/xeno_attack(src.loc,src)
+ if("singulo")
+ new /obj/effect/hallucination/singularity_scare(src.loc,src)
+ if("battle")
+ new /obj/effect/hallucination/battle(src.loc,src)
+ if("flood")
+ new /obj/effect/hallucination/fake_flood(src.loc,src)
+ if("delusion")
+ new /obj/effect/hallucination/delusion(src.loc,src)
+ if("fake")
+ new /obj/effect/hallucination/fakeattacker(src.loc,src)
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 120e7da4350..bddf6207364 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -371,10 +371,6 @@
else
hallucination -= 2
- else
- for(var/atom/a in hallucinations)
- qdel(a)
-
//this handles hud updates. Calls update_vision() and handle_hud_icons()
/mob/living/carbon/handle_regular_hud_updates()
if(!client) return 0