mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-29 18:40:42 +00:00
Pyroclastic anomalies make player-controlled adult slimes. Tweaks announcement/spawn of anomalies some. Flux anomalies are super dangerous and are now announced ahead of time, and pyroclastic anomalies are somewhat less devastating so they're given some time before announcing, like gravitational ones.
337 lines
9.0 KiB
Plaintext
337 lines
9.0 KiB
Plaintext
//Anomalies, used for events. Note that these DO NOT work by themselves; their procs are called by the event datum.
|
|
|
|
/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 = 0
|
|
anchored = 1
|
|
light_range = 3
|
|
var/movechance = 70
|
|
var/obj/item/device/assembly/signaler/anomaly/aSignal = null
|
|
var/area/impact_area
|
|
|
|
var/lifespan = 990
|
|
var/death_time
|
|
|
|
var/countdown_colour
|
|
var/obj/effect/countdown/anomaly/countdown
|
|
|
|
/obj/effect/anomaly/New()
|
|
..()
|
|
poi_list |= src
|
|
START_PROCESSING(SSobj, src)
|
|
impact_area = get_area(src)
|
|
|
|
aSignal = new(src)
|
|
aSignal.name = "[name] core"
|
|
aSignal.code = rand(1,100)
|
|
|
|
aSignal.frequency = rand(1200, 1599)
|
|
if(IsMultiple(aSignal.frequency, 2))//signaller frequencies are always uneven!
|
|
aSignal.frequency++
|
|
|
|
death_time = world.time + lifespan
|
|
countdown = new(src)
|
|
if(countdown_colour)
|
|
countdown.color = countdown_colour
|
|
countdown.start()
|
|
|
|
/obj/effect/anomaly/process()
|
|
anomalyEffect()
|
|
if(death_time < world.time)
|
|
if(loc)
|
|
detonate()
|
|
qdel(src)
|
|
|
|
/obj/effect/anomaly/Destroy()
|
|
poi_list.Remove(src)
|
|
STOP_PROCESSING(SSobj, src)
|
|
qdel(countdown)
|
|
return ..()
|
|
|
|
/obj/effect/anomaly/proc/anomalyEffect()
|
|
if(prob(movechance))
|
|
step(src,pick(alldirs))
|
|
|
|
/obj/effect/anomaly/proc/detonate()
|
|
return
|
|
|
|
/obj/effect/anomaly/ex_act(severity, target)
|
|
if(severity == 1)
|
|
qdel(src)
|
|
|
|
/obj/effect/anomaly/proc/anomalyNeutralize()
|
|
new /obj/effect/particle_effect/smoke/bad(loc)
|
|
|
|
for(var/atom/movable/O in src)
|
|
O.loc = src.loc
|
|
|
|
qdel(src)
|
|
|
|
|
|
/obj/effect/anomaly/attackby(obj/item/I, mob/user, params)
|
|
if(istype(I, /obj/item/device/analyzer))
|
|
to_chat(user, "<span class='notice'>Analyzing... [src]'s unstable field is fluctuating along frequency [format_frequency(aSignal.frequency)], code [aSignal.code].</span>")
|
|
|
|
///////////////////////
|
|
|
|
/obj/effect/anomaly/grav
|
|
name = "gravitational anomaly"
|
|
icon_state = "shield2"
|
|
density = 0
|
|
var/boing = 0
|
|
|
|
/obj/effect/anomaly/grav/New()
|
|
..()
|
|
aSignal.origin_tech = "magnets=7"
|
|
|
|
/obj/effect/anomaly/grav/anomalyEffect()
|
|
..()
|
|
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))
|
|
step_towards(M,src)
|
|
for(var/obj/O in range(0,src))
|
|
if(!O.anchored)
|
|
var/mob/living/target = locate() in view(4,src)
|
|
if(target && !target.stat)
|
|
O.throw_at(target, 5, 10)
|
|
|
|
/obj/effect/anomaly/grav/Crossed(mob/A)
|
|
gravShock(A)
|
|
|
|
/obj/effect/anomaly/grav/Bump(mob/A)
|
|
gravShock(A)
|
|
|
|
/obj/effect/anomaly/grav/Bumped(mob/A)
|
|
gravShock(A)
|
|
|
|
/obj/effect/anomaly/grav/proc/gravShock(mob/A)
|
|
if(boing && isliving(A) && !A.stat)
|
|
A.Weaken(2)
|
|
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/flux
|
|
name = "flux wave anomaly"
|
|
icon_state = "electricity2"
|
|
density = 1
|
|
var/canshock = 0
|
|
var/shockdamage = 20
|
|
var/explosive = 1
|
|
|
|
/obj/effect/anomaly/flux/New()
|
|
..()
|
|
aSignal.origin_tech = "powerstorage=7"
|
|
|
|
/obj/effect/anomaly/flux/anomalyEffect()
|
|
..()
|
|
canshock = 1
|
|
for(var/mob/living/M in range(0, src))
|
|
mobShock(M)
|
|
|
|
/obj/effect/anomaly/flux/Crossed(mob/living/M)
|
|
mobShock(M)
|
|
|
|
/obj/effect/anomaly/flux/Bump(mob/living/M)
|
|
mobShock(M)
|
|
|
|
/obj/effect/anomaly/flux/Bumped(mob/living/M)
|
|
mobShock(M)
|
|
|
|
/obj/effect/anomaly/flux/proc/mobShock(mob/living/M)
|
|
if(canshock && istype(M))
|
|
canshock = 0 //Just so you don't instakill yourself if you slam into the anomaly five times in a second.
|
|
if(iscarbon(M))
|
|
if(ishuman(M))
|
|
M.electrocute_act(shockdamage, "[name]", safety=1)
|
|
return
|
|
M.electrocute_act(shockdamage, "[name]")
|
|
return
|
|
else
|
|
M.adjustFireLoss(shockdamage)
|
|
M.visible_message("<span class='danger'>[M] was shocked by \the [name]!</span>", \
|
|
"<span class='userdanger'>You feel a powerful shock coursing through your body!</span>", \
|
|
"<span class='italics'>You hear a heavy electrical crack.</span>")
|
|
|
|
/obj/effect/anomaly/flux/detonate()
|
|
if(explosive)
|
|
explosion(src, 1, 4, 16, 18) //Low devastation, but hits a lot of stuff.
|
|
else
|
|
new /obj/effect/particle_effect/sparks(loc)
|
|
|
|
|
|
/////////////////////
|
|
|
|
/obj/effect/anomaly/bluespace
|
|
name = "bluespace anomaly"
|
|
icon = 'icons/obj/projectiles.dmi'
|
|
icon_state = "bluespace"
|
|
density = 1
|
|
|
|
/obj/effect/anomaly/bluespace/New()
|
|
..()
|
|
aSignal.origin_tech = "bluespace=7"
|
|
|
|
/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)
|
|
|
|
/obj/effect/anomaly/bluespace/Bumped(atom/A)
|
|
if(isliving(A))
|
|
do_teleport(A, locate(A.x, A.y, A.z), 8)
|
|
|
|
/obj/effect/anomaly/bluespace/detonate()
|
|
var/turf/T = safepick(get_area_turfs(impact_area))
|
|
if(T)
|
|
// Calculate new position (searches through beacons in world)
|
|
var/obj/item/device/radio/beacon/chosen
|
|
var/list/possible = list()
|
|
for(var/obj/item/device/radio/beacon/W in teleportbeacons)
|
|
possible += W
|
|
|
|
if(possible.len > 0)
|
|
chosen = pick(possible)
|
|
|
|
if(chosen)
|
|
// 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, 1)
|
|
priority_announce("Massive bluespace translocation detected.", "Anomaly Alert")
|
|
|
|
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/device/radio/beacon)) continue // don't teleport beacons because that's just insanely stupid
|
|
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.loc = newloc
|
|
|
|
spawn()
|
|
if(ismob(A) && !(A in flashers)) // don't flash if we're already doing an effect
|
|
var/mob/M = A
|
|
if(M.client)
|
|
var/obj/blueeffect = new /obj(src)
|
|
blueeffect.screen_loc = "WEST,SOUTH to EAST,NORTH"
|
|
blueeffect.icon = 'icons/effects/effects.dmi'
|
|
blueeffect.icon_state = "shieldsparkles"
|
|
blueeffect.layer = FLASH_LAYER
|
|
blueeffect.plane = FULLSCREEN_PLANE
|
|
blueeffect.mouse_opacity = 0
|
|
M.client.screen += blueeffect
|
|
sleep(20)
|
|
M.client.screen -= blueeffect
|
|
qdel(blueeffect)
|
|
|
|
/////////////////////
|
|
|
|
/obj/effect/anomaly/pyro
|
|
name = "pyroclastic anomaly"
|
|
icon_state = "mustard"
|
|
var/ticks = 0
|
|
|
|
/obj/effect/anomaly/pyro/New()
|
|
..()
|
|
aSignal.origin_tech = "plasmatech=7"
|
|
|
|
/obj/effect/anomaly/pyro/anomalyEffect()
|
|
..()
|
|
ticks++
|
|
if(ticks < 5)
|
|
return
|
|
else
|
|
ticks = 0
|
|
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()
|
|
offer_control(S)
|
|
|
|
/////////////////////
|
|
|
|
/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."
|
|
|
|
/obj/effect/anomaly/bhole/New()
|
|
..()
|
|
aSignal.origin_tech = "engineering=7"
|
|
|
|
/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
|
|
O.ex_act(2)
|
|
|
|
/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)
|
|
O.ex_act(ex_act_force)
|
|
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) )
|
|
T.ex_act(ex_act_force)
|