mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 00:29:02 +01:00
Hallucination revamps and additions (#89865)
## About The Pull Request 1. Hallucination effects are now tiered Hallucinations now all have tiers, ranging from common to special. If you are just hallucinating a teeny bit, you will not experience the more extreme hallucinations, like bubblegum or your mom. But if you're hallucinating off your butt, you will be a bit more likely to experience them. 2. Hallucination rate has been tweaked Default hallucination cooldown is now 20-80 seconds, up from 10-60 seconds. However the cooldown will *also* vary depending on just how much you're hallucinating, going down to 10-40 seconds. 3. RDS is now capped a bit lower (meaning you don't see the higher tiers like bubblegum). But I added a preference to uncap it. For the people who actually like bubblegum visits. 4. If a hallucination fails to trigger, the cooldown will partially reset. (by 75%) 5. "Fake chat" hallucination will pick more viable subjects. Fake chat will try to find someone who can actually speak your language, rather than make a monkey speak mothic or something. (I may revisit this so if you're super-hallucinating it reverts to old behavior though.) 6. Adds a hallucination: Fake blood You hallucinate that you start bleeding, very simple. 7. Adds a hallucination: Fake telepathy You hallucinate a random telepathic message, similar to fake chat. 8. Adds a hallucination: Eyes in the Dark A nearby dark turf will have a set of glowing red eyes shine through the dark. A classic. 9. Adds some new sub-hallucination: PDA ringtone (fake sound), summon guns/magic (fake item) Funny prank. 10. Makes mindbreaker a bit more effective at combating RDS. Pretty much does nothing right now unless you gulp like 50u. ## Why It's Good For The Game Hallucinations are pretty one note if you experience them for longer than 10 minutes. This is due to two fold: - Many hallucinations are goofy, and not subtle - Hallucinations trigger very rapidly You will never fall for a hallucination because in between "You see John Greytide put the blueprints away", you get your mom yelling at you, everyone looking like syndies (again), and bubblegum This pr addresses it by - Limiting the wacky hallucinations for when you're really off your gourd - Reducing the period between triggers - Adding a few hallucinations If the wackier hallucinations are reserved for when you're really off your rocker, this lets the more subtle ones sink in over time, leaves more room for second guessing ## Changelog 🆑 Melbert add: Adds 4-5 new hallucinations. Collect them all. balance: If you are only hallucinating a little bit, the game will prefer to pick more subtle hallucinations. If you are hallucinating a ton, it will prefer the more wacky hallucinations. balance: If you are only hallucinating a little bit, the cooldown between hallucinations is longer. If you are hallucinating a ton, it will be shorter. balance: If a hallucination fails to trigger (such as a deaf person getting a sound hallucination) the next one will be a lot sooner. balance: RDS hallucination amount is capped at mid tier hallucinations. This means bubblegum and co. will be a lot rarer, or will even never show. HOWEVER, there is now a preference allowing you to uncap your RDS hallucinations. balance: Mindbreaker toxin is more effective at suppressing RDS. balance: Some hallucinations effects have been tweaked up or down according to the new thresholds. Madness mask as an example. fix: "Fake Fire" Hallucination works again, and now has a unique message for if you stop-drop-roll that other people see. /🆑
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
/datum/hallucination
|
||||
/// What is this hallucination's weight in the random hallucination pool?
|
||||
var/random_hallucination_weight = 0
|
||||
/// What tier of hallucination is this? Rarer ones should be higher
|
||||
var/hallucination_tier = HALLUCINATION_TIER_NEVER
|
||||
/// Who's our next highest abstract parent type?
|
||||
var/abstract_hallucination_parent = /datum/hallucination
|
||||
/// Extra info about the hallucination displayed in the log.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/datum/hallucination/battle
|
||||
abstract_hallucination_parent = /datum/hallucination/battle
|
||||
random_hallucination_weight = 3
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/// Subtype of battle hallucination for gun based battles, where it sounds like someone is being shot.
|
||||
/datum/hallucination/battle/gun
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/datum/hallucination/blood_flow
|
||||
random_hallucination_weight = 3
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
/// The bleeding hallucination's image
|
||||
var/image/bleeding
|
||||
|
||||
/datum/hallucination/blood_flow/start()
|
||||
if(!hallucinator.client || !iscarbon(hallucinator))
|
||||
return FALSE
|
||||
|
||||
var/mob/living/carbon/carb_hallucinator = hallucinator
|
||||
if(!length(carb_hallucinator.bodyparts) || HAS_TRAIT(carb_hallucinator, TRAIT_NOBLOOD))
|
||||
return FALSE
|
||||
var/obj/item/bodypart/picked
|
||||
var/list/bodyparts = carb_hallucinator.bodyparts.Copy()
|
||||
while(isnull(picked) && length(bodyparts))
|
||||
picked = pick_n_take(bodyparts)
|
||||
if(!picked.can_bleed())
|
||||
picked = null
|
||||
|
||||
if(isnull(picked))
|
||||
return FALSE
|
||||
|
||||
feedback_details += "Bleeding: [picked]"
|
||||
|
||||
RegisterSignals(picked, list(COMSIG_QDELETING, COMSIG_BODYPART_REMOVED), PROC_REF(stop_bleeding))
|
||||
RegisterSignal(hallucinator, SIGNAL_ADDTRAIT(TRAIT_NOBLOOD), PROC_REF(stop_bleeding))
|
||||
|
||||
to_chat(hallucinator, span_warning("Your [picked.plaintext_zone] looses a spray of blood!"))
|
||||
var/bleed_duration = rand(16 SECONDS, 40 SECONDS)
|
||||
addtimer(CALLBACK(src, PROC_REF(stop_bleeding), picked), bleed_duration)
|
||||
if(prob(25))
|
||||
addtimer(CALLBACK(src, PROC_REF(by_god), picked), bleed_duration * pick(0.5, 0.66))
|
||||
stamina_loop()
|
||||
|
||||
hallucinator.playsound_local(get_turf(hallucinator), pick('sound/effects/wounds/blood1.ogg', 'sound/effects/wounds/blood2.ogg', 'sound/effects/wounds/blood3.ogg'), 50, TRUE)
|
||||
bleeding = image(
|
||||
icon = 'icons/mob/effects/bleed_overlays.dmi',
|
||||
icon_state = "[picked.body_zone]_[pick(2, 3)]",
|
||||
loc = hallucinator,
|
||||
)
|
||||
bleeding.layer = -WOUND_LAYER
|
||||
hallucinator.client?.images += bleeding
|
||||
return TRUE
|
||||
|
||||
/datum/hallucination/blood_flow/Destroy()
|
||||
hallucinator.client?.images -= bleeding
|
||||
return ..()
|
||||
|
||||
/datum/hallucination/blood_flow/proc/by_god(obj/item/bodypart/picked)
|
||||
if(QDELETED(src) || QDELETED(hallucinator) || QDELETED(picked))
|
||||
return
|
||||
|
||||
to_chat(hallucinator, span_warning("The blood doesn't stop flowing, yet [picked.plaintext_zone] doesn't seem to hurt..."))
|
||||
|
||||
/datum/hallucination/blood_flow/proc/stop_bleeding(obj/item/bodypart/source)
|
||||
SIGNAL_HANDLER
|
||||
UnregisterSignal(source, list(COMSIG_QDELETING, COMSIG_BODYPART_REMOVED))
|
||||
UnregisterSignal(hallucinator, SIGNAL_ADDTRAIT(TRAIT_NOBLOOD))
|
||||
if(!QDELETED(source))
|
||||
to_chat(hallucinator, span_warning("Your [source.plaintext_zone] stops bleeding."))
|
||||
if(!QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
/datum/hallucination/blood_flow/proc/stamina_loop()
|
||||
set waitfor = FALSE
|
||||
while(!QDELETED(src) && !QDELETED(hallucinator))
|
||||
hallucinator.adjustStaminaLoss(5)
|
||||
sleep(4 SECONDS)
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Makes a random body appear and disappear quickly in view of the hallucinator.
|
||||
/datum/hallucination/body
|
||||
abstract_hallucination_parent = /datum/hallucination/body
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
/// The file to make the body image from.
|
||||
var/body_image_file
|
||||
/// The icon state to make the body image form.
|
||||
@@ -126,6 +127,7 @@
|
||||
/datum/hallucination/body/weird
|
||||
random_hallucination_weight = 0.1 // These are very uncommon
|
||||
abstract_hallucination_parent = /datum/hallucination/body/weird
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
|
||||
/datum/hallucination/body/weird/alien
|
||||
body_image_file = 'icons/mob/nonhuman-player/alien.dmi'
|
||||
@@ -140,6 +142,7 @@
|
||||
body_image_file = 'icons/mob/simple/mob.dmi'
|
||||
body_image_state = "chronostuck"
|
||||
body_floats = TRUE
|
||||
hallucination_tier = HALLUCINATION_TIER_VERYSPECIAL
|
||||
|
||||
/datum/hallucination/body/weird/god
|
||||
body_image_file = 'icons/mob/simple/mob.dmi'
|
||||
@@ -158,6 +161,7 @@
|
||||
/datum/hallucination/body/weird/bones
|
||||
body_image_file = 'icons/obj/trader_signs.dmi'
|
||||
body_image_state = "mrbones"
|
||||
hallucination_tier = HALLUCINATION_TIER_VERYSPECIAL
|
||||
|
||||
/datum/hallucination/body/weird/freezer
|
||||
random_hallucination_weight = 0.3 // Slightly more common since it's cool (heh)
|
||||
@@ -165,6 +169,7 @@
|
||||
body_image_state = "the_freezer"
|
||||
body_layer = ABOVE_ALL_MOB_LAYER
|
||||
spawn_under_hallucinator = TRUE
|
||||
hallucination_tier = HALLUCINATION_TIER_VERYSPECIAL
|
||||
|
||||
/datum/hallucination/body/weird/freezer/make_body_image(turf/location)
|
||||
var/image/body = ..()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/datum/hallucination/bolts
|
||||
random_hallucination_weight = 7
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
/// A list of weakrefs to airlocks we bolt down around us
|
||||
var/list/datum/weakref/airlocks_to_hit
|
||||
/// A list of weakrefs to fake lock hallucinations we've created
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Sends a fake bubblegum charging through a nearby wall to our target.
|
||||
/datum/hallucination/oh_yeah
|
||||
random_hallucination_weight = 1
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
/// An image overlayed to the wall bubblegum comes out of, to look destroyed.
|
||||
var/image/fake_broken_wall
|
||||
/// An image put where bubblegum is expected to land, to mimic his charge "rune" icon.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// A hallucination that makes us and (possibly) other people look like something else.
|
||||
/datum/hallucination/delusion
|
||||
abstract_hallucination_parent = /datum/hallucination/delusion
|
||||
hallucination_tier = HALLUCINATION_TIER_UNCOMMON
|
||||
|
||||
/// The duration of the delusions
|
||||
var/duration = 30 SECONDS
|
||||
@@ -249,6 +250,7 @@
|
||||
delusion_name = "Syndicate"
|
||||
affects_others = TRUE
|
||||
affects_us = FALSE
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
|
||||
/datum/hallucination/delusion/preset/syndies/make_delusion_image(mob/over_who)
|
||||
delusion_appearance = get_dynamic_human_appearance(
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/datum/hallucination/eyes_in_dark
|
||||
random_hallucination_weight = 2
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
/// The floating eye effect, somewhere in the world
|
||||
var/obj/effect/abstract/floating_eyes/eyes
|
||||
|
||||
/datum/hallucination/eyes_in_dark/Destroy()
|
||||
if(QDELETED(eyes))
|
||||
eyes = null
|
||||
else
|
||||
QDEL_NULL(eyes)
|
||||
return ..()
|
||||
|
||||
/datum/hallucination/eyes_in_dark/start()
|
||||
if(!hallucinator.client)
|
||||
return FALSE
|
||||
|
||||
if(hallucinator.lighting_cutoff >= 2.5)
|
||||
return FALSE
|
||||
|
||||
var/list/valid = list()
|
||||
for(var/turf/open/nearby in view(hallucinator))
|
||||
if(nearby.get_lumcount() > LIGHTING_TILE_IS_DARK)
|
||||
continue
|
||||
valid += nearby
|
||||
|
||||
if(!length(valid))
|
||||
return FALSE
|
||||
|
||||
if(prob(5))
|
||||
to_chat(hallucinator, span_warning("You feel like you're being watched..."))
|
||||
|
||||
var/turf/selected = pick(valid)
|
||||
feedback_details += "Eye coords: [selected.x], [selected.y], [selected.z]"
|
||||
eyes = new(selected, hallucinator)
|
||||
RegisterSignal(eyes, COMSIG_QDELETING, PROC_REF(end_hallucination))
|
||||
addtimer(CALLBACK(src, PROC_REF(end_hallucination_gracefully)), rand(60 SECONDS, 180 SECONDS))
|
||||
return TRUE
|
||||
|
||||
/datum/hallucination/eyes_in_dark/proc/end_hallucination_gracefully()
|
||||
animate(eyes, alpha = 0, time = 1 SECONDS)
|
||||
QDEL_IN(src, 1.2 SECONDS)
|
||||
|
||||
/datum/hallucination/eyes_in_dark/proc/end_hallucination()
|
||||
SIGNAL_HANDLER
|
||||
if(!QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/abstract/floating_eyes
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
// Who sees the eyes?
|
||||
var/datum/weakref/seer_ref
|
||||
|
||||
/obj/effect/abstract/floating_eyes/Initialize(mapload, mob/seer)
|
||||
. = ..()
|
||||
if(isnull(seer))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
seer_ref = WEAKREF(seer)
|
||||
var/image/make_invis = image(icon = null, icon_state = null, loc = src)
|
||||
make_invis.override = TRUE
|
||||
add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/one_person/reversed, "hallucination", make_invis, null, seer)
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
update_appearance()
|
||||
|
||||
/obj/effect/abstract/floating_eyes/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/abstract/floating_eyes/update_overlays()
|
||||
. = ..()
|
||||
var/mutable_appearance/r_eye = mutable_appearance(icon = 'icons/mob/human/human_face.dmi', icon_state = "eyes_glow_r")
|
||||
r_eye.color = COLOR_DARK_RED
|
||||
. += r_eye
|
||||
var/mutable_appearance/l_eye = mutable_appearance(icon = 'icons/mob/human/human_face.dmi', icon_state = "eyes_glow_l")
|
||||
l_eye.color = COLOR_DARK_RED
|
||||
. += l_eye
|
||||
|
||||
. += emissive_appearance('icons/mob/human/human_face.dmi', "eyes_glow_l", src)
|
||||
. += emissive_appearance('icons/mob/human/human_face.dmi', "eyes_glow_r", src)
|
||||
|
||||
/obj/effect/abstract/floating_eyes/process(seconds_per_tick)
|
||||
var/turf/below_us = get_turf(src)
|
||||
var/mob/seer = seer_ref?.resolve()
|
||||
if(below_us.get_lumcount() < LIGHTING_TILE_IS_DARK || seer?.lighting_cutoff >= 2.5 || get_dist(seer, src) <= 1)
|
||||
graceful_delete()
|
||||
|
||||
/obj/effect/abstract/floating_eyes/proc/graceful_delete()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
animate(src, alpha = 0, time = 0.5 SECONDS)
|
||||
QDEL_IN(src, 0.75 SECONDS)
|
||||
@@ -2,6 +2,7 @@
|
||||
/datum/hallucination/fake_alert
|
||||
abstract_hallucination_parent = /datum/hallucination/fake_alert
|
||||
random_hallucination_weight = 1
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
var/del_timer_id
|
||||
/// The duration of the alert being thrown.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Sends a fake chat message to the hallucinator.
|
||||
/datum/hallucination/chat
|
||||
random_hallucination_weight = 100
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/// If TRUE, we force the message to be hallucinated from common radio. Only set in New()
|
||||
var/force_radio
|
||||
@@ -12,30 +13,59 @@
|
||||
src.specific_message = specific_message
|
||||
return ..()
|
||||
|
||||
/// When passed a mob, returns a list of languages that mob could theoretically speak IF a blank slate.
|
||||
/datum/hallucination/chat/proc/get_hallucinating_spoken_languages(atom/movable/who)
|
||||
var/override_typepath
|
||||
if(iscarbon(who))
|
||||
var/mob/living/carbon/human_who = who
|
||||
override_typepath = human_who.dna?.species?.species_language_holder
|
||||
|
||||
var/datum/language_holder/what_they_speak = GLOB.prototype_language_holders[override_typepath || who.initial_language_holder]
|
||||
return what_they_speak?.spoken_languages?.Copy() || list()
|
||||
|
||||
/datum/hallucination/chat/start()
|
||||
var/mob/living/carbon/human/speaker
|
||||
var/datum/language/understood_language = hallucinator.get_random_understood_language()
|
||||
for(var/mob/living/carbon/nearby_human in view(hallucinator))
|
||||
if(nearby_human == hallucinator)
|
||||
continue
|
||||
var/list/datum/language/understood_languages = hallucinator.get_language_holder().understood_languages
|
||||
var/understood_language
|
||||
|
||||
if(!speaker)
|
||||
speaker = nearby_human
|
||||
else if(get_dist(hallucinator, nearby_human) < get_dist(hallucinator, speaker))
|
||||
if(!force_radio)
|
||||
var/list/valid_humans = list()
|
||||
var/list/valid_corpses = list()
|
||||
for(var/mob/living/carbon/nearby_human in view(hallucinator))
|
||||
if(nearby_human == hallucinator)
|
||||
continue
|
||||
if(nearby_human.stat == DEAD)
|
||||
valid_corpses += nearby_human
|
||||
continue
|
||||
valid_humans += nearby_human
|
||||
|
||||
// pick a nearby human which can speak a language the hallucinator understands
|
||||
for(var/mob/living/carbon/nearby_human in shuffle(valid_humans))
|
||||
var/list/shared_languages = get_hallucinating_spoken_languages(nearby_human) & understood_languages
|
||||
if(!length(shared_languages)) // future idea : have people hallucinating off their minds ignore this check
|
||||
continue
|
||||
speaker = nearby_human
|
||||
understood_language = pick(shared_languages)
|
||||
break
|
||||
|
||||
// corpses disrespect language because they're... dead
|
||||
if(isnull(speaker) && length(valid_corpses))
|
||||
speaker = pick(valid_corpses)
|
||||
|
||||
// Get person to affect if radio hallucination
|
||||
var/is_radio = !speaker || force_radio
|
||||
var/is_radio = force_radio || isnull(speaker)
|
||||
if(is_radio)
|
||||
var/list/humans = list()
|
||||
for(var/datum/mind/crew_mind in shuffle(get_crewmember_minds()))
|
||||
if(crew_mind == hallucinator.mind)
|
||||
continue
|
||||
var/list/shared_languages = get_hallucinating_spoken_languages(crew_mind.current) & understood_languages
|
||||
if(!length(shared_languages))
|
||||
continue
|
||||
speaker = crew_mind.current
|
||||
understood_language = pick(shared_languages)
|
||||
break
|
||||
|
||||
for(var/datum/mind/crew_mind in get_crewmember_minds())
|
||||
if(crew_mind.current)
|
||||
humans += crew_mind.current
|
||||
if(humans.len)
|
||||
speaker = pick(humans)
|
||||
|
||||
if(!speaker)
|
||||
if(isnull(speaker))
|
||||
return
|
||||
|
||||
// Time to generate a message.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// This hallucinations makes us suddenly think we died, stopping us / changing our hud / sending a fake deadchat message.
|
||||
/datum/hallucination/death
|
||||
random_hallucination_weight = 1
|
||||
hallucination_tier = HALLUCINATION_TIER_UNCOMMON
|
||||
/// Determines whether we floor them or just immobilize them
|
||||
var/floor_them = TRUE
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/datum/hallucination/message
|
||||
random_hallucination_weight = 60
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/datum/hallucination/message/start()
|
||||
var/list/nearby_humans = list()
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
/// Plasma starts flooding from the nearby vent
|
||||
/datum/hallucination/fake_flood
|
||||
random_hallucination_weight = 7
|
||||
hallucination_tier = HALLUCINATION_TIER_UNCOMMON
|
||||
|
||||
var/list/image/flood_images = list()
|
||||
var/list/obj/effect/plasma_image_holder/flood_image_holders = list()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Hallucination that plays a fake sound somewhere nearby.
|
||||
/datum/hallucination/fake_sound
|
||||
abstract_hallucination_parent = /datum/hallucination/fake_sound
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/// Volume of the fake sound
|
||||
var/volume = 50
|
||||
@@ -10,6 +11,9 @@
|
||||
var/sound_type
|
||||
|
||||
/datum/hallucination/fake_sound/start()
|
||||
if(!hallucinator.can_hear())
|
||||
return FALSE
|
||||
|
||||
var/sound_to_play = islist(sound_type) ? pick(sound_type) : sound_type
|
||||
play_fake_sound(random_far_turf(), sound_to_play)
|
||||
feedback_details += "Sound: [sound_to_play]"
|
||||
@@ -148,9 +152,31 @@
|
||||
volume = 90
|
||||
sound_type = 'sound/items/weapons/flash.ogg'
|
||||
|
||||
/datum/hallucination/fake_sound/normal/ringtone
|
||||
volume = 50
|
||||
|
||||
/datum/hallucination/fake_sound/normal/ringtone/New(mob/living/hallucinator)
|
||||
. = ..()
|
||||
if(HAS_TRAIT(SSstation, STATION_TRAIT_PDA_GLITCHED))
|
||||
sound_type = pick(
|
||||
'sound/machines/beep/twobeep_voice1.ogg',
|
||||
'sound/machines/beep/twobeep_voice2.ogg',
|
||||
)
|
||||
else
|
||||
sound_type = 'sound/machines/beep/twobeep_high.ogg'
|
||||
|
||||
/datum/hallucination/fake_sound/normal/ringtone/play_fake_sound(turf/source, sound_to_play = sound_type)
|
||||
if(prob(33))
|
||||
source = get_turf(hallucinator)
|
||||
var/obj/item/modular_computer/pda/pda = locate() in hallucinator.get_all_contents()
|
||||
var/datum/computer_file/program/messenger/messenger_app = locate() in pda?.stored_files
|
||||
hallucinator.balloon_alert(hallucinator, "*[messenger_app?.ringtone || MESSENGER_RINGTONE_DEFAULT]*")
|
||||
return ..()
|
||||
|
||||
/datum/hallucination/fake_sound/weird
|
||||
abstract_hallucination_parent = /datum/hallucination/fake_sound/weird
|
||||
random_hallucination_weight = 1
|
||||
hallucination_tier = HALLUCINATION_TIER_VERYSPECIAL
|
||||
|
||||
/// if FALSE, we will pass "null" in as the turf source, meaning the sound will just play without direction / etc.
|
||||
var/no_source = FALSE
|
||||
@@ -187,6 +213,7 @@
|
||||
sound_type = 'sound/effects/magic/clockwork/invoke_general.ogg'
|
||||
|
||||
/datum/hallucination/fake_sound/weird/creepy
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/datum/hallucination/fake_sound/weird/creepy/New(mob/living/hallucinator)
|
||||
. = ..()
|
||||
@@ -202,6 +229,7 @@
|
||||
/datum/hallucination/fake_sound/weird/game_over
|
||||
sound_vary = FALSE
|
||||
sound_type = 'sound/machines/compiler/compiler-failure.ogg'
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
|
||||
/datum/hallucination/fake_sound/weird/hallelujah
|
||||
sound_vary = FALSE
|
||||
@@ -216,8 +244,10 @@
|
||||
sound_vary = FALSE
|
||||
no_source = TRUE
|
||||
sound_type = 'sound/runtime/hyperspace/hyperspace_begin.ogg'
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/datum/hallucination/fake_sound/weird/laugher
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
sound_type = list(
|
||||
'sound/mobs/humanoids/human/laugh/womanlaugh.ogg',
|
||||
'sound/mobs/humanoids/human/laugh/manlaugh1.ogg',
|
||||
@@ -228,6 +258,7 @@
|
||||
volume = 15
|
||||
sound_vary = FALSE
|
||||
sound_type = 'sound/items/weapons/ring.ogg'
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
|
||||
/datum/hallucination/fake_sound/weird/phone/play_fake_sound(turf/source, sound_to_play)
|
||||
for(var/next_ring in 1 to 3)
|
||||
@@ -236,6 +267,7 @@
|
||||
return ..()
|
||||
|
||||
/datum/hallucination/fake_sound/weird/spell
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
sound_type = list(
|
||||
'sound/effects/magic/disintegrate.ogg',
|
||||
'sound/effects/magic/ethereal_enter.ogg',
|
||||
@@ -247,15 +279,18 @@
|
||||
)
|
||||
|
||||
/datum/hallucination/fake_sound/weird/spell/just_jaunt // A few antags use jaunts, so this sound specifically is fun to isolate
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
sound_type = 'sound/effects/magic/ethereal_enter.ogg'
|
||||
|
||||
/datum/hallucination/fake_sound/weird/summon_sound // Heretic circle sound, notably
|
||||
volume = 75
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
sound_type = 'sound/effects/magic/castsummon.ogg'
|
||||
|
||||
/datum/hallucination/fake_sound/weird/tesloose
|
||||
volume = 35
|
||||
sound_type = 'sound/effects/magic/lightningbolt.ogg'
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
|
||||
/datum/hallucination/fake_sound/weird/tesloose/play_fake_sound(turf/source, sound_to_play)
|
||||
. = ..()
|
||||
@@ -265,6 +300,7 @@
|
||||
/datum/hallucination/fake_sound/weird/xeno
|
||||
random_hallucination_weight = 2 // Some of these are ambience sounds too
|
||||
volume = 25
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
sound_type = list(
|
||||
'sound/mobs/non-humanoids/hiss/lowHiss1.ogg',
|
||||
'sound/mobs/non-humanoids/hiss/lowHiss2.ogg',
|
||||
@@ -283,7 +319,7 @@
|
||||
sound_type = 'sound/effects/hallucinations/radio_static.ogg'
|
||||
|
||||
/datum/hallucination/fake_sound/weird/ice_crack
|
||||
random_hallucination_weight = 2
|
||||
random_hallucination_weight = 0
|
||||
volume = 100
|
||||
no_source = TRUE
|
||||
sound_type = 'sound/effects/ice_shovel.ogg'
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/datum/hallucination/hazard
|
||||
abstract_hallucination_parent = /datum/hallucination/hazard
|
||||
random_hallucination_weight = 5
|
||||
hallucination_tier = HALLUCINATION_TIER_UNCOMMON
|
||||
|
||||
/// The type of effect we create
|
||||
var/hazard_type = /obj/effect/client_image_holder/hallucination/danger
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/datum/hallucination/screwy_hud
|
||||
abstract_hallucination_parent = /datum/hallucination/screwy_hud
|
||||
random_hallucination_weight = 4
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/// The type of hud we give to the hallucinator
|
||||
var/screwy_hud_type = SCREWYHUD_NONE
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Causes the hallucinator to believe themselves frozen in ice. Man am I glad he's frozen in there etc etc
|
||||
/datum/hallucination/ice
|
||||
random_hallucination_weight = 3
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/// What icon file to use for our hallucinator
|
||||
var/ice_icon = 'icons/effects/freeze.dmi'
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/datum/hallucination/fake_item
|
||||
abstract_hallucination_parent = /datum/hallucination/fake_item
|
||||
random_hallucination_weight = 1
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/// A flag of slots this fake item can appear in.
|
||||
var/valid_slots = ITEM_SLOT_HANDS|ITEM_SLOT_BELT|ITEM_SLOT_LPOCKET|ITEM_SLOT_RPOCKET
|
||||
@@ -114,6 +115,24 @@
|
||||
|
||||
return hallucinated_item
|
||||
|
||||
/datum/hallucination/fake_item/summon_guns
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
valid_slots = ITEM_SLOT_HANDS
|
||||
|
||||
/datum/hallucination/fake_item/summon_guns/make_fake_item(where_to_put_it, equip_flags)
|
||||
template_item_type = pick(GLOB.summoned_guns)
|
||||
. = ..()
|
||||
hallucinator.playsound_local(get_turf(hallucinator), 'sound/effects/magic/summon_guns.ogg', 50, TRUE)
|
||||
|
||||
/datum/hallucination/fake_item/summon_magic
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
valid_slots = ITEM_SLOT_HANDS
|
||||
|
||||
/datum/hallucination/fake_item/summon_magic/make_fake_item(where_to_put_it, equip_flags)
|
||||
template_item_type = pick(GLOB.summoned_magic + GLOB.summoned_special_magic)
|
||||
. = ..()
|
||||
hallucinator.playsound_local(get_turf(hallucinator), 'sound/effects/magic/summon_magic.ogg', 50, TRUE)
|
||||
|
||||
/obj/item/hallucinated
|
||||
name = "mirage"
|
||||
plane = ABOVE_HUD_PLANE
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/// Your mother appears to scold you.
|
||||
/datum/hallucination/your_mother
|
||||
random_hallucination_weight = 2
|
||||
hallucination_tier = HALLUCINATION_TIER_VERYSPECIAL
|
||||
|
||||
var/obj/effect/client_image_holder/hallucination/your_mother/mother
|
||||
|
||||
/datum/hallucination/your_mother/start()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/datum/hallucination/nearby_fake_item
|
||||
abstract_hallucination_parent = /datum/hallucination/nearby_fake_item
|
||||
random_hallucination_weight = 1
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/// The icon file to draw from for left hand icons
|
||||
var/left_hand_file
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
/datum/hallucination/fire
|
||||
random_hallucination_weight = 3
|
||||
hallucination_tier = HALLUCINATION_TIER_UNCOMMON
|
||||
|
||||
/// Are we currently burning our mob?
|
||||
var/active = TRUE
|
||||
@@ -27,21 +28,29 @@
|
||||
/// How long have we spent on fire?
|
||||
var/time_spent = 0
|
||||
|
||||
/datum/hallucination/fire/New(mob/living/hallucinator)
|
||||
if(ismonkey(hallucinator))
|
||||
fire_icon_state = "monkey_big_fire"
|
||||
var/fake_firestacks = 0
|
||||
|
||||
else if(!ishuman(hallucinator))
|
||||
fire_icon_state = "generic_fire"
|
||||
/datum/hallucination/fire/proc/make_overlay()
|
||||
var/mutable_appearance/real_overlay = hallucinator.get_fire_overlay(fake_firestacks)
|
||||
if(!real_overlay)
|
||||
return null
|
||||
if(real_overlay.icon_state == fire_overlay?.icon_state)
|
||||
return fire_overlay
|
||||
|
||||
return ..()
|
||||
var/image/new_overlay = image(real_overlay.icon, hallucinator, real_overlay.icon_state, real_overlay.layer)
|
||||
new_overlay.appearance_flags = real_overlay.appearance_flags
|
||||
return new_overlay
|
||||
|
||||
/datum/hallucination/fire/start()
|
||||
fire_overlay = image(fire_icon, hallucinator, fire_icon_state, ABOVE_MOB_LAYER)
|
||||
SET_PLANE_EXPLICIT(fire_overlay, ABOVE_GAME_PLANE, hallucinator)
|
||||
fake_firestacks = rand(5, 15)
|
||||
fire_overlay = make_overlay()
|
||||
if(!fire_overlay)
|
||||
return FALSE
|
||||
|
||||
hallucinator.client?.images |= fire_overlay
|
||||
to_chat(hallucinator, span_userdanger("You're set on fire!"))
|
||||
hallucinator.throw_alert(ALERT_FIRE, /atom/movable/screen/alert/fire, override = TRUE)
|
||||
var/atom/movable/screen/alert/fire/fake/alert = hallucinator.throw_alert(ALERT_FIRE, /atom/movable/screen/alert/fire/fake, override = TRUE)
|
||||
alert.hallucination_weakref = WEAKREF(src)
|
||||
times_to_lower_stamina = rand(5, 10)
|
||||
addtimer(CALLBACK(src, PROC_REF(start_expanding)), 2 SECONDS)
|
||||
return TRUE
|
||||
@@ -66,8 +75,15 @@
|
||||
if(QDELETED(src))
|
||||
return
|
||||
|
||||
if(hallucinator.fire_stacks <= 0)
|
||||
fake_firestacks -= (0.25 * seconds_per_tick)
|
||||
if(fake_firestacks <= 0)
|
||||
clear_fire()
|
||||
else
|
||||
var/new_overlay = make_overlay()
|
||||
if(new_overlay && new_overlay != fire_overlay)
|
||||
hallucinator.client?.images -= fire_overlay
|
||||
fire_overlay = new_overlay
|
||||
hallucinator.client?.images |= fire_overlay
|
||||
|
||||
time_spent += seconds_per_tick
|
||||
|
||||
@@ -100,6 +116,8 @@
|
||||
/datum/hallucination/fire/proc/update_temp()
|
||||
if(stage <= 0)
|
||||
hallucinator.clear_alert(ALERT_TEMPERATURE, clear_override = TRUE)
|
||||
if(!active)
|
||||
qdel(src)
|
||||
else
|
||||
hallucinator.clear_alert(ALERT_TEMPERATURE, clear_override = TRUE)
|
||||
hallucinator.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, stage, override = TRUE)
|
||||
@@ -117,3 +135,11 @@
|
||||
|
||||
#undef RAISE_FIRE_COUNT
|
||||
#undef RAISE_FIRE_TIME
|
||||
|
||||
/// This alert is thrown when hallucinating fire
|
||||
/atom/movable/screen/alert/fire/fake
|
||||
/// We need to track the original hallucination so we can pass it to the status effect
|
||||
var/datum/weakref/hallucination_weakref
|
||||
|
||||
/atom/movable/screen/alert/fire/fake/handle_stop_drop_roll(mob/living/roller)
|
||||
return !!roller.apply_status_effect(/datum/status_effect/stop_drop_roll/hallucinating, hallucination_weakref)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
///Causes the target to see incorrect health damages on the healthdoll
|
||||
/datum/hallucination/fake_health_doll
|
||||
random_hallucination_weight = 12
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/// The duration of the hallucination
|
||||
var/duration
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Causes a fake "zap" to the hallucinator.
|
||||
/datum/hallucination/shock
|
||||
random_hallucination_weight = 1
|
||||
random_hallucination_weight = 1 // really low weight, as it also has a snowflake check to trigger when bumping airlocks
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
var/electrocution_icon = 'icons/mob/human/human.dmi'
|
||||
var/electrocution_icon_state = "electrocuted_base"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/hallucination/station_message
|
||||
abstract_hallucination_parent = /datum/hallucination/station_message
|
||||
random_hallucination_weight = 1
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
|
||||
/datum/hallucination/station_message/start()
|
||||
qdel(src) // To be implemented by subtypes, call parent for easy cleanup
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Shoots a random, fake projectile to the hallucinator
|
||||
/datum/hallucination/stray_bullet
|
||||
random_hallucination_weight = 7
|
||||
hallucination_tier = HALLUCINATION_TIER_UNCOMMON
|
||||
|
||||
/datum/hallucination/stray_bullet/start()
|
||||
var/list/turf/starting_locations = list()
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/datum/hallucination/telepathy
|
||||
random_hallucination_weight = 4
|
||||
hallucination_tier = HALLUCINATION_TIER_COMMON
|
||||
|
||||
/datum/hallucination/telepathy/start()
|
||||
var/datum/action/cooldown/spell/list_target/telepathy/mimiced_type = pick(typesof(/datum/action/cooldown/spell/list_target/telepathy))
|
||||
hallucinator.balloon_alert(hallucinator, "you hear a voice")
|
||||
to_chat(hallucinator, "\
|
||||
<span class='[initial(mimiced_type.bold_telepathy_span)]'>You hear a voice in your head...</span>\
|
||||
<span class='[initial(mimiced_type.telepathy_span)]'> [get_telepath_message()]</span>\
|
||||
")
|
||||
return TRUE
|
||||
|
||||
/datum/hallucination/telepathy/proc/get_telepath_message()
|
||||
if(prob(0.001))
|
||||
return "horse"
|
||||
|
||||
var/memo = pick(
|
||||
pick_list_replacements(HALLUCINATION_FILE, "advice"),
|
||||
pick_list_replacements(HALLUCINATION_FILE, "aggressive"),
|
||||
pick_list_replacements(HALLUCINATION_FILE, "conversation"),
|
||||
pick_list_replacements(HALLUCINATION_FILE, "didyouhearthat"),
|
||||
pick_list_replacements(HALLUCINATION_FILE, "doubt"),
|
||||
pick_list_replacements(HALLUCINATION_FILE, "escape"),
|
||||
pick_list_replacements(HALLUCINATION_FILE, "getout"),
|
||||
pick_list_replacements(HALLUCINATION_FILE, "greetings"),
|
||||
pick_list_replacements(HALLUCINATION_FILE, "suspicion"),
|
||||
)
|
||||
var/names = pick(
|
||||
first_name(hallucinator.name),
|
||||
last_name(hallucinator.name),
|
||||
first_name(hallucinator.real_name),
|
||||
last_name(hallucinator.real_name),
|
||||
)
|
||||
|
||||
return replacetext(memo, "%TARGETNAME%", names)
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Xeno crawls from nearby vent, jumps at you, and goes back in.
|
||||
/datum/hallucination/xeno_attack
|
||||
random_hallucination_weight = 2
|
||||
hallucination_tier = HALLUCINATION_TIER_RARE
|
||||
|
||||
/datum/hallucination/xeno_attack/start()
|
||||
var/turf/xeno_attack_source
|
||||
|
||||
Reference in New Issue
Block a user