Files
Bubberstation/code/game/objects/effects/anomalies.dm
SkyratBot 98e95fde9b [MIRROR] Rename "Delimber" anomaly to "Bioscrambler" anomaly. [MDB IGNORE] (#14484)
* Rename "Delimber" anomaly to "Bioscrambler" anomaly. (#67886)

Renames all occurrences of "delimber", "delimber_anomaly", "delimbering", etc. to "bioscrambler", "bioscrambler_anomaly", and "bioscrambling", etc.

* Rename "Delimber" anomaly to "Bioscrambler" anomaly.

Co-authored-by: skylord-a52 <skylord-a52@users.noreply.github.com>
2022-06-24 21:01:08 +01:00

550 lines
16 KiB
Plaintext

//Anomalies, used for events. Note that these DO NOT work by themselves; their procs are called by the event datum.
/// Chance of taking a step per second
#define ANOMALY_MOVECHANCE 45
/obj/effect/anomaly
name = "anomaly"
desc = "A mysterious anomaly, seen commonly only in the region of space that the station orbits..."
icon_state = "bhole3"
density = FALSE
anchored = TRUE
light_range = 3
var/obj/item/assembly/signaler/anomaly/aSignal = /obj/item/assembly/signaler/anomaly
var/area/impact_area
var/lifespan = 990
var/death_time
var/countdown_colour
var/obj/effect/countdown/anomaly/countdown
/// Do we drop a core when we're neutralized?
var/drops_core = TRUE
///Do we keep on living forever?
var/immortal = FALSE
/obj/effect/anomaly/Initialize(mapload, new_lifespan, drops_core = TRUE)
. = ..()
SSpoints_of_interest.make_point_of_interest(src)
START_PROCESSING(SSobj, src)
impact_area = get_area(src)
if (!impact_area)
return INITIALIZE_HINT_QDEL
src.drops_core = drops_core
aSignal = new aSignal(src)
aSignal.code = rand(1,100)
aSignal.anomaly_type = type
var/frequency = rand(MIN_FREE_FREQ, MAX_FREE_FREQ)
if(ISMULTIPLE(frequency, 2))//signaller frequencies are always uneven!
frequency++
aSignal.set_frequency(frequency)
if(new_lifespan)
lifespan = new_lifespan
death_time = world.time + lifespan
countdown = new(src)
if(countdown_colour)
countdown.color = countdown_colour
countdown.start()
/obj/effect/anomaly/process(delta_time)
anomalyEffect(delta_time)
if(death_time < world.time && !immortal)
if(loc)
detonate()
qdel(src)
/obj/effect/anomaly/Destroy()
STOP_PROCESSING(SSobj, src)
QDEL_NULL(countdown)
if(aSignal)
QDEL_NULL(aSignal)
return ..()
/obj/effect/anomaly/proc/anomalyEffect(delta_time)
if(DT_PROB(ANOMALY_MOVECHANCE, delta_time))
step(src,pick(GLOB.alldirs))
/obj/effect/anomaly/proc/detonate()
return
/obj/effect/anomaly/ex_act(severity, target)
if(severity >= EXPLODE_DEVASTATE)
qdel(src)
/obj/effect/anomaly/proc/anomalyNeutralize()
new /obj/effect/particle_effect/fluid/smoke/bad(loc)
if(drops_core)
aSignal.forceMove(drop_location())
aSignal = null
// else, anomaly core gets deleted by qdel(src).
qdel(src)
/obj/effect/anomaly/attackby(obj/item/weapon, mob/user, params)
if(weapon.tool_behaviour == TOOL_ANALYZER)
to_chat(user, span_notice("Analyzing... [src]'s unstable field is fluctuating along frequency [format_frequency(aSignal.frequency)], code [aSignal.code]."))
return TRUE
return ..()
///////////////////////
/atom/movable/warp_effect
plane = GRAVITY_PULSE_PLANE
appearance_flags = PIXEL_SCALE|LONG_GLIDE // no tile bound so you can see it around corners and so
icon = 'icons/effects/light_overlays/light_352.dmi'
icon_state = "light"
pixel_x = -176
pixel_y = -176
/obj/effect/anomaly/grav
name = "gravitational anomaly"
icon_state = "shield2"
density = FALSE
aSignal = /obj/item/assembly/signaler/anomaly/grav
var/boing = 0
///Warp effect holder for displacement filter to "pulse" the anomaly
var/atom/movable/warp_effect/warp
/obj/effect/anomaly/grav/Initialize(mapload, new_lifespan, drops_core)
. = ..()
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = .proc/on_entered,
)
AddElement(/datum/element/connect_loc, loc_connections)
warp = new(src)
vis_contents += warp
/obj/effect/anomaly/grav/Destroy()
vis_contents -= warp
warp = null
return ..()
/obj/effect/anomaly/grav/anomalyEffect(delta_time)
..()
boing = 1
for(var/obj/O in orange(4, src))
if(!O.anchored)
step_towards(O,src)
for(var/mob/living/M in range(0, src))
gravShock(M)
for(var/mob/living/M in orange(4, src))
if(!M.mob_negates_gravity())
step_towards(M,src)
for(var/obj/O in range(0,src))
if(!O.anchored)
if(isturf(O.loc))
var/turf/T = O.loc
if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE && HAS_TRAIT(O, TRAIT_T_RAY_VISIBLE))
continue
var/mob/living/target = locate() in view(4,src)
if(target && !target.stat)
O.throw_at(target, 5, 10)
//anomaly quickly contracts then slowly expands it's ring
animate(warp, time = delta_time*3, transform = matrix().Scale(0.5,0.5))
animate(time = delta_time*7, transform = matrix())
/obj/effect/anomaly/grav/proc/on_entered(datum/source, atom/movable/AM)
SIGNAL_HANDLER
gravShock(AM)
/obj/effect/anomaly/grav/Bump(atom/A)
gravShock(A)
/obj/effect/anomaly/grav/Bumped(atom/movable/AM)
gravShock(AM)
/obj/effect/anomaly/grav/proc/gravShock(mob/living/A)
if(boing && isliving(A) && !A.stat)
A.Paralyze(40)
var/atom/target = get_edge_target_turf(A, get_dir(src, get_step_away(A, src)))
A.throw_at(target, 5, 1)
boing = 0
/obj/effect/anomaly/grav/high
var/datum/proximity_monitor/advanced/gravity/grav_field
/obj/effect/anomaly/grav/high/Initialize(mapload, new_lifespan)
. = ..()
INVOKE_ASYNC(src, .proc/setup_grav_field)
/obj/effect/anomaly/grav/high/proc/setup_grav_field()
grav_field = new(src, 7, TRUE, rand(0, 3))
/obj/effect/anomaly/grav/high/detonate()
for(var/obj/machinery/gravity_generator/main/the_generator in GLOB.machines)
if(is_station_level(the_generator.z))
the_generator.blackout()
/obj/effect/anomaly/grav/high/Destroy()
QDEL_NULL(grav_field)
. = ..()
/////////////////////
/obj/effect/anomaly/flux
name = "flux wave anomaly"
icon_state = "electricity2"
density = TRUE
aSignal = /obj/item/assembly/signaler/anomaly/flux
var/canshock = FALSE
var/shockdamage = 20
var/explosive = FLUX_EXPLOSIVE
/obj/effect/anomaly/flux/Initialize(mapload, new_lifespan, drops_core = TRUE, explosive = FLUX_EXPLOSIVE)
. = ..()
src.explosive = explosive
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = .proc/on_entered,
)
AddElement(/datum/element/connect_loc, loc_connections)
/obj/effect/anomaly/flux/anomalyEffect()
..()
canshock = TRUE
for(var/mob/living/M in range(0, src))
mobShock(M)
/obj/effect/anomaly/flux/update_overlays()
. = ..()
. += emissive_appearance(icon, icon_state, alpha=src.alpha)
/obj/effect/anomaly/flux/proc/on_entered(datum/source, atom/movable/AM)
SIGNAL_HANDLER
mobShock(AM)
/obj/effect/anomaly/flux/Bump(atom/A)
mobShock(A)
/obj/effect/anomaly/flux/Bumped(atom/movable/AM)
mobShock(AM)
/obj/effect/anomaly/flux/proc/mobShock(mob/living/M)
if(canshock && istype(M))
canshock = FALSE
M.electrocute_act(shockdamage, name, flags = SHOCK_NOGLOVES)
/obj/effect/anomaly/flux/detonate()
switch(explosive)
if(FLUX_EXPLOSIVE)
explosion(src, devastation_range = 1, heavy_impact_range = 4, light_impact_range = 16, flash_range = 18) //Low devastation, but hits a lot of stuff.
if(FLUX_LOW_EXPLOSIVE)
explosion(src, heavy_impact_range = 1, light_impact_range = 4, flash_range = 6)
if(FLUX_NO_EXPLOSION)
new /obj/effect/particle_effect/sparks(loc)
/////////////////////
/obj/effect/anomaly/bluespace
name = "bluespace anomaly"
icon = 'icons/obj/guns/projectiles.dmi'
icon_state = "bluespace"
density = TRUE
aSignal = /obj/item/assembly/signaler/anomaly/bluespace
/obj/effect/anomaly/bluespace/anomalyEffect()
..()
for(var/mob/living/M in range(1,src))
do_teleport(M, locate(M.x, M.y, M.z), 4, channel = TELEPORT_CHANNEL_BLUESPACE)
/obj/effect/anomaly/bluespace/Bumped(atom/movable/AM)
if(isliving(AM))
do_teleport(AM, locate(AM.x, AM.y, AM.z), 8, channel = TELEPORT_CHANNEL_BLUESPACE)
/obj/effect/anomaly/bluespace/detonate()
var/turf/T = pick(get_area_turfs(impact_area))
if(!T)
return
// Calculate new position (searches through beacons in world)
var/obj/item/beacon/chosen
var/list/possible = list()
for(var/obj/item/beacon/W in GLOB.teleportbeacons)
possible += W
if(possible.len > 0)
chosen = pick(possible)
if(!chosen)
return
// Calculate previous position for transition
var/turf/FROM = T // the turf of origin we're travelling FROM
var/turf/TO = get_turf(chosen) // the turf of origin we're travelling TO
playsound(TO, 'sound/effects/phasein.ogg', 100, TRUE)
priority_announce("Massive bluespace translocation detected.", "Anomaly Alert", ANNOUNCER_MASSIVEBSPACEANOMALIES) //SKYRAT EDIT CHANGE
var/list/flashers = list()
for(var/mob/living/carbon/C in viewers(TO, null))
if(C.flash_act())
flashers += C
var/y_distance = TO.y - FROM.y
var/x_distance = TO.x - FROM.x
for (var/atom/movable/A in urange(12, FROM )) // iterate thru list of mobs in the area
if(istype(A, /obj/item/beacon))
continue // don't teleport beacons because that's just insanely stupid
if(iscameramob(A))
continue // Don't mess with AI eye, blob eye, xenobio or advanced cameras
if(A.anchored)
continue
var/turf/newloc = locate(A.x + x_distance, A.y + y_distance, TO.z) // calculate the new place
if(!A.Move(newloc) && newloc) // if the atom, for some reason, can't move, FORCE them to move! :) We try Move() first to invoke any movement-related checks the atom needs to perform after moving
A.forceMove(newloc)
if(ismob(A) && !(A in flashers)) // don't flash if we're already doing an effect
var/mob/give_sparkles = A
if(give_sparkles.client)
blue_effect(give_sparkles)
/obj/effect/anomaly/bluespace/proc/blue_effect(mob/make_sparkle)
make_sparkle.overlay_fullscreen("bluespace_flash", /atom/movable/screen/fullscreen/bluespace_sparkle, 1)
addtimer(CALLBACK(make_sparkle, /mob/.proc/clear_fullscreen, "bluespace_flash"), 2 SECONDS)
/////////////////////
/obj/effect/anomaly/pyro
name = "pyroclastic anomaly"
icon_state = "mustard"
var/ticks = 0
/// How many seconds between each gas release
var/releasedelay = 10
aSignal = /obj/item/assembly/signaler/anomaly/pyro
/obj/effect/anomaly/pyro/anomalyEffect(delta_time)
..()
ticks += delta_time
if(ticks < releasedelay)
return
else
ticks -= releasedelay
var/turf/open/T = get_turf(src)
if(istype(T))
T.atmos_spawn_air("o2=5;plasma=5;TEMP=1000")
/obj/effect/anomaly/pyro/detonate()
INVOKE_ASYNC(src, .proc/makepyroslime)
/obj/effect/anomaly/pyro/proc/makepyroslime()
var/turf/open/T = get_turf(src)
if(istype(T))
T.atmos_spawn_air("o2=500;plasma=500;TEMP=1000") //Make it hot and burny for the new slime
var/new_colour = pick("red", "orange")
var/mob/living/simple_animal/slime/S = new(T, new_colour)
S.rabid = TRUE
S.amount_grown = SLIME_EVOLUTION_THRESHOLD
S.Evolve()
var/datum/action/innate/slime/reproduce/A = new
A.Grant(S)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as a pyroclastic anomaly slime?", ROLE_SENTIENCE, null, 10 SECONDS, S, POLL_IGNORE_PYROSLIME)
if(LAZYLEN(candidates))
var/mob/dead/observer/chosen = pick(candidates)
S.key = chosen.key
S.mind.special_role = ROLE_PYROCLASTIC_SLIME
var/policy = get_policy(ROLE_PYROCLASTIC_SLIME)
if (policy)
to_chat(S, policy)
log_game("[key_name(S.key)] was made into a slime by pyroclastic anomaly at [AREACOORD(T)].")
/////////////////////
/obj/effect/anomaly/bhole
name = "vortex anomaly"
icon_state = "bhole3"
desc = "That's a nice station you have there. It'd be a shame if something happened to it."
aSignal = /obj/item/assembly/signaler/anomaly/vortex
/obj/effect/anomaly/bhole/anomalyEffect()
..()
if(!isturf(loc)) //blackhole cannot be contained inside anything. Weird stuff might happen
qdel(src)
return
grav(rand(0,3), rand(2,3), 50, 25)
//Throwing stuff around!
for(var/obj/O in range(2,src))
if(O == src)
return //DON'T DELETE YOURSELF GOD DAMN
if(!O.anchored)
var/mob/living/target = locate() in view(4,src)
if(target && !target.stat)
O.throw_at(target, 7, 5)
else
SSexplosions.med_mov_atom += O
/obj/effect/anomaly/bhole/proc/grav(r, ex_act_force, pull_chance, turf_removal_chance)
for(var/t = -r, t < r, t++)
affect_coord(x+t, y-r, ex_act_force, pull_chance, turf_removal_chance)
affect_coord(x-t, y+r, ex_act_force, pull_chance, turf_removal_chance)
affect_coord(x+r, y+t, ex_act_force, pull_chance, turf_removal_chance)
affect_coord(x-r, y-t, ex_act_force, pull_chance, turf_removal_chance)
/obj/effect/anomaly/bhole/proc/affect_coord(x, y, ex_act_force, pull_chance, turf_removal_chance)
//Get turf at coordinate
var/turf/T = locate(x, y, z)
if(isnull(T))
return
//Pulling and/or ex_act-ing movable atoms in that turf
if(prob(pull_chance))
for(var/obj/O in T.contents)
if(O.anchored)
switch(ex_act_force)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += O
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += O
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += O
else
step_towards(O,src)
for(var/mob/living/M in T.contents)
step_towards(M,src)
//Damaging the turf
if( T && prob(turf_removal_chance) )
switch(ex_act_force)
if(EXPLODE_DEVASTATE)
SSexplosions.highturf += T
if(EXPLODE_HEAVY)
SSexplosions.medturf += T
if(EXPLODE_LIGHT)
SSexplosions.lowturf += T
/obj/effect/anomaly/bioscrambler
name = "bioscrambler anomaly"
icon_state = "bioscrambler_anomaly"
aSignal = /obj/item/assembly/signaler/anomaly/bioscrambler
immortal = TRUE
/// Cooldown for every anomaly pulse
COOLDOWN_DECLARE(pulse_cooldown)
/// How many seconds between each anomaly pulses
var/pulse_delay = 15 SECONDS
/// Range of the anomaly pulse
var/range = 5
///Lists for zones and bodyparts to swap and randomize
var/static/list/zones = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
var/static/list/chests
var/static/list/heads
var/static/list/l_arms
var/static/list/r_arms
var/static/list/l_legs
var/static/list/r_legs
/obj/effect/anomaly/bioscrambler/Initialize(mapload, new_lifespan, drops_core)
. = ..()
if(!chests)
chests = typesof(/obj/item/bodypart/chest)
if(!heads)
heads = typesof(/obj/item/bodypart/head)
if(!l_arms)
l_arms = typesof(/obj/item/bodypart/l_arm)
if(!r_arms)
r_arms = typesof(/obj/item/bodypart/r_arm)
if(!l_legs)
l_legs = typesof(/obj/item/bodypart/l_leg)
if(!r_legs)
r_legs = typesof(/obj/item/bodypart/r_leg)
/obj/effect/anomaly/bioscrambler/anomalyEffect(delta_time)
. = ..()
if(!COOLDOWN_FINISHED(src, pulse_cooldown))
return
COOLDOWN_START(src, pulse_cooldown, pulse_delay)
swap_parts(range)
/obj/effect/anomaly/bioscrambler/proc/swap_parts(swap_range)
for(var/mob/living/carbon/nearby in range(swap_range, src))
if(nearby.run_armor_check(attack_flag = BIO, absorb_text = "Your armor protects you from [src]!") >= 100)
continue //We are protected
var/picked_zone = pick(zones)
var/obj/item/bodypart/picked_user_part = nearby.get_bodypart(picked_zone)
var/obj/item/bodypart/picked_part
switch(picked_zone)
if(BODY_ZONE_HEAD)
picked_part = pick(heads)
if(BODY_ZONE_CHEST)
picked_part = pick(chests)
if(BODY_ZONE_L_ARM)
picked_part = pick(l_arms)
if(BODY_ZONE_R_ARM)
picked_part = pick(r_arms)
if(BODY_ZONE_L_LEG)
picked_part = pick(l_legs)
if(BODY_ZONE_R_LEG)
picked_part = pick(r_legs)
var/obj/item/bodypart/new_part = new picked_part()
new_part.replace_limb(nearby, TRUE)
if(picked_user_part)
qdel(picked_user_part)
nearby.update_body(TRUE)
balloon_alert(nearby, "something has changed about you")
/obj/effect/anomaly/hallucination
name = "hallucination anomaly"
icon_state = "hallucination_anomaly"
aSignal = /obj/item/assembly/signaler/anomaly/hallucination
/// Time passed since the last effect, increased by delta_time of the SSobj
var/ticks = 0
/// How many seconds between each small hallucination pulses
var/release_delay = 5
/obj/effect/anomaly/hallucination/anomalyEffect(delta_time)
. = ..()
ticks += delta_time
if(ticks < release_delay)
return
ticks -= release_delay
var/turf/open/our_turf = get_turf(src)
if(istype(our_turf))
hallucination_pulse(our_turf, 5)
/obj/effect/anomaly/hallucination/detonate()
var/turf/open/our_turf = get_turf(src)
if(istype(our_turf))
hallucination_pulse(our_turf, 10)
/obj/effect/anomaly/hallucination/proc/hallucination_pulse(turf/open/location, range)
for(var/mob/living/carbon/human/near in view(location, range))
// If they are immune to hallucinations.
if (HAS_TRAIT(near, TRAIT_MADNESS_IMMUNE) || (near.mind && HAS_TRAIT(near.mind, TRAIT_MADNESS_IMMUNE)))
continue
// Blind people don't get hallucinations.
if (near.is_blind())
continue
// Everyone else gets hallucinations.
var/dist = sqrt(1 / max(1, get_dist(near, location)))
near.hallucination += 50 * dist
near.hallucination = clamp(near.hallucination, 0, 150)
var/list/messages = list(
"You feel your conscious mind fall apart!",
"Reality warps around you!",
"Something's wispering around you!",
"You are going insane!",
)
to_chat(near, span_warning(pick(messages)))
#undef ANOMALY_MOVECHANCE