diff --git a/code/__DEFINES/logging.dm.rej b/code/__DEFINES/logging.dm.rej
new file mode 100644
index 0000000000..6a7a358a9c
--- /dev/null
+++ b/code/__DEFINES/logging.dm.rej
@@ -0,0 +1,9 @@
+diff a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm (rejected hunks)
+@@ -9,6 +9,7 @@
+ #define INVESTIGATE_SUPERMATTER "supermatter"
+ #define INVESTIGATE_TELESCI "telesci"
+ #define INVESTIGATE_WIRES "wires"
++#define INVESTIGATE_HALLUCINATIONS "hallucinations"
+
+ //Individual logging defines
+ #define INDIVIDUAL_ATTACK_LOG "Attack log"
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index 60f932a88a..3672b850ca 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -929,6 +929,26 @@
manipulate_organs(C)
href_list["datumrefresh"] = href_list["editorgans"]
+ else if(href_list["hallucinate"])
+ if(!check_rights(0))
+ return
+
+ var/mob/living/carbon/C = locate(href_list["hallucinate"]) in GLOB.mob_list
+ if(!istype(C))
+ to_chat(usr, "This can only be done to instances of type /mob/living/carbon")
+ return
+
+ var/list/hallucinations = subtypesof(/datum/hallucination)
+ var/result = input(usr, "Choose the hallucination to apply","Send Hallucination") as null|anything in hallucinations
+ if(!usr)
+ return
+ if(QDELETED(C))
+ to_chat(usr, "Mob doesn't exist anymore")
+ return
+
+ if(result)
+ new result(C, TRUE)
+
else if(href_list["makehuman"])
if(!check_rights(R_SPAWN))
return
diff --git a/code/datums/diseases/advance/symptoms/hallucigen.dm b/code/datums/diseases/advance/symptoms/hallucigen.dm
index f913d49573..9bfd5b0baf 100644
--- a/code/datums/diseases/advance/symptoms/hallucigen.dm
+++ b/code/datums/diseases/advance/symptoms/hallucigen.dm
@@ -59,4 +59,4 @@ Bonus
else
if(prob(base_message_chance))
to_chat(M, "[pick("Oh, your head...", "Your head pounds.", "They're everywhere! Run!", "Something in the shadows...")]")
- M.hallucination += (15 * power)
+ M.hallucination += (45 * power)
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 624d853808..94047727bc 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -233,9 +233,13 @@
return
else /*if(src.justzap)*/
return
- else if(user.hallucination > 50 && ishuman(user) && prob(10) && src.operating == FALSE)
- hallucinate_shock(user)
- return
+ else if(user.hallucinating() && ishuman(user) && prob(4) && !operating)
+ var/mob/living/carbon/human/H = user
+ if(H.gloves)
+ var/obj/item/clothing/gloves/G = H.gloves
+ if(G.siemens_coefficient)//not insulated
+ hallucinate_shock(H)
+ return
if (cyclelinkedairlock)
if (!shuttledocked && !emergency && !cyclelinkedairlock.shuttledocked && !cyclelinkedairlock.emergency && allowed(user))
if(cyclelinkedairlock.operating)
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index c9b524836f..005d9c7595 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -127,7 +127,7 @@
var/pure_red = list(0,0,0,0,0,0,0,0,0,1,0,0)
spawn(0)
- new /obj/effect/hallucination/delusion(victim.loc,victim,"demon",duration,0)
+ new /datum/hallucination/delusion(victim, TRUE, "demon",duration,0)
var/obj/item/weapon/twohanded/required/chainsaw/doomslayer/chainsaw = new(victim.loc)
chainsaw.flags |= NODROP
diff --git a/code/modules/admin/admin_investigate.dm.rej b/code/modules/admin/admin_investigate.dm.rej
new file mode 100644
index 0000000000..4f8c142c61
--- /dev/null
+++ b/code/modules/admin/admin_investigate.dm.rej
@@ -0,0 +1,10 @@
+diff a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm (rejected hunks)
+@@ -5,7 +5,7 @@
+ F << "[time_stamp()] \ref[src] ([x],[y],[z]) || [src] [message]
"
+
+
+-/client/proc/investigate_show(subject in list("hrefs","notes, memos, watchlist", INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY) )
++/client/proc/investigate_show(subject in list("hrefs","notes, memos, watchlist", INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY, INVESTIGATE_HALLUCINATIONS) )
+ set name = "Investigate"
+ set category = "Admin"
+ if(!holder)
diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index 0b1187e9bc..6ae32a9d6a 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -11,6 +11,8 @@ Gunshots/explosions/opening doors/less rare audio (done)
*/
+#define HAL_LINES_FILE "hallucination.json"
+
/mob/living/carbon
var/image/halimage
var/image/halbody
@@ -64,13 +66,14 @@ Gunshots/explosions/opening doors/less rare audio (done)
var/col_mod = null
var/image/current_image = null
var/image_layer = MOB_LAYER
- var/active = 1 //qdelery
+ var/active = TRUE //qdelery
/obj/effect/hallucination/simple/Initialize(mapload, var/mob/living/carbon/T)
..()
target = T
current_image = GetImage()
- if(target.client) target.client.images |= current_image
+ if(target.client)
+ target.client.images |= current_image
/obj/effect/hallucination/simple/proc/GetImage()
var/image/I = image(image_icon,src,image_state,image_layer,dir=src.dir)
@@ -82,10 +85,12 @@ Gunshots/explosions/opening doors/less rare audio (done)
/obj/effect/hallucination/simple/proc/Show(update=1)
if(active)
- if(target.client) target.client.images.Remove(current_image)
+ if(target.client)
+ target.client.images.Remove(current_image)
if(update)
current_image = GetImage()
- if(target.client) target.client.images |= current_image
+ if(target.client)
+ target.client.images |= current_image
/obj/effect/hallucination/simple/update_icon(new_state,new_icon,new_px=0,new_py=0)
image_state = new_state
@@ -101,36 +106,39 @@ Gunshots/explosions/opening doors/less rare audio (done)
Show()
/obj/effect/hallucination/simple/Destroy()
- if(target.client) target.client.images.Remove(current_image)
- active = 0
+ if(target.client)
+ target.client.images.Remove(current_image)
+ active = FALSE
return ..()
#define FAKE_FLOOD_EXPAND_TIME 20
#define FAKE_FLOOD_MAX_RADIUS 10
-/obj/effect/hallucination/fake_flood
+/datum/hallucination/fake_flood
//Plasma starts flooding from the nearby vent
+ var/turf/center
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
+ cost = 25
-/obj/effect/hallucination/fake_flood/Initialize(mapload, var/mob/living/carbon/T)
+/datum/hallucination/fake_flood/New(mob/living/carbon/T, forced = TRUE)
..()
- target = T
for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in orange(7,target))
if(!U.welded)
- src.loc = U.loc
+ center = get_turf(U)
break
- flood_images += image(image_icon,src,image_state,MOB_LAYER)
- flood_turfs += get_turf(src.loc)
+ feedback_details += "Vent Coords: [center.x],[center.y],[center.z]"
+ flood_images += image(image_icon,center,image_state,MOB_LAYER)
+ flood_turfs += center
if(target.client) target.client.images |= flood_images
next_expand = world.time + FAKE_FLOOD_EXPAND_TIME
START_PROCESSING(SSobj, src)
-/obj/effect/hallucination/fake_flood/process()
+/datum/hallucination/fake_flood/process()
if(next_expand <= world.time)
radius++
if(radius > FAKE_FLOOD_MAX_RADIUS)
@@ -138,10 +146,10 @@ Gunshots/explosions/opening doors/less rare audio (done)
return
Expand()
if((get_turf(target) in flood_turfs) && !target.internal)
- target.hallucinate("fake_alert", "tox_in_air")
+ new /datum/hallucination/fake_alert(target, TRUE, "tox_in_air")
next_expand = world.time + FAKE_FLOOD_EXPAND_TIME
-/obj/effect/hallucination/fake_flood/proc/Expand()
+/datum/hallucination/fake_flood/proc/Expand()
for(var/turf/FT in flood_turfs)
for(var/dir in GLOB.cardinals)
var/turf/T = get_step(FT, dir)
@@ -152,7 +160,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
if(target.client)
target.client.images |= flood_images
-/obj/effect/hallucination/fake_flood/Destroy()
+/datum/hallucination/fake_flood/Destroy()
STOP_PROCESSING(SSobj, src)
qdel(flood_turfs)
flood_turfs = list()
@@ -167,7 +175,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
image_icon = 'icons/mob/alien.dmi'
image_state = "alienh_pounce"
-/obj/effect/hallucination/simple/xeno/Initialize(mapload, var/mob/living/carbon/T)
+/obj/effect/hallucination/simple/xeno/Initialize(mapload, mob/living/carbon/T)
..()
name = "alien hunter ([rand(1, 1000)])"
@@ -177,18 +185,19 @@ Gunshots/explosions/opening doors/less rare audio (done)
target.Knockdown(100)
target.visible_message("[target] flails around wildly.","[name] pounces on you!")
-/obj/effect/hallucination/xeno_attack
+/datum/hallucination/xeno_attack
//Xeno crawls from nearby vent,jumps at you, and goes back in
var/obj/machinery/atmospherics/components/unary/vent_pump/pump = null
var/obj/effect/hallucination/simple/xeno/xeno = null
+ cost = 25
-/obj/effect/hallucination/xeno_attack/Initialize(mapload, var/mob/living/carbon/T)
+/datum/hallucination/xeno_attack/New(mob/living/carbon/T, forced = TRUE)
..()
- target = T
for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in orange(7,target))
if(!U.welded)
pump = U
break
+ feedback_details += "Vent Coords: [pump.x],[pump.y],[pump.z]"
if(pump)
xeno = new(pump.loc,target)
sleep(10)
@@ -200,7 +209,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
sleep(10)
var/xeno_name = xeno.name
to_chat(target, "[xeno_name] begins climbing into the ventilation system...")
- sleep(10)
+ sleep(30)
qdel(xeno)
to_chat(target, "[xeno_name] scrambles into the ventilation ducts!")
qdel(src)
@@ -209,7 +218,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
image_icon = 'icons/mob/animal.dmi'
image_state = "clown"
-/obj/effect/hallucination/simple/clown/Initialize(mapload, var/mob/living/carbon/T,duration)
+/obj/effect/hallucination/simple/clown/Initialize(mapload, mob/living/carbon/T, duration)
..(loc, T)
name = pick(GLOB.clown_names)
QDEL_IN(src,duration)
@@ -256,20 +265,21 @@ Gunshots/explosions/opening doors/less rare audio (done)
image_state = "bubblegum"
px = -32
-/obj/effect/hallucination/oh_yeah
+/datum/hallucination/oh_yeah
var/obj/effect/hallucination/simple/bubblegum/bubblegum
var/image/fakebroken
var/image/fakerune
+ cost = 75
-/obj/effect/hallucination/oh_yeah/Initialize(mapload, var/mob/living/carbon/T)
+/datum/hallucination/oh_yeah/New(mob/living/carbon/T, forced = TRUE)
. = ..()
- target = T
var/turf/closed/wall/wall
for(var/turf/closed/wall/W in range(7,target))
wall = W
break
if(!wall)
return INITIALIZE_HINT_QDEL
+ feedback_details += "Source: [wall.x],[wall.y],[wall.z]"
fakebroken = image('icons/turf/floors.dmi', wall, "plating", layer = TURF_LAYER)
var/turf/landing = get_turf(target)
@@ -283,7 +293,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
bubblegum = new(wall, target)
addtimer(CALLBACK(src, .proc/bubble_attack, landing), 10)
-/obj/effect/hallucination/oh_yeah/proc/bubble_attack(turf/landing)
+/datum/hallucination/oh_yeah/proc/bubble_attack(turf/landing)
var/charged = FALSE //only get hit once
while(get_turf(bubblegum) != landing && target && target.stat != DEAD)
bubblegum.forceMove(get_step_towards(bubblegum, landing))
@@ -301,7 +311,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
sleep(30)
qdel(src)
-/obj/effect/hallucination/oh_yeah/Destroy()
+/datum/hallucination/oh_yeah/Destroy()
if(target.client)
target.client.images.Remove(fakebroken)
target.client.images.Remove(fakerune)
@@ -310,23 +320,24 @@ Gunshots/explosions/opening doors/less rare audio (done)
QDEL_NULL(bubblegum)
return ..()
-/obj/effect/hallucination/singularity_scare
+/datum/hallucination/singularity_scare
//Singularity moving towards you.
//todo Hide where it moved with fake space images
var/obj/effect/hallucination/simple/singularity/s = null
+ cost = 75
-/obj/effect/hallucination/singularity_scare/Initialize(mapload, var/mob/living/carbon/T)
+/datum/hallucination/singularity_scare/New(mob/living/carbon/T, forced = TRUE)
..()
- target = T
var/turf/start = get_turf(T)
var/screen_border = pick(SOUTH,EAST,WEST,NORTH)
- for(var/i = 0,i<11,i++)
+ for(var/i in 1 to 13)
start = get_step(start,screen_border)
+ feedback_details += "Source: [start.x],[start.y],[start.z]"
s = new(start,target)
s.parent = src
- for(var/i = 0,i<11,i++)
- sleep(5)
- s.loc = get_step(get_turf(s),get_dir(s,target))
+ for(var/i in 1 to 13)
+ sleep(10)
+ s.forceMove(get_step(get_turf(s),get_dir(s,target)))
s.Show()
s.Eat()
qdel(s)
@@ -337,64 +348,72 @@ Gunshots/explosions/opening doors/less rare audio (done)
image_layer = MASSIVE_OBJ_LAYER
px = -96
py = -96
- var/obj/effect/hallucination/singularity_scare/parent
+ var/datum/hallucination/singularity_scare/parent
/obj/effect/hallucination/simple/singularity/proc/Eat(atom/OldLoc, Dir)
var/target_dist = get_dist(src,target)
if(target_dist<=3) //"Eaten"
- target.hal_screwyhud = SCREWYHUD_CRIT
+ target.set_screwyhud(SCREWYHUD_DEAD)
target.SetUnconscious(160)
- addtimer(CALLBACK(parent, .proc/wake_and_restore), rand(30, 50))
+ addtimer(CALLBACK(parent, /datum/hallucination/.proc/wake_and_restore), rand(30, 50))
-/obj/effect/hallucination/battle
+/datum/hallucination/battle
+ cost = 15
-/obj/effect/hallucination/battle/Initialize(mapload, var/mob/living/carbon/T)
+/datum/hallucination/battle/New(mob/living/carbon/T, forced = TRUE, battle_type)
..()
- target = T
var/hits = rand(3,6)
- switch(rand(1,5))
- if(1) //Laser fight
- for(var/i=0,i...wabbajack...wabbajack...")
- target.playsound_local(target,'sound/magic/staff_change.ogg', 50, 1, -1)
+ if(wabbajack)
+ to_chat(target, "...wabbajack...wabbajack...")
+ target.playsound_local(target,'sound/magic/staff_change.ogg', 50, 1)
delusion = A
target.client.images |= A
QDEL_IN(src, duration)
-/obj/effect/hallucination/self_delusion/Destroy()
+/datum/hallucination/self_delusion/Destroy()
if(target.client)
target.client.images.Remove(delusion)
return ..()
-/obj/effect/hallucination/fakeattacker/Initialize(mapload, var/mob/living/carbon/T)
+/datum/hallucination/fakeattacker/New(mob/living/carbon/T, forced = TRUE)
..()
- target = T
var/mob/living/carbon/human/clone = null
var/clone_weapon = null
@@ -523,6 +544,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
if(H.stat || H.lying)
continue
clone = H
+ feedback_details += "Clone of: [H.real_name]"
break
if(!clone)
@@ -604,7 +626,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
for(var/mob/O in oviewers(world.view , my_target))
to_chat(O, "[my_target] stumbles around.")
-/obj/effect/fake_attacker/Initialize(mapload, var/mob/living/carbon/T)
+/obj/effect/fake_attacker/Initialize(mapload, mob/living/carbon/T)
..()
my_target = T
QDEL_IN(src, 300)
@@ -651,7 +673,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
if(!locate(/obj/effect/overlay) in my_target.loc)
fake_blood(my_target)
else
- my_target.playsound_local(my_target, pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg'), 25, 1, -1)
+ my_target.playsound_local(my_target, pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg'), 25, 1)
my_target.show_message("[src.name] has punched [my_target]!", 1)
my_target.staminaloss += 30
if(prob(33))
@@ -674,14 +696,15 @@ Gunshots/explosions/opening doors/less rare audio (done)
QDEL_IN(O, 300)
-/obj/effect/hallucination/bolts
+/datum/hallucination/bolts
var/list/doors = list()
+ cost = 25
-/obj/effect/hallucination/bolts/Initialize(mapload, var/mob/living/carbon/T,var/door_number=-1) //-1 for severe, 1-2 for subtle
+/datum/hallucination/bolts/New(mob/living/carbon/T, forced, door_number=-1) //-1 for severe, 1-2 for subtle
..()
- target = T
var/image/I = null
var/count = 0
+ feedback_details += "Door amount: [door_number]"
for(var/obj/machinery/door/airlock/A in range(7, target))
if(count>door_number && door_number>0)
break
@@ -700,13 +723,30 @@ Gunshots/explosions/opening doors/less rare audio (done)
sleep(rand(6,12))
qdel(src)
-/obj/effect/hallucination/whispers
+/datum/hallucination/whispers
+ cost = 15
-/obj/effect/hallucination/whispers/Initialize(mapload, var/mob/living/carbon/T)
+/datum/hallucination/whispers/New(mob/living/carbon/T, forced = TRUE)
..()
- target = T
- var/speak_messages = list("I'm watching you...","[target.first_name()]!","Get out!","Kchck-Chkck? Kchchck!","Did you hear that?","What did you do ?","Why?","Give me that!","HELP!!","EI NATH!!", "RUN!!", "Kill me!","O bidai nabora se'sma!", "[text2ratvar("Divinity, grant...")]")
- var/radio_messages = list("Xenos!","Singularity loose!","Comms down!","They are arming the nuke!","They butchered Ian!","H-help!","[pick("Cult", "Wizard", "Ling", "Ops", "Revenant", "Murderer", "Harm", "I hear flashing", "Help")] in [pick(GLOB.teleportlocs)][prob(50)?"!":"!!"]","Where's [target.first_name()]?","Call the shuttle!","AI rogue!!")
+ var/speak_messages = list("[pick("I'm watching you...","I know what you're doing","What are you hiding?","I saw that")]",\
+ "[pick("","Hey, ","Hi ","Hello ","Wait, ","It's ")][target.first_name()]!",\
+ "[pick("Get out","Go away","Fuck off","OUT!")]",\
+ "[pick("Kchck-Chkck? Kchchck!","EEEeeeeEEEE","#@§*&£","H-hhhhh...")]",\
+ "[pick("Did you hear that?","Did you see that?","What was that?")]",\
+ "[pick("Hail Ratvar","Hail Nar'Sie","Viva!","[generate_code_phrase()]","Are you mr. [pick(GLOB.possible_changeling_IDs)]?")]",\
+ "[pick("Why?","What?","Wait, what?","Wait","Hold on","Uh...")]",\
+ "Give me that!",\
+ "HELP[pick(""," ME"," HIM"," HER"," THEM")]!!",\
+ "RUN!!",\
+ "I'm infected, [pick("stay away","don't get close","be careful","help me","kill me")]")
+
+ var/radio_messages = list("Set [target.first_name()] to arrest!",\
+ "[pick("Captain","Hos","Cmo","Rd","Ce","Hop","Janitor","AI","Viro","Qm","[target.first_name()]")] is [pick("rogue","cult","clockcult","a revhead","a gang leader","a traitor","a ling","dead")]!",\
+ "Help!",\
+ "[pick("Cult", "Wizard", "Blob", "Ling", "Ops", "Swarmers", "Revenant", "Traitor", "Harm", "I hear flashing", "Help")] in [pick(GLOB.teleportlocs)][prob(50)?"!":"!!"]",\
+ "Where's [target.first_name()]?"\
+ ,"[pick("C","Ai, c","Someone c","Rec")]all the shuttle!"\
+ ,"AI [pick("rogue", "is dead")]!!")
var/list/mob/living/carbon/people = list()
var/list/mob/living/carbon/person = null
@@ -722,7 +762,9 @@ Gunshots/explosions/opening doors/less rare audio (done)
people += H
if(person) //Basic talk
var/image/speech_overlay = image('icons/mob/talk.dmi', person, "default0", layer = ABOVE_MOB_LAYER)
- to_chat(target, target.compose_message(person,understood_language,pick(speak_messages),null,person.get_spans()))
+ var/message = target.compose_message(person,understood_language,pick(speak_messages),null,person.get_spans())
+ feedback_details += "Type: Talk, Source: [person.real_name], Message: [message]"
+ to_chat(target, message)
if(target.client)
target.client.images |= speech_overlay
sleep(30)
diff --git a/code/modules/flufftext/Hallucination.dm.rej b/code/modules/flufftext/Hallucination.dm.rej
new file mode 100644
index 0000000000..78b5d879f2
--- /dev/null
+++ b/code/modules/flufftext/Hallucination.dm.rej
@@ -0,0 +1,209 @@
+diff a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm (rejected hunks)
+@@ -60,9 +60,14 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
+ var/halpick = pick(current)
+ new halpick(src, FALSE)
+
++/mob/living/carbon/proc/set_screwyhud(hud_type)
++ hal_screwyhud = hud_type
++ update_health_hud()
++
+ /datum/hallucination
+ var/mob/living/carbon/target
+ var/cost = 5 //affects the amount of hallucination reduced, and cooldown until the next hallucination
++ var/feedback_details //extra info for investigate
+
+ /datum/hallucination/New(mob/living/carbon/T, forced = TRUE)
+ set waitfor = 0
+@@ -72,9 +77,13 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
+ target.next_hallucination = world.time + (rand(cost * 0.5, cost * 3) * 10)
+
+ /datum/hallucination/proc/wake_and_restore()
+- target.hal_screwyhud = SCREWYHUD_NONE
++ target.set_screwyhud(SCREWYHUD_NONE)
+ target.SetSleeping(0)
+
++/datum/hallucination/Destroy()
++ target.investigate_log("was afflicted with a hallucination of type [type]. [feedback_details]", INVESTIGATE_HALLUCINATIONS)
++ return ..()
++
+ /obj/effect/hallucination
+ invisibility = INVISIBILITY_OBSERVER
+ var/mob/living/carbon/target = null
+@@ -744,7 +771,9 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
+ for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
+ humans += H
+ person = pick(humans)
+- to_chat(target, target.compose_message(person,understood_language,pick(radio_messages),"1459",person.get_spans()))
++ var/message = target.compose_message(person,understood_language,pick(radio_messages),"1459",person.get_spans())
++ feedback_details += "Type: Radio, Source: [person.real_name], Message: [message]"
++ to_chat(target, message)
+ qdel(src)
+
+ /datum/hallucination/message
+@@ -763,43 +792,48 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
+ "You're hallucinating.", \
+ //Direct advice
+ "[pick_list_replacements(HAL_LINES_FILE, "advice")]")
++ feedback_details += "Message: [chosen]"
+ to_chat(target, chosen)
+ qdel(src)
+
+ /datum/hallucination/sounds
+ cost = 15
+
+-/datum/hallucination/sounds/New(mob/living/carbon/T, forced = TRUE)
++/datum/hallucination/sounds/New(mob/living/carbon/T, forced = TRUE, sound_type)
+ ..()
++ if(!sound_type)
++ sound_type = pick("airlock","explosion","far_explosion","glass","phone","summon_guns","alarm","beepsky","hallelujah","creepy","ratvar","shuttle_dock",
++ "wall_decon","door_hack","esword","blob_alert","tesla","malf_ai")
++ feedback_details += "Type: [sound_type]"
+ //Strange audio
+- switch(rand(1,20))
+- if(1)
++ switch(sound_type)
++ if("airlock")
+ target.playsound_local(null,'sound/machines/airlock.ogg', 15, 1)
+- if(2)
++ if("explosion")
+ if(prob(50))
+ target.playsound_local(null,'sound/effects/explosion1.ogg', 50, 1)
+ else
+ target.playsound_local(null, 'sound/effects/explosion2.ogg', 50, 1)
+- if(3)
++ if("far_explosion")
+ target.playsound_local(null, 'sound/effects/explosionfar.ogg', 50, 1)
+- if(4)
++ if("glass")
+ target.playsound_local(null, pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg'), 50, 1)
+- if(5)
++ if("phone")
+ target.playsound_local(null, 'sound/weapons/ring.ogg', 35)
+ sleep(15)
+ target.playsound_local(null, 'sound/weapons/ring.ogg', 35)
+ sleep(15)
+ target.playsound_local(null, 'sound/weapons/ring.ogg', 35)
+- if(6)
++ if("summon_guns")
+ target.playsound_local(null, 'sound/magic/summon_guns.ogg', 50, 1)
+- if(7)
++ if("alarm")
+ target.playsound_local(null, 'sound/machines/alarm.ogg', 100, 0)
+- if(8)
++ if("beepsky")
+ target.playsound_local(null, 'sound/voice/bfreeze.ogg', 35, 0)
+- if(9)
++ if("hallelujah")
+ target.playsound_local(null, 'sound/effects/pray_chaplain.ogg', 50)
+ //Rare audio
+- if(10)
++ if("creepy")
+ //These sounds are (mostly) taken from Hidden: Source
+ var/static/list/hallucinations_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',\
+@@ -807,42 +841,42 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
+ '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')
+ target.playsound_local(null, pick(hallucinations_creepyasssounds), 50, 1)
+- if(11)
++ if("ratvar")
+ target.playsound_local(null, 'sound/effects/ratvar_rises.ogg', 100)
+ sleep(150)
+ target.playsound_local(null, 'sound/effects/ratvar_reveal.ogg', 100)
+- if(12)
++ if("shuttle_dock")
+ to_chat(target, "Priority Announcement
")
+ to_chat(target, "
The Emergency Shuttle has docked with the station. You have 3 minutes to board the Emergency Shuttle.
")
+ target.playsound_local(null, 'sound/ai/shuttledock.ogg', 100)
+ //Deconstructing a wall
+- if(13)
++ if("wall_decon")
+ target.playsound_local(null, 'sound/items/welder.ogg', 15, 1)
+ sleep(105)
+ target.playsound_local(null, 'sound/items/welder2.ogg', 15, 1)
+ sleep(15)
+ target.playsound_local(null, 'sound/items/ratchet.ogg', 15, 1)
+ //Hacking a door
+- if(14)
++ if("door_hack")
+ target.playsound_local(null, 'sound/items/screwdriver.ogg', 15, 1)
+ sleep(rand(10,30))
+ for(var/i = rand(1,3), i>0, i--)
+ target.playsound_local(null, 'sound/weapons/empty.ogg', 15, 1)
+ sleep(rand(10,30))
+ target.playsound_local(null, 'sound/machines/airlockforced.ogg', 15, 1)
+- if(15)
++ if("esword")
+ target.playsound_local(null, 'sound/weapons/saberon.ogg',35,1)
+- if(16)
++ if("blob_alert")
+ to_chat(target, "Biohazard Alert
")
+ to_chat(target, "
Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.
")
+ target.playsound_local(null, 'sound/ai/outbreak5.ogg', 100, 0)
+- if(17) //Tesla loose!
++ if("tesla") //Tesla loose!
+ target.playsound_local(null, 'sound/magic/lightningbolt.ogg', 35, 1)
+ sleep(20)
+ target.playsound_local(null, 'sound/magic/lightningbolt.ogg', 65, 1)
+ sleep(20)
+ target.playsound_local(null, 'sound/magic/lightningbolt.ogg', 100, 1)
+- if(18) //AI is doomsdaying!
++ if("malf_ai") //AI is doomsdaying!
+ to_chat(target, "Anomaly Alert
")
+ to_chat(target, "
Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.
")
+ target.playsound_local(null, 'sound/ai/aimalf.ogg', 100, 0)
+@@ -854,9 +888,10 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
+ /datum/hallucination/hudscrew/New(mob/living/carbon/T, forced = TRUE)
+ ..()
+ //Screwy HUD
+- target.hal_screwyhud = pick(SCREWYHUD_CRIT,SCREWYHUD_DEAD,SCREWYHUD_HEALTHY)
++ target.set_screwyhud(pick(SCREWYHUD_CRIT,SCREWYHUD_DEAD,SCREWYHUD_HEALTHY))
++ feedback_details += "Type: [target.hal_screwyhud]"
+ sleep(rand(100,250))
+- target.hal_screwyhud = SCREWYHUD_NONE
++ target.set_screwyhud(SCREWYHUD_NONE)
+ qdel(src)
+
+ /datum/hallucination/fake_alert
+@@ -867,6 +902,7 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
+ var/alert_type = pick("not_enough_oxy","not_enough_tox","not_enough_co2","too_much_oxy","too_much_co2","too_much_tox","newlaw","nutrition","charge","weightless","fire","locked","hacked","temphot","tempcold","pressure")
+ if(specific)
+ alert_type = specific
++ feedback_details += "Type: [alert_type]"
+ switch(alert_type)
+ if("oxy")
+ target.throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy, override = TRUE)
+@@ -962,6 +998,7 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
+ target.halitem.icon = 'icons/obj/grenade.dmi'
+ target.halitem.icon_state = "flashbang1"
+ target.halitem.name = "Flashbang"
++ feedback_details += "Type: [target.halitem.name]"
+ if(target.client) target.client.screen += target.halitem
+ QDEL_IN(target.halitem, rand(150, 350))
+ qdel(src)
+@@ -1006,7 +1043,7 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
+ /datum/hallucination/death/New(mob/living/carbon/T, forced = TRUE)
+ set waitfor = 0
+ ..()
+- target.hal_screwyhud = SCREWYHUD_DEAD
++ target.set_screwyhud(SCREWYHUD_DEAD)
+ target.Knockdown(300)
+ target.silent += 10
+ var/area/area = get_area(target)
+@@ -1025,7 +1062,7 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
+ to_chat(target, "DEAD: [fakemob.name] says, \"[pick("rip","hey [target.first_name()]","you too?","is the AI rogue?",\
+ "i[prob(50)?" fucking":""] hate [pick("blood cult", "clock cult", "revenants", "abductors","double agents","viruses","badmins","you")]")]\"")
+ sleep(rand(70,90))
+- target.hal_screwyhud = SCREWYHUD_NONE
++ target.set_screwyhud(SCREWYHUD_NONE)
+ target.SetKnockdown(0)
+ target.silent = 0
+ qdel(src)
+@@ -1100,6 +1137,7 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
+ startlocs += T
+ var/turf/start = pick(startlocs)
+ var/proj_type = pick(subtypesof(/obj/item/projectile/hallucination))
++ feedback_details += "Type: [proj_type]"
+ var/obj/item/projectile/hallucination/H = new proj_type(start)
+ target.playsound_local(start, H.hal_fire_sound, 60, 1)
+ H.hal_target = target
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 4415c0d7ab..cd5f179dd7 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -240,6 +240,12 @@
/mob/living/carbon/is_muzzled()
return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle))
+/mob/living/carbon/hallucinating()
+ if(hallucination)
+ return TRUE
+ else
+ return FALSE
+
/mob/living/carbon/resist_buckle()
if(restrained())
changeNext_move(CLICK_CD_BREAKOUT)
@@ -811,3 +817,4 @@
.["Make AI"] = "?_src_=vars;makeai=\ref[src]"
.["Modify bodypart"] = "?_src_=vars;editbodypart=\ref[src]"
.["Modify organs"] = "?_src_=vars;editorgans=\ref[src]"
+ .["Hallucinate"] = "?_src_=vars;hallucinate=\ref[src]"
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 1d60ae4982..6bacfdd807 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -370,8 +370,7 @@
adjust_drugginess(-1)
if(hallucination)
- spawn handle_hallucinations()
- hallucination = max(hallucination-2,0)
+ handle_hallucinations()
//used in human and monkey handle_environment()
/mob/living/carbon/proc/natural_bodytemperature_stabilization()
diff --git a/code/modules/mob/living/simple_animal/guardian/types/fire.dm b/code/modules/mob/living/simple_animal/guardian/types/fire.dm
index b0a8ba5215..8f456abc53 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/fire.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/fire.dm
@@ -21,7 +21,7 @@
/mob/living/simple_animal/hostile/guardian/fire/AttackingTarget()
. = ..()
if(. && ishuman(target) && target != summoner)
- new /obj/effect/hallucination/delusion(target.loc,target,"custom",200,0, icon_state,icon)
+ new /datum/hallucination/delusion(target,TRUE,"custom",200,0, icon_state,icon)
/mob/living/simple_animal/hostile/guardian/fire/Crossed(AM as mob|obj)
..()
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index a704c2e43f..46f5db920b 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -325,6 +325,9 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
return B.eye_blind
return 0
+/mob/proc/hallucinating()
+ return FALSE
+
/proc/is_special_character(mob/M) // returns 1 for special characters and 2 for heroes of gamemode //moved out of admins.dm because things other than admin procs were calling this.
if(!SSticker.HasRoundStarted())
return 0
diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm
index 4b1d5af6c4..5a8f49f45a 100644
--- a/code/modules/projectiles/projectile/special.dm
+++ b/code/modules/projectiles/projectile/special.dm
@@ -387,3 +387,232 @@
var/obj/effect/ebeam/B = b
animate(B, alpha = 0, time = 32)
return ..()
+
+/obj/item/projectile/hallucination
+ name = "bullet"
+ icon = null
+ icon_state = null
+ hitsound = ""
+ suppressed = TRUE
+ ricochets_max = 0
+ ricochet_chance = 0
+ damage = 0
+ nodamage = TRUE
+ projectile_type = /obj/item/projectile/hallucination
+ log_override = TRUE
+ var/hal_icon_state
+ var/image/fake_icon
+ var/mob/living/carbon/hal_target
+ var/hal_fire_sound
+ var/hal_hitsound
+ var/hal_hitsound_wall
+ var/hal_impact_effect
+ var/hal_impact_effect_wall
+ var/hit_duration
+ var/hit_duration_wall
+
+/obj/item/projectile/hallucination/fire()
+ ..()
+ fake_icon = image('icons/obj/projectiles.dmi', src, hal_icon_state, ABOVE_MOB_LAYER)
+ if(hal_target.client)
+ hal_target.client.images += fake_icon
+
+/obj/item/projectile/hallucination/Destroy()
+ if(hal_target.client)
+ hal_target.client.images -= fake_icon
+ QDEL_NULL(fake_icon)
+ return ..()
+
+/obj/item/projectile/hallucination/Collide(atom/A)
+ if(!ismob(A))
+ if(hal_hitsound_wall)
+ hal_target.playsound_local(loc, hal_hitsound_wall, 40, 1)
+ if(hal_impact_effect_wall)
+ spawn_hit(A, TRUE)
+ else if(A == hal_target)
+ if(hal_hitsound)
+ hal_target.playsound_local(A, hal_hitsound, 100, 1)
+ target_on_hit(A)
+ qdel(src)
+ return TRUE
+
+/obj/item/projectile/hallucination/proc/target_on_hit(mob/M)
+ if(M == hal_target)
+ to_chat(hal_target, "[M] is hit by \a [src] in the chest!")
+ hal_apply_effect()
+ else if(M in view(hal_target))
+ to_chat(hal_target, "[M] is hit by \a [src] in the chest!!")
+ if(damage_type == BRUTE)
+ var/splatter_dir = dir
+ if(starting)
+ splatter_dir = get_dir(starting, get_turf(M))
+ spawn_blood(M, splatter_dir)
+ else if(hal_impact_effect)
+ spawn_hit(M, FALSE)
+
+/obj/item/projectile/hallucination/proc/spawn_blood(mob/M, set_dir)
+ set waitfor = 0
+ if(!hal_target.client)
+ return
+
+ var/splatter_icon_state
+ if(set_dir in GLOB.diagonals)
+ splatter_icon_state = "splatter[pick(1, 2, 6)]"
+ else
+ splatter_icon_state = "splatter[pick(3, 4, 5)]"
+
+ var/image/blood = image('icons/effects/blood.dmi', M, splatter_icon_state, ABOVE_MOB_LAYER)
+ var/target_pixel_x = 0
+ var/target_pixel_y = 0
+ switch(set_dir)
+ if(NORTH)
+ target_pixel_y = 16
+ if(SOUTH)
+ target_pixel_y = -16
+ layer = ABOVE_MOB_LAYER
+ if(EAST)
+ target_pixel_x = 16
+ if(WEST)
+ target_pixel_x = -16
+ if(NORTHEAST)
+ target_pixel_x = 16
+ target_pixel_y = 16
+ if(NORTHWEST)
+ target_pixel_x = -16
+ target_pixel_y = 16
+ if(SOUTHEAST)
+ target_pixel_x = 16
+ target_pixel_y = -16
+ layer = ABOVE_MOB_LAYER
+ if(SOUTHWEST)
+ target_pixel_x = -16
+ target_pixel_y = -16
+ layer = ABOVE_MOB_LAYER
+ hal_target.client.images += blood
+ animate(blood, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = 5)
+ sleep(5)
+ hal_target.client.images -= blood
+ qdel(blood)
+
+/obj/item/projectile/hallucination/proc/spawn_hit(atom/A, is_wall)
+ set waitfor = 0
+ if(!hal_target.client)
+ return
+
+ var/image/hit_effect = image('icons/effects/blood.dmi', A, is_wall ? hal_impact_effect_wall : hal_impact_effect, ABOVE_MOB_LAYER)
+ hit_effect.pixel_x = A.pixel_x + rand(-4,4)
+ hit_effect.pixel_y = A.pixel_y + rand(-4,4)
+ hal_target.client.images += hit_effect
+ sleep(is_wall ? hit_duration_wall : hit_duration)
+ hal_target.client.images -= hit_effect
+ qdel(hit_effect)
+
+
+/obj/item/projectile/hallucination/proc/hal_apply_effect()
+ return
+
+/obj/item/projectile/hallucination/bullet
+ name = "bullet"
+ hal_icon_state = "bullet"
+ hal_fire_sound = "gunshot"
+ hal_hitsound = 'sound/weapons/pierce.ogg'
+ hal_hitsound_wall = "ricochet"
+ hal_impact_effect = "impact_bullet"
+ hal_impact_effect_wall = "impact_bullet"
+ hit_duration = 5
+ hit_duration_wall = 5
+
+/obj/item/projectile/hallucination/bullet/hal_apply_effect()
+ hal_target.adjustStaminaLoss(60)
+
+/obj/item/projectile/hallucination/laser
+ name = "laser"
+ damage_type = BURN
+ hal_icon_state = "laser"
+ hal_fire_sound = 'sound/weapons/laser.ogg'
+ hal_hitsound = 'sound/weapons/sear.ogg'
+ hal_hitsound_wall = 'sound/weapons/effects/searwall.ogg'
+ hal_impact_effect = "impact_laser"
+ hal_impact_effect_wall = "impact_laser_wall"
+ hit_duration = 4
+ hit_duration_wall = 10
+ pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
+
+/obj/item/projectile/hallucination/laser/hal_apply_effect()
+ hal_target.adjustStaminaLoss(20)
+ hal_target.blur_eyes(2)
+
+/obj/item/projectile/hallucination/taser
+ name = "electrode"
+ damage_type = BURN
+ hal_icon_state = "spark"
+ color = "#FFFF00"
+ hal_fire_sound = 'sound/weapons/taser.ogg'
+ hal_hitsound = 'sound/weapons/taserhit.ogg'
+ hal_hitsound_wall = null
+ hal_impact_effect = null
+ hal_impact_effect_wall = null
+
+/obj/item/projectile/hallucination/taser/hal_apply_effect()
+ hal_target.Knockdown(100)
+ hal_target.stuttering += 20
+ if(hal_target.dna && hal_target.dna.check_mutation(HULK))
+ hal_target.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
+ else if(hal_target.status_flags & CANKNOCKDOWN)
+ addtimer(CALLBACK(hal_target, /mob/living/carbon.proc/do_jitter_animation, 20), 5)
+
+/obj/item/projectile/hallucination/disabler
+ name = "disabler beam"
+ damage_type = STAMINA
+ hal_icon_state = "omnilaser"
+ hal_fire_sound = 'sound/weapons/taser2.ogg'
+ hal_hitsound = 'sound/weapons/tap.ogg'
+ hal_hitsound_wall = 'sound/weapons/effects/searwall.ogg'
+ hal_impact_effect = "impact_laser_blue"
+ hal_impact_effect_wall = null
+ hit_duration = 4
+ pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
+
+/obj/item/projectile/hallucination/disabler/hal_apply_effect()
+ hal_target.adjustStaminaLoss(25)
+
+/obj/item/projectile/hallucination/ebow
+ name = "bolt"
+ damage_type = TOX
+ hal_icon_state = "cbbolt"
+ hal_fire_sound = 'sound/weapons/genhit.ogg'
+ hal_hitsound = null
+ hal_hitsound_wall = null
+ hal_impact_effect = null
+ hal_impact_effect_wall = null
+
+/obj/item/projectile/hallucination/ebow/hal_apply_effect()
+ hal_target.Knockdown(100)
+ hal_target.stuttering += 5
+ hal_target.adjustStaminaLoss(8)
+
+/obj/item/projectile/hallucination/change
+ name = "bolt of change"
+ damage_type = BURN
+ hal_icon_state = "ice_1"
+ hal_fire_sound = 'sound/magic/staff_change.ogg'
+ hal_hitsound = null
+ hal_hitsound_wall = null
+ hal_impact_effect = null
+ hal_impact_effect_wall = null
+
+/obj/item/projectile/hallucination/change/hal_apply_effect()
+ new /datum/hallucination/self_delusion(hal_target, TRUE, wabbajack = FALSE)
+
+/obj/item/projectile/hallucination/death
+ name = "bolt of death"
+ damage_type = BURN
+ hal_icon_state = "pulse1_bl"
+ hal_fire_sound = 'sound/magic/wandodeath.ogg'
+ hal_hitsound = null
+ hal_hitsound_wall = null
+ hal_impact_effect = null
+ hal_impact_effect_wall = null
+
+/obj/item/projectile/hallucination/death/hal_apply_effect()
+ new /datum/hallucination/death(hal_target, TRUE)
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index 27cad406fa..3811512a02 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -101,9 +101,11 @@
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "chem_dispenser", name, 550, 550, master_ui, state)
+ if(user.hallucinating())
+ ui.set_autoupdate(FALSE) //to not ruin the immersion by constantly changing the fake chemicals
ui.open()
-/obj/machinery/chem_dispenser/ui_data()
+/obj/machinery/chem_dispenser/ui_data(mob/user)
var/data = list()
data["amount"] = amount
data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI.
@@ -128,10 +130,16 @@
data["beakerTransferAmounts"] = null
var chemicals[0]
+ var/is_hallucinating = FALSE
+ if(user.hallucinating())
+ is_hallucinating = TRUE
for(var/re in dispensable_reagents)
var/datum/reagent/temp = GLOB.chemical_reagents_list[re]
if(temp)
- chemicals.Add(list(list("title" = temp.name, "id" = temp.id)))
+ var/chemname = temp.name
+ if(is_hallucinating && prob(5))
+ chemname = "[pick_list_replacements("hallucination.json", "chemicals")]"
+ chemicals.Add(list(list("title" = chemname, "id" = temp.id)))
data["chemicals"] = chemicals
return data
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index ff44804e75..0f5f1de91d 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -290,9 +290,8 @@
//HALLUCINATE
else if((findtext(message, hallucinate_words)))
cooldown = COOLDOWN_MEME
- for(var/V in listeners)
- var/mob/living/L = V
- new /obj/effect/hallucination/delusion(get_turf(L),L,null,150 * power_multiplier,0)
+ for(var/mob/living/carbon/C in listeners)
+ new /datum/hallucination/delusion(C, TRUE, null,150 * power_multiplier,0)
//WAKE UP
else if((findtext(message, wakeup_words)))
diff --git a/strings/hallucination.json b/strings/hallucination.json
new file mode 100644
index 0000000000..b28c70db4a
--- /dev/null
+++ b/strings/hallucination.json
@@ -0,0 +1,229 @@
+{
+ "suspicion": [
+ "I'm watching you...",
+ "I know what you're doing",
+ "What are you hiding?",
+ "I saw that"
+ ],
+
+ "greetings": [
+ "",
+ "Hey, ",
+ "Hi ",
+ "Hello ",
+ "Wait, ",
+ "It's "
+ ],
+
+ "getout": [
+ "Get out",
+ "Get out!",
+ "Go away",
+ "Fuck off",
+ "OUT!",
+ "Out!"
+ ],
+
+ "weird": [
+ "Kchck-Chkck? Kchchck!",
+ "Kchckchk...",
+ "EEEeeeeEEEE",
+ "khhhhh",
+ "#@§*&£",
+ "H**p m*",
+ "H-hhhhh..."
+ ],
+
+ "didyouhearthat": [
+ "Did you hear that?",
+ "Did you see that?",
+ "What was that?"
+ ],
+
+ "imatraitor": [
+ "Hail Ratvar",
+ "Hail Nar'Sie",
+ "Hey, i've got some TC left, want something?",
+ "Viva!",
+ "I'll spare you if you don't tell anybody about me",
+ "Hey, are you a traitor too?",
+ "You're my target, but @pick(excuses)",
+ "Are you mr. @pick(ling_names)?"
+ ],
+
+ "excuses": [
+ "i like you, so i'll spare you",
+ "i don't really feel like following objectives today",
+ "i'm not robust enough to fight you",
+ "who cares",
+ "i'll kill you later"
+ ]
+
+ "ling_names": [
+ "Alpha",
+ "Beta",
+ "Gamma",
+ "Delta",
+ "Epsilon",
+ "Eta",
+ "Theta",
+ "Lambda",
+ "Mu",
+ "Xi",
+ "Rho",
+ "Sigma",
+ "Tau",
+ "Upsilon",
+ "Phi",
+ "Psi",
+ "Omega"
+ ]
+
+ "doubt": [
+ "Why?",
+ "What?",
+ "Wait, what?",
+ "Wait",
+ "Hold on",
+ "Uh..."
+ ],
+
+ "aggressive": [
+ "Give me that!",
+ "I'm going to kill you!",
+ "Fuck you!"
+ ],
+
+ "help": [
+ "HELP",
+ "HELP ME",
+ "HELP HIM",
+ "HELP HER",
+ "HELP THEM",
+ "HELP US",
+ "HELP YOURSELF"
+ ],
+
+ "escape": [
+ "RUN!!",
+ "They're behind me!",
+ "It's here!",
+ "Follow me!",
+ "Follow me"
+ ]
+
+ "infection_advice": [
+ "stay away",
+ "don't get close",
+ "be careful",
+ "help me",
+ "kill me"
+ ]
+
+ "people": [
+ "Captain",
+ "Hos",
+ "Cmo",
+ "Rd",
+ "Ce",
+ "Hop",
+ "Janitor",
+ "AI",
+ "Viro",
+ "Qm",
+ "[target.first_name()]"
+ ]
+
+ "accusations": [
+ "rogue",
+ "cult",
+ "a cultist",
+ "clockcult",
+ "a clock cultist",
+ "a revhead",
+ "a rev",
+ "a gang leader",
+ "a gangster",
+ "a traitor",
+ "a tator",
+ "a ling",
+ "a changeling"
+ ]
+
+ "threat": [
+ "Cult",
+ "Wizard",
+ "Blob",
+ "Ling",
+ "Ops",
+ "Swarmers",
+ "Revenant",
+ "Traitor",
+ "Harm",
+ "I hear flashing",
+ "Help"
+ ]
+
+ "location": [
+ "bridge",
+ "armory",
+ "sec",
+ "security",
+ "science",
+ "engineering",
+ "cargo",
+ "medbay",
+ "atmos",
+ "maint",
+ "hops office",
+ "captains office",
+ "chapel",
+ "library",
+ "tool storage",
+ "botany",
+ "kitchen",
+ "the ai sat"
+ ]
+
+ "advice": [
+ "Hmm...not sure about that.",
+ "Yes. You're doing the right thing.",
+ "No. Stop what you're doing.",
+ "You should be wary of that person.",
+ "Trust that person.",
+ "That person wants to kill you.",
+ "Kill that person. You know who.",
+ "You should go somewhere else. Quickly.",
+ "Good luck. You'll need it.",
+ "You have my permission. Do it."
+ ]
+
+ "chemicals": [
+ "Ooze",
+ "Fire",
+ "Earth",
+ "Lightning",
+ "Air",
+ "Magic",
+ "Spiders",
+ "Button",
+ "Surprise",
+ "Happiness",
+ "Despair",
+ "Blood",
+ "Awesome",
+ "Infinity",
+ "Electronics",
+ "Time",
+ "Space",
+ "Pain",
+ "Guts",
+ "Life",
+ "Death",
+ "Phlebotinium",
+ "Mana",
+ "Energy",
+ "?????"
+ ]
+
+}