mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 01:34:01 +00:00
* Pulls apart the vestiges of components still hanging onto signals * update modular --------- Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com>
317 lines
9.9 KiB
Plaintext
317 lines
9.9 KiB
Plaintext
/// Shoots a random, fake projectile to the hallucinator
|
|
/datum/hallucination/stray_bullet
|
|
random_hallucination_weight = 7
|
|
|
|
/datum/hallucination/stray_bullet/start()
|
|
var/list/turf/starting_locations = list()
|
|
for(var/turf/open/open_out_of_view in view(world.view + 1, hallucinator) - view(world.view, hallucinator))
|
|
starting_locations += open_out_of_view
|
|
if(!length(starting_locations))
|
|
return FALSE
|
|
|
|
var/turf/start = pick(starting_locations)
|
|
var/fake_type = pick(subtypesof(/obj/projectile/hallucination))
|
|
|
|
feedback_details += "Type: [fake_type], Source: ([start.x], [start.y], [start.z])"
|
|
|
|
var/obj/projectile/hallucination/fake_projectile = new fake_type(start, src)
|
|
|
|
fake_projectile.preparePixelProjectile(hallucinator, start)
|
|
fake_projectile.fire()
|
|
|
|
QDEL_IN(src, 10 SECONDS) // Should clean up the projectile if it somehow gets stuck.
|
|
return TRUE
|
|
|
|
/// Hallucinated projectiles.
|
|
/obj/projectile/hallucination
|
|
name = "bullet"
|
|
icon = null
|
|
icon_state = null
|
|
hitsound = ""
|
|
suppressed = SUPPRESSED_VERY
|
|
ricochets_max = 0
|
|
ricochet_chance = 0
|
|
damage = 0
|
|
projectile_type = /obj/projectile/hallucination
|
|
log_override = TRUE
|
|
/// Our parent hallucination that's created us
|
|
var/datum/hallucination/parent
|
|
/// The image that represents our projectile itself
|
|
var/image/fake_bullet
|
|
|
|
var/hal_icon = 'icons/obj/weapons/guns/projectiles.dmi'
|
|
var/hal_icon_state
|
|
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/projectile/hallucination/Initialize(mapload, datum/hallucination/parent)
|
|
. = ..()
|
|
if(!parent)
|
|
stack_trace("[type] was created without a parent hallucination.")
|
|
return INITIALIZE_HINT_QDEL
|
|
|
|
src.parent = parent
|
|
RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(parent_deleting))
|
|
|
|
|
|
/obj/projectile/hallucination/Destroy()
|
|
if(!QDELETED(parent.hallucinator))
|
|
parent.hallucinator.client?.images -= fake_bullet
|
|
fake_bullet = null
|
|
|
|
UnregisterSignal(parent, COMSIG_QDELETING)
|
|
parent = null
|
|
return ..()
|
|
|
|
/// Signal proc for [COMSIG_QDELETING], if our associated hallucination deletes, we need to clean up
|
|
/obj/projectile/hallucination/proc/parent_deleting(datum/source)
|
|
SIGNAL_HANDLER
|
|
|
|
qdel(src)
|
|
|
|
/obj/projectile/hallucination/fire()
|
|
if(hal_fire_sound)
|
|
parent.hallucinator.playsound_local(get_turf(src), hal_fire_sound, 60, TRUE)
|
|
|
|
fake_bullet = image(hal_icon, src, hal_icon_state, ABOVE_MOB_LAYER)
|
|
parent.hallucinator.client?.images += fake_bullet
|
|
return ..()
|
|
|
|
/obj/projectile/hallucination/on_hit(atom/target, blocked, pierce_hit)
|
|
. = ..()
|
|
if(. != BULLET_ACT_HIT)
|
|
return
|
|
|
|
if(ismob(target))
|
|
if(hal_hitsound)
|
|
parent.hallucinator.playsound_local(target, hal_hitsound, 100, 1)
|
|
on_mob_hit(target)
|
|
|
|
else
|
|
if(hal_hitsound_wall)
|
|
parent.hallucinator.playsound_local(loc, hal_hitsound_wall, 40, 1)
|
|
if(hal_impact_effect_wall)
|
|
spawn_hit(target, TRUE)
|
|
|
|
qdel(src)
|
|
return TRUE
|
|
|
|
/// Called when a mob is hit by the fake projectile
|
|
/obj/projectile/hallucination/proc/on_mob_hit(mob/living/hit_mob)
|
|
if(hit_mob == parent.hallucinator)
|
|
to_chat(parent.hallucinator, span_userdanger("[hit_mob] is hit by \a [src] in the chest!"))
|
|
apply_effect_to_hallucinator(parent.hallucinator)
|
|
|
|
else if(hit_mob in view(parent.hallucinator))
|
|
to_chat(parent.hallucinator, span_danger("[hit_mob] 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(hit_mob))
|
|
spawn_blood(hit_mob, splatter_dir)
|
|
|
|
else if(hal_impact_effect)
|
|
spawn_hit(hit_mob, FALSE)
|
|
|
|
/// Called when the hallucinator themselves are hit by the fake projectile
|
|
/obj/projectile/hallucination/proc/apply_effect_to_hallucinator(mob/living/afflicted)
|
|
return
|
|
|
|
/// Called after a mob is hit by the fake projectile, and our fake projectile is of brute type, to create fake blood
|
|
/obj/projectile/hallucination/proc/spawn_blood(mob/living/bleeding, set_dir)
|
|
if(!parent.hallucinator.client) // Purely visual, don't need to do this for clientless mobs
|
|
return
|
|
|
|
var/splatter_icon_state
|
|
if(ISDIAGONALDIR(set_dir))
|
|
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', bleeding, 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
|
|
|
|
parent.hallucinator.client?.images |= blood
|
|
animate(blood, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = 5)
|
|
addtimer(CALLBACK(src, PROC_REF(clean_up_blood), blood), 0.5 SECONDS)
|
|
|
|
/obj/projectile/hallucination/proc/clean_up_blood(image/blood)
|
|
parent.hallucinator.client?.images -= blood
|
|
|
|
/// Called with a non-mob atom was hit by our fake projectile, or a mob was hit and our damge type is not brute
|
|
/obj/projectile/hallucination/proc/spawn_hit(atom/hit_atom, is_wall)
|
|
if(!parent.hallucinator.client) // Purely visual, don't need to do this for clientless mobs
|
|
return
|
|
|
|
var/image/hit_effect = image('icons/effects/blood.dmi', hit_atom, is_wall ? hal_impact_effect_wall : hal_impact_effect, ABOVE_MOB_LAYER)
|
|
hit_effect.pixel_x = hit_atom.pixel_x + rand(-4,4)
|
|
hit_effect.pixel_y = hit_atom.pixel_y + rand(-4,4)
|
|
parent.hallucinator.client.images |= hit_effect
|
|
addtimer(CALLBACK(src, PROC_REF(clean_up_hit), hit_effect), is_wall ? hit_duration_wall : hit_duration)
|
|
|
|
/obj/projectile/hallucination/proc/clean_up_hit(image/hit_effect)
|
|
parent.hallucinator.client?.images -= hit_effect
|
|
|
|
/obj/projectile/hallucination/bullet
|
|
name = "bullet"
|
|
hal_icon_state = "bullet"
|
|
hal_fire_sound = "gunshot"
|
|
hal_hitsound = 'sound/weapons/pierce.ogg'
|
|
hal_hitsound_wall = SFX_RICOCHET
|
|
hal_impact_effect = "impact_bullet"
|
|
hal_impact_effect_wall = "impact_bullet"
|
|
hit_duration = 5
|
|
hit_duration_wall = 5
|
|
|
|
/obj/projectile/hallucination/bullet/apply_effect_to_hallucinator(mob/living/afflicted)
|
|
afflicted.adjustStaminaLoss(60)
|
|
|
|
/obj/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
|
|
|
|
ricochets_max = 50
|
|
ricochet_chance = 80
|
|
reflectable = REFLECT_NORMAL // No idea if this works
|
|
|
|
/obj/projectile/hallucination/laser/apply_effect_to_hallucinator(mob/living/afflicted)
|
|
afflicted.adjustStaminaLoss(20)
|
|
afflicted.adjust_eye_blur(4 SECONDS)
|
|
|
|
/obj/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/projectile/hallucination/taser/apply_effect_to_hallucinator(mob/living/afflicted)
|
|
afflicted.Paralyze(10 SECONDS)
|
|
afflicted.adjust_stutter(40 SECONDS)
|
|
if(HAS_TRAIT(afflicted, TRAIT_HULK))
|
|
afflicted.say(pick(
|
|
";RAAAAAAAARGH!",
|
|
";HNNNNNNNNNGGGGGGH!",
|
|
";GWAAAAAAAARRRHHH!",
|
|
"NNNNNNNNGGGGGGGGHH!",
|
|
";AAAAAAARRRGH!"),
|
|
forced = "hulk (hallucinating)",
|
|
)
|
|
else if(!afflicted.check_stun_immunity(CANKNOCKDOWN))
|
|
addtimer(CALLBACK(afflicted, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 20), 0.5 SECONDS)
|
|
|
|
/obj/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
|
|
|
|
ricochets_max = 50
|
|
ricochet_chance = 80
|
|
reflectable = REFLECT_NORMAL // No idea if this works
|
|
|
|
/obj/projectile/hallucination/disabler/apply_effect_to_hallucinator(mob/living/afflicted)
|
|
afflicted.adjustStaminaLoss(30)
|
|
|
|
/obj/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/projectile/hallucination/ebow/apply_effect_to_hallucinator(mob/living/afflicted)
|
|
afflicted.adjust_slurring(10 SECONDS)
|
|
afflicted.Knockdown(1 SECONDS)
|
|
afflicted.adjustStaminaLoss(75) // 60 stam + 15 tox
|
|
afflicted.adjust_eye_blur(20 SECONDS)
|
|
|
|
/obj/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/projectile/hallucination/change/apply_effect_to_hallucinator(mob/living/afflicted)
|
|
// Future idea: Make it so any other mob hit appear to be polymorphed to the hallucinator
|
|
afflicted.cause_hallucination( \
|
|
get_random_valid_hallucination_subtype(/datum/hallucination/delusion/preset), \
|
|
"fake [name]", \
|
|
duration = 30 SECONDS, \
|
|
affects_us = TRUE, \
|
|
affects_others = FALSE, \
|
|
skip_nearby = FALSE, \
|
|
play_wabbajack = TRUE, \
|
|
)
|
|
|
|
/obj/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/projectile/hallucination/death/apply_effect_to_hallucinator(mob/living/afflicted)
|
|
afflicted.cause_hallucination(/datum/hallucination/death, "fake [name]")
|