Anomaly Refactor and Rework (#15259)

* Anomaly Refactor and Rework

* tweaks

* tweaks
This commit is contained in:
Fox McCloud
2021-01-10 14:46:37 -05:00
committed by GitHub
parent 23dfab1a49
commit 84ffa263ca
19 changed files with 415 additions and 342 deletions
+1
View File
@@ -37,6 +37,7 @@
#define SPECIAL_ROLE_MORPH "Morph"
#define SPECIAL_ROLE_MULTIVERSE "Multiverse Traveller"
#define SPECIAL_ROLE_NUKEOPS "Syndicate"
#define SPECIAL_ROLE_PYROCLASTIC_SLIME "Pyroclastic Anomaly Slime"
#define SPECIAL_ROLE_RAIDER "Vox Raider"
#define SPECIAL_ROLE_REVENANT "Revenant"
#define SPECIAL_ROLE_SHADOWLING "Shadowling"
+15
View File
@@ -825,3 +825,18 @@ proc/dd_sortedObjectList(list/incoming)
L1[key] += other_value
else
L1[key] = other_value
/**
* A proc for turning a list into an associative list.
*
* A simple proc for turning all things in a list into an associative list, instead
* Each item in the list will have an associative value of TRUE
* Arguments:
* * flat_list - the list that it passes to make associative
*/
/proc/make_associative(list/flat_list)
. = list()
for(var/thing in flat_list)
.[thing] = TRUE
+24 -24
View File
@@ -1202,99 +1202,99 @@
result = "/obj/mecha/combat/phazon"
steps = list(
//1
list("key"=/obj/item/assembly/signaler/anomaly,
list("key" = /obj/item/assembly/signaler/anomaly/bluespace,
"backkey"=null, //Cannot remove the anomaly core once it's in
"desc"="Anomaly core socket is open and awaiting connection."),
//2
list("key"=TOOL_WELDER,
list("key" = TOOL_WELDER,
"backkey"=TOOL_WRENCH,
"desc"="External armor is wrenched."),
//3
list("key"=TOOL_WRENCH,
list("key" = TOOL_WRENCH,
"backkey"=TOOL_CROWBAR,
"desc"="External armor is installed."),
//4
list("key"=/obj/item/mecha_parts/part/phazon_armor,
list("key" = /obj/item/mecha_parts/part/phazon_armor,
"backkey"=TOOL_WELDER,
"desc"="Phase armor is welded."),
//5
list("key"=TOOL_WELDER,
list("key" = TOOL_WELDER,
"backkey"=TOOL_WRENCH,
"desc"="Phase armor is wrenched."),
//6
list("key"=TOOL_WRENCH,
list("key" = TOOL_WRENCH,
"backkey"=TOOL_CROWBAR,
"desc"="Phase armor is installed."),
//7
list("key"=/obj/item/stack/sheet/plasteel,
list("key" = /obj/item/stack/sheet/plasteel,
"backkey"=TOOL_SCREWDRIVER,
"desc"="The bluespace crystal is engaged."),
//8
list("key"=TOOL_SCREWDRIVER,
list("key" = TOOL_SCREWDRIVER,
"backkey"=/obj/item/wirecutters,
"desc"="The bluespace crystal is connected."),
//9
list("key"=/obj/item/stack/cable_coil,
list("key" = /obj/item/stack/cable_coil,
"backkey"=TOOL_CROWBAR,
"desc"="The bluespace crystal is installed."),
//10
list("key"=/obj/item/stack/ore/bluespace_crystal,
list("key" = /obj/item/stack/ore/bluespace_crystal,
"backkey"=TOOL_SCREWDRIVER,
"desc"="Super capacitor is secured."),
//11
list("key"=TOOL_SCREWDRIVER,
list("key" = TOOL_SCREWDRIVER,
"backkey"=TOOL_CROWBAR,
"desc"="Super capacitor is installed."),
//12
list("key"=/obj/item/stock_parts/capacitor/super,
list("key" = /obj/item/stock_parts/capacitor/super,
"backkey"=TOOL_SCREWDRIVER,
"desc"="Phasic scanner module is secured."),
//13
list("key"=TOOL_SCREWDRIVER,
list("key" = TOOL_SCREWDRIVER,
"backkey"=TOOL_CROWBAR,
"desc"="Phasic scanner module is installed."),
//14
list("key"=/obj/item/stock_parts/scanning_module/phasic,
list("key" = /obj/item/stock_parts/scanning_module/phasic,
"backkey"=TOOL_SCREWDRIVER,
"desc"="Scanning module is secured."),
//15
list("key"=TOOL_SCREWDRIVER,
list("key" = TOOL_SCREWDRIVER,
"backkey"=TOOL_CROWBAR,
"desc"="Scanning module is installed."),
//16
list("key"=/obj/item/circuitboard/mecha/phazon/targeting,
list("key" = /obj/item/circuitboard/mecha/phazon/targeting,
"backkey"=TOOL_SCREWDRIVER,
"desc"="Peripherals control module is secured."),
//17
list("key"=TOOL_SCREWDRIVER,
list("key" = TOOL_SCREWDRIVER,
"backkey"=TOOL_CROWBAR,
"desc"="Peripherals control module is installed"),
//18
list("key"=/obj/item/circuitboard/mecha/phazon/peripherals,
list("key" = /obj/item/circuitboard/mecha/phazon/peripherals,
"backkey"=TOOL_SCREWDRIVER,
"desc"="Central control module is secured."),
//19
list("key"=TOOL_SCREWDRIVER,
list("key" = TOOL_SCREWDRIVER,
"backkey"=TOOL_CROWBAR,
"desc"="Central control module is installed."),
//20
list("key"=/obj/item/circuitboard/mecha/phazon/main,
list("key" = /obj/item/circuitboard/mecha/phazon/main,
"backkey"=TOOL_SCREWDRIVER,
"desc"="The wiring is adjusted."),
//21
list("key"=/obj/item/wirecutters,
list("key" = /obj/item/wirecutters,
"backkey"=TOOL_SCREWDRIVER,
"desc"="The wiring is added."),
//22
list("key"=/obj/item/stack/cable_coil,
list("key" = /obj/item/stack/cable_coil,
"backkey"=TOOL_SCREWDRIVER,
"desc"="The hydraulic systems are active."),
//23
list("key"=TOOL_SCREWDRIVER,
list("key" = TOOL_SCREWDRIVER,
"backkey"=TOOL_WRENCH,
"desc"="The hydraulic systems are connected."),
//24
list("key"=TOOL_WRENCH,
list("key" = TOOL_WRENCH,
"desc"="The hydraulic systems are disconnected.")
)
+5
View File
@@ -259,6 +259,11 @@
..()
construct = new /datum/construction/mecha/phazon_chassis(src)
/obj/item/mecha_parts/chassis/phazon/attackby(obj/item/I, mob/user, params)
. = ..()
if(istype(I, /obj/item/assembly/signaler/anomaly) && !istype(I, /obj/item/assembly/signaler/anomaly/bluespace))
to_chat(user, "<span class='warning'>The anomaly core socket only accepts bluespace anomaly cores!</span>")
/obj/item/mecha_parts/part/phazon_torso
name="Phazon Torso"
icon_state = "phazon_harness"
+238 -101
View File
@@ -1,98 +1,180 @@
//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 70
/obj/effect/anomaly
name = "anomaly"
icon = 'icons/effects/effects.dmi'
desc = "A mysterious anomaly, seen commonly only in the region of space that the station orbits..."
icon_state = "bhole3"
density = 0
anchored = 1
luminosity = 3
var/obj/item/assembly/signaler/anomaly/aSignal = null
density = FALSE
anchored = TRUE
light_range = 3
var/movechance = ANOMALY_MOVECHANCE
var/obj/item/assembly/signaler/anomaly/aSignal = /obj/item/assembly/signaler/anomaly
var/area/impact_area
/// Time in deciseconds before the anomaly triggers
var/lifespan = 990
var/death_time
/obj/effect/anomaly/New()
var/countdown_colour
var/obj/effect/countdown/anomaly/countdown
/// Do we drop a core when we're neutralized?
var/drops_core = TRUE
/obj/effect/anomaly/Initialize(mapload, new_lifespan, _drops_core = TRUE)
. = ..()
set_light(initial(luminosity))
aSignal = new(src)
aSignal.code = rand(1,100)
var/new_frequency = sanitize_frequency(rand(PUBLIC_LOW_FREQ, PUBLIC_HIGH_FREQ))
aSignal.set_frequency(new_frequency)
GLOB.poi_list |= src
START_PROCESSING(SSobj, src)
impact_area = get_area(src)
if(!impact_area)
return INITIALIZE_HINT_QDEL
drops_core = _drops_core
aSignal = new aSignal(src)
aSignal.code = rand(1, 100)
aSignal.anomaly_type = type
var/frequency = rand(PUBLIC_LOW_FREQ, PUBLIC_HIGH_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/Destroy()
QDEL_NULL(aSignal)
GLOB.poi_list.Remove(src)
STOP_PROCESSING(SSobj, src)
QDEL_NULL(countdown)
QDEL_NULL(aSignal)
return ..()
/obj/effect/anomaly/process()
anomalyEffect()
if(death_time < world.time)
if(loc)
detonate()
qdel(src)
/obj/effect/anomaly/proc/anomalyEffect()
if(prob(50))
if(prob(movechance))
step(src, pick(GLOB.alldirs))
/obj/effect/anomaly/proc/detonate()
return
/obj/effect/anomaly/ex_act(severity)
if(severity == EXPLODE_DEVASTATE)
qdel(src)
/obj/effect/anomaly/proc/anomalyNeutralize()
var/turf/T = get_turf(src)
new /obj/effect/particle_effect/smoke/bad(loc)
new /obj/effect/particle_effect/smoke/bad(T)
if(aSignal)
aSignal.forceMove(T)
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/I, mob/user, params)
if(istype(I, /obj/item/analyzer))
to_chat(user, "<span class='notice'>Analyzing... [src]'s unstable field is fluctuating along frequency [aSignal.code]:[format_frequency(aSignal.frequency)].</span>")
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 = 1
var/boing = 0
/obj/effect/anomaly/grav/New()
..()
aSignal.origin_tech = "magnets=7"
density = FALSE
var/boing = FALSE
aSignal = /obj/item/assembly/signaler/anomaly/grav
/obj/effect/anomaly/grav/anomalyEffect()
..()
boing = 1
boing = TRUE
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)
if(!M.mob_negates_gravity())
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/Bump(mob/A)
/obj/effect/anomaly/grav/Crossed(atom/movable/AM)
. = ..()
gravShock(AM)
/obj/effect/anomaly/grav/Bump(atom/A)
gravShock(A)
return
/obj/effect/anomaly/grav/Bumped(mob/A)
gravShock(A)
return
/obj/effect/anomaly/grav/Bumped(atom/movable/AM)
gravShock(AM)
/obj/effect/anomaly/grav/proc/gravShock(var/mob/A)
/obj/effect/anomaly/grav/proc/gravShock(mob/living/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
return
boing = FALSE
/////////////////////
/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 = TRUE
/obj/effect/anomaly/flux/New()
/obj/effect/anomaly/flux/Initialize(mapload, new_lifespan, drops_core = TRUE, _explosive = TRUE)
. = ..()
explosive = _explosive
/obj/effect/anomaly/flux/anomalyEffect()
..()
aSignal.origin_tech = "powerstorage=7"
canshock = TRUE
for(var/mob/living/M in get_turf(src))
mobShock(M)
/obj/effect/anomaly/flux/Crossed(atom/movable/AM)
. = ..()
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 //Just so you don't instakill yourself if you slam into the anomaly five times in a second.
M.electrocute_act(shockdamage, "[name]", safety = TRUE)
/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)
/////////////////////
@@ -100,32 +182,116 @@
name = "bluespace anomaly"
icon = 'icons/obj/projectiles.dmi'
icon_state = "bluespace"
density = 1
density = TRUE
aSignal = /obj/item/assembly/signaler/anomaly/bluespace
/obj/effect/anomaly/bluespace/New()
/obj/effect/anomaly/bluespace/anomalyEffect()
..()
aSignal.origin_tech = "bluespace=7"
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/movable/AM)
if(isliving(AM))
do_teleport(AM, locate(AM.x, AM.y, AM.z), 8)
/obj/effect/anomaly/bluespace/detonate()
var/turf/T = pick(get_area_turfs(impact_area))
if(T)
// Calculate new position (searches through beacons in world)
var/obj/item/radio/beacon/chosen
var/list/possible = list()
for(var/obj/item/radio/beacon/W in GLOB.beacons)
if(!is_station_level(W.z))
continue
possible += W
if(length(possible))
chosen = pick(possible)
if(chosen)
// Calculate previous position for transition
var/turf/turf_from = T // the turf of origin we're travelling FROM
var/turf/turf_to = get_turf(chosen) // the turf of origin we're travelling TO
playsound(turf_to, 'sound/effects/phasein.ogg', 100, TRUE)
GLOB.event_announcement.Announce("Massive bluespace translocation detected.", "Anomaly Alert")
var/list/flashers = list()
for(var/mob/living/carbon/C in viewers(turf_to, null))
if(C.flash_eyes())
flashers += C
var/y_distance = turf_to.y - turf_from.y
var/x_distance = turf_to.x - turf_from.x
for(var/atom/movable/A in urange(12, turf_from)) // iterate thru list of mobs in the area
if(istype(A, /obj/item/radio/beacon))
continue // don't teleport beacons because that's just insanely stupid
if(A.anchored || A.move_resist == INFINITY)
continue
var/turf/newloc = locate(A.x + x_distance, A.y + y_distance, turf_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/M = A
if(M.client)
INVOKE_ASYNC(src, .proc/blue_effect, M)
/obj/effect/anomaly/bluespace/proc/blue_effect(mob/M)
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 = MOUSE_OPACITY_TRANSPARENT
M.client.screen += blueeffect
sleep(20)
M.client.screen -= blueeffect
qdel(blueeffect)
/obj/effect/anomaly/bluespace/Bumped(atom/A)
if(isliving(A))
do_teleport(A, locate(A.x, A.y, A.z), 10)
return
/////////////////////
/obj/effect/anomaly/pyro
name = "pyroclastic anomaly"
icon_state = "mustard"
/obj/effect/anomaly/pyro/New()
..()
aSignal.origin_tech = "plasmatech=7"
var/ticks = 0
aSignal = /obj/item/assembly/signaler/anomaly/pyro
/obj/effect/anomaly/pyro/anomalyEffect()
..()
ticks++
if(ticks < 5)
return
else
ticks = 0
var/turf/simulated/T = get_turf(src)
if(istype(T))
T.atmos_spawn_air(LINDA_SPAWN_HEAT | LINDA_SPAWN_TOXINS, 3)
T.atmos_spawn_air(LINDA_SPAWN_HEAT | LINDA_SPAWN_TOXINS | LINDA_SPAWN_OXYGEN, 5)
/obj/effect/anomaly/pyro/detonate()
INVOKE_ASYNC(src, .proc/makepyroslime)
/obj/effect/anomaly/pyro/proc/makepyroslime()
var/turf/simulated/T = get_turf(src)
if(istype(T))
T.atmos_spawn_air(LINDA_SPAWN_HEAT | LINDA_SPAWN_TOXINS | LINDA_SPAWN_OXYGEN, 500) //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 = SSghost_spawns.poll_candidates("Do you want to play as a pyroclastic anomaly slime?", ROLE_SENTIENT, FALSE, 100, source = S, role_cleanname = "pyroclastic anomaly slime")
if(LAZYLEN(candidates))
var/mob/dead/observer/chosen = pick(candidates)
S.key = chosen.key
S.mind.special_role = SPECIAL_ROLE_PYROCLASTIC_SLIME
log_game("[key_name(S.key)] was made into a slime by pyroclastic anomaly at [AREACOORD(T)].")
/////////////////////
@@ -133,10 +299,7 @@
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"
aSignal = /obj/item/assembly/signaler/anomaly/vortex
/obj/effect/anomaly/bhole/anomalyEffect()
..()
@@ -144,31 +307,31 @@
qdel(src)
return
grav(rand(0,3), rand(2,3), 50, 25)
grav(rand(0, 3), rand(2, 3), 50, 25)
//Throwing stuff around!
for(var/obj/O in orange(1,src))
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(5,src)
if(!target)
return
O.throw_at(target, 5, 10)
return
var/mob/living/target = locate() in view(4, src)
if(target && !target.stat)
O.throw_at(target, 7, 5)
else
O.ex_act(2)
O.ex_act(EXPLODE_HEAVY)
/obj/effect/anomaly/bhole/proc/grav(var/r, var/ex_act_force, var/pull_chance, var/turf_removal_chance)
/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)
return
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(var/x, var/y, var/ex_act_force, var/pull_chance, var/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
if(isnull(T))
return
//Pulling and/or ex_act-ing movable atoms in that turf
if(prob(pull_chance))
@@ -176,38 +339,12 @@
if(O.anchored)
O.ex_act(ex_act_force)
else
step_towards(O,src)
step_towards(O, src)
for(var/mob/living/M in T.contents)
step_towards(M,src)
step_towards(M, src)
//Damaging the turf
if( T && istype(T,/turf/simulated) && prob(turf_removal_chance) )
if(T && prob(turf_removal_chance))
T.ex_act(ex_act_force)
return
/////////////////////
/obj/effect/anomaly/atmos
name = "transformative gas anomaly"
icon_state = "electricity2"
var/gas_type
/obj/effect/anomaly/atmos/New()
..()
gas_type = pick(GAS_N2O, GAS_CO2, GAS_N2)
aSignal.origin_tech = "materials=7" //turning gas into another gas has some interesting implications for material science
//might also work as biotech maybe? Since there's no anomaly for that.
/obj/effect/anomaly/atmos/anomalyEffect()
..()
var/turf/simulated/T = get_turf(src)
if(istype(T))
var/flag
switch(gas_type)
if(GAS_CO2)
flag = LINDA_SPAWN_CO2
if(GAS_N2O)
flag = LINDA_SPAWN_N2O
else
flag = LINDA_SPAWN_NITROGEN
T.atmos_spawn_air(LINDA_SPAWN_20C | flag, 10)
#undef ANOMALY_MOVECHANCE
-17
View File
@@ -151,20 +151,3 @@
SSradio.remove_object(src, frequency)
frequency = new_frequency
radio_connection = SSradio.add_object(src, frequency, RADIO_CHAT)
// Embedded signaller used in anomalies.
/obj/item/assembly/signaler/anomaly
name = "anomaly core"
desc = "The neutralized core of an anomaly. It'd probably be valuable for research."
icon_state = "anomaly core"
item_state = "electronic"
resistance_flags = FIRE_PROOF
receiving = TRUE
/obj/item/assembly/signaler/anomaly/receive_signal(datum/signal/signal)
if(..())
for(var/obj/effect/anomaly/A in orange(0, src))
A.anomalyNeutralize()
/obj/item/assembly/signaler/anomaly/attack_self()
return
+20 -10
View File
@@ -5,22 +5,22 @@
And maybe we'll come back\n\
To earth, who can tell?"
var/displayed_text
var/atom/attached_to
color = "#ff0000"
var/text_size = 4
var/started = FALSE
invisibility = INVISIBILITY_OBSERVER
anchored = TRUE
layer = GHOST_LAYER
layer = MASSIVE_OBJ_LAYER
color = "#ff0000" // text color
var/text_size = 3 // larger values clip when the displayed text is larger than 2 digits.
var/started = FALSE
var/displayed_text
var/atom/attached_to
/obj/effect/countdown/New(atom/A)
/obj/effect/countdown/Initialize(mapload)
. = ..()
attach(A)
attach(loc)
/obj/effect/countdown/examine(mob/user)
. = ..()
. += "This countdown is displaying: [displayed_text]"
. += "This countdown is displaying: [displayed_text]."
/obj/effect/countdown/proc/attach(atom/A)
attached_to = A
@@ -51,7 +51,7 @@
displayed_text = new_val
if(displayed_text)
maptext = "<font size = [text_size]>[displayed_text]</font>"
maptext = "<font face='Small Fonts' size=[text_size]>[displayed_text]</font>"
else
maptext = null
@@ -90,3 +90,13 @@
else if(C.occupant)
var/completion = round(C.get_completion())
return completion
/obj/effect/countdown/anomaly
name = "anomaly countdown"
/obj/effect/countdown/anomaly/get_value()
var/obj/effect/anomaly/A = attached_to
if(!istype(A))
return
var/time_left = max(0, (A.death_time - world.time) / 10)
return round(time_left)
+34 -20
View File
@@ -1,33 +1,47 @@
/datum/event/anomaly
var/obj/effect/anomaly/newAnomaly
name = "Anomaly: Energetic Flux"
var/obj/effect/anomaly/anomaly_path = /obj/effect/anomaly/flux
announceWhen = 1
/datum/event/anomaly/setup(loop=0)
var/safety_loop = loop + 1
if(safety_loop > 50)
kill()
end()
/datum/event/anomaly/proc/findEventArea()
var/static/list/allowed_areas
if(!allowed_areas)
//Places that shouldn't explode
var/list/safe_area_types = typecacheof(list(
/area/turret_protected/ai,
/area/turret_protected/ai_upload,
/area/ai_monitored/storage/emergency,
/area/engine,
/area/solar,
/area/holodeck,
/area/shuttle,
/area/maintenance,
/area/toxins/test_area)
)
//Subtypes from the above that actually should explode.
var/list/unsafe_area_subtypes = typecacheof(list(/area/engine/break_room))
allowed_areas = make_associative(GLOB.the_station_areas) - safe_area_types + unsafe_area_subtypes
var/list/possible_areas = typecache_filter_list(GLOB.all_areas, allowed_areas)
if(length(possible_areas))
return pick(possible_areas)
/datum/event/anomaly/setup()
impact_area = findEventArea()
if(!impact_area)
setup(safety_loop)
CRASH("No valid areas for anomaly found.")
var/list/turf_test = get_area_turfs(impact_area)
if(!turf_test.len)
setup(safety_loop)
if(!length(turf_test))
CRASH("Anomaly: No valid turfs found for [impact_area] - [impact_area.type]")
/datum/event/anomaly/announce()
GLOB.event_announcement.Announce("Localized hyper-energetic flux wave detected on long range scanners. Expected location of impact: [impact_area.name].", "Anomaly Alert")
/datum/event/anomaly/start()
var/turf/T = pick(get_area_turfs(impact_area))
var/newAnomaly
if(T)
newAnomaly = new /obj/effect/anomaly/flux(T.loc)
/datum/event/anomaly/tick()
if(!newAnomaly)
kill()
return
newAnomaly.anomalyEffect()
/datum/event/anomaly/end()
if(newAnomaly)//Kill the anomaly if it still exists at the end.
qdel(newAnomaly)
newAnomaly = new anomaly_path(T)
if(newAnomaly)
announce_to_ghosts(newAnomaly)
-52
View File
@@ -1,52 +0,0 @@
/datum/event/anomaly/anomaly_atmos
startWhen = 30
announceWhen = 3
endWhen = 100
/datum/event/anomaly/anomaly_atmos/announce()
GLOB.event_announcement.Announce("Transformative gas anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
/datum/event/anomaly/anomaly_atmos/start()
var/turf/T = pick(get_area_turfs(impact_area))
if(T)
newAnomaly = new /obj/effect/anomaly/atmos(T.loc)
/datum/event/anomaly/anomaly_atmos/tick()
if(!newAnomaly)
kill()
return
if(ISMULTIPLE(activeFor, 5))
newAnomaly.anomalyEffect()
/datum/event/anomaly/anomaly_atmos/end()
if(!newAnomaly || !newAnomaly.loc) //no anomaly or it is in nullspace
return
var/obj/effect/anomaly/atmos/A = newAnomaly
var/gas_type = A.gas_type
var/area/t_area = get_area(A)
for(var/turf/T in t_area)
if(istype(T, /turf/simulated)) //should not occur on unsimulated turfs without admemery
var/turf/simulated/S = T
fill_with_gas(gas_type, S)
explosion(get_turf(newAnomaly), -1, 0, 2) // a small boom so people know something happened.
..()
/**
* Replaces all oxygen and nitrogen on the simulated turf S with the gas type specified in gas, taking N2, N20, CO2 and agent B
*/
/datum/event/anomaly/anomaly_atmos/proc/fill_with_gas(gas, turf/simulated/S)
if(!S.air)//no air to transform
return
var/amount_to_add = S.air.oxygen + S.air.nitrogen
S.air.oxygen = 0
S.air.nitrogen = 0
switch(gas)
if(GAS_N2)
S.air.nitrogen += amount_to_add
if(GAS_N2O)
S.air.sleeping_agent += amount_to_add
if(GAS_CO2)
S.air.carbon_dioxide += amount_to_add
S.update_visuals()
S.air_update_turf()
+2 -63
View File
@@ -1,69 +1,8 @@
/datum/event/anomaly/anomaly_bluespace
name = "Anomaly: Bluespace"
startWhen = 3
announceWhen = 10
endWhen = 160
anomaly_path = /obj/effect/anomaly/bluespace
/datum/event/anomaly/anomaly_bluespace/announce()
GLOB.event_announcement.Announce("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
/datum/event/anomaly/anomaly_bluespace/start()
var/turf/T = pick(get_area_turfs(impact_area))
if(T)
newAnomaly = new /obj/effect/anomaly/bluespace(T.loc)
/datum/event/anomaly/anomaly_bluespace/end()
if(newAnomaly)//If it hasn't been neutralized, it's time to warp half the station away jeez
var/turf/T = pick(get_area_turfs(impact_area))
if(T)
// Calculate new position (searches through beacons in world)
var/obj/item/radio/beacon/chosen
var/list/possible = list()
for(var/obj/item/radio/beacon/W in GLOB.global_radios)
if(!is_station_level(W.z))
continue
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)
GLOB.event_announcement.Announce("Massive bluespace translocation detected.", "Anomaly Alert")
var/list/flashers = list()
for(var/mob/living/carbon/C in viewers(TO, null))
if(C.flash_eyes())
flashers += C
var/y_distance = TO.y - FROM.y
var/x_distance = TO.x - FROM.x
for(var/atom/movable/A in range(12, FROM )) // iterate thru list of mobs in the area
if(istype(A, /obj/item/radio/beacon)) // don't teleport beacons because that's just insanely stupid
continue
if(A.anchored || A.move_resist == INFINITY)
continue
var/turf/newloc = locate(A.x + x_distance, A.y + y_distance, TO.z) // calculate the new place
if(!A.Move(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 = locate(A.x + x_distance, A.y + y_distance, TO.z)
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 = MOUSE_OPACITY_TRANSPARENT
M.client.screen += blueeffect
sleep(20)
M.client.screen -= blueeffect
qdel(blueeffect)
qdel(newAnomaly)
+4 -13
View File
@@ -1,17 +1,8 @@
/datum/event/anomaly/anomaly_flux
startWhen = 3
announceWhen = 20
endWhen = 180
name = "Anomaly: Hyper-Energetic Flux"
startWhen = 10
announceWhen = 3
anomaly_path = /obj/effect/anomaly/flux
/datum/event/anomaly/anomaly_flux/announce()
GLOB.event_announcement.Announce("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
/datum/event/anomaly/anomaly_flux/start()
var/turf/T = pick(get_area_turfs(impact_area))
if(T)
newAnomaly = new /obj/effect/anomaly/flux(T.loc)
/datum/event/anomaly/anomaly_flux/end()
if(newAnomaly.loc)//If it hasn't been neutralized, it's time to blow up.
explosion(newAnomaly, -1, 3, 5, 5)
qdel(newAnomaly)
+2 -6
View File
@@ -1,12 +1,8 @@
/datum/event/anomaly/anomaly_grav
name = "Anomaly: Gravitational"
startWhen = 3
announceWhen = 20
endWhen = 70
anomaly_path = /obj/effect/anomaly/grav
/datum/event/anomaly/anomaly_grav/announce()
GLOB.event_announcement.Announce("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
/datum/event/anomaly/anomaly_grav/start()
var/turf/T = pick(get_area_turfs(impact_area))
if(T)
newAnomaly = new /obj/effect/anomaly/grav(T.loc)
+4 -27
View File
@@ -1,31 +1,8 @@
/datum/event/anomaly/anomaly_pyro
startWhen = 30
announceWhen = 3
endWhen = 110
name = "Anomaly: Pyroclastic"
startWhen = 3
announceWhen = 10
anomaly_path = /obj/effect/anomaly/pyro
/datum/event/anomaly/anomaly_pyro/announce()
GLOB.event_announcement.Announce("Atmospheric anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
/datum/event/anomaly/anomaly_pyro/start()
var/turf/T = pick(get_area_turfs(impact_area))
if(T)
newAnomaly = new /obj/effect/anomaly/pyro(T.loc)
/datum/event/anomaly/anomaly_pyro/tick()
if(!newAnomaly)
kill()
return
if(ISMULTIPLE(activeFor, 5))
newAnomaly.anomalyEffect()
/datum/event/anomaly/anomaly_pyro/end()
if(newAnomaly.loc)
explosion(get_turf(newAnomaly), -1,0,3, flame_range = 4)
var/turf/T = get_turf(src)
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()
qdel(newAnomaly)
+3 -7
View File
@@ -1,12 +1,8 @@
/datum/event/anomaly/anomaly_vortex
startWhen = 20
name = "Anomaly: Vortex"
startWhen = 10
announceWhen = 3
endWhen = 80
anomaly_path = /obj/effect/anomaly/bhole
/datum/event/anomaly/anomaly_vortex/announce()
GLOB.event_announcement.Announce("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name]", "Anomaly Alert")
/datum/event/anomaly/anomaly_vortex/start()
var/turf/T = pick(get_area_turfs(impact_area))
if(T)
newAnomaly = new /obj/effect/anomaly/bhole(T.loc)
+9
View File
@@ -51,6 +51,8 @@
return 0*/
/datum/event //NOTE: Times are measured in master controller ticks!
/// The human-readable name of the event
var/name
var/processing = 1
/// When in the lifetime to call start().
var/startWhen = 0
@@ -190,3 +192,10 @@
setup()
..()
//Called after something followable has been spawned by an event
//Provides ghosts a follow link to an atom if possible
//Only called once.
/datum/event/proc/announce_to_ghosts(atom/atom_of_interest)
if(atom_of_interest)
notify_ghosts("[name] has an object of interest: [atom_of_interest]!", title = "Something's Interesting!", source = atom_of_interest, action = NOTIFY_FOLLOW)
-1
View File
@@ -174,7 +174,6 @@ GLOBAL_LIST_EMPTY(event_last_fired)
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Vent Clog", /datum/event/vent_clog, 250),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Wormholes", /datum/event/wormholes, 150),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Pyro Anomaly", /datum/event/anomaly/anomaly_pyro, 75, list(ASSIGNMENT_ENGINEER = 60)),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Atmos Anomaly", /datum/event/anomaly/anomaly_atmos, 75, list(ASSIGNMENT_ENGINEER = 60)),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Vortex Anomaly", /datum/event/anomaly/anomaly_vortex, 75, list(ASSIGNMENT_ENGINEER = 25)),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Bluespace Anomaly", /datum/event/anomaly/anomaly_bluespace, 75, list(ASSIGNMENT_ENGINEER = 25)),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Flux Anomaly", /datum/event/anomaly/anomaly_flux, 75, list(ASSIGNMENT_ENGINEER = 50)),
+53
View File
@@ -0,0 +1,53 @@
// Embedded signaller used in anomalies.
/obj/item/assembly/signaler/anomaly
name = "anomaly core"
desc = "The neutralized core of an anomaly. It'd probably be valuable for research."
icon_state = "anomaly_core"
item_state = "electronic"
resistance_flags = FIRE_PROOF
receiving = TRUE
var/anomaly_type = /obj/effect/anomaly
/obj/item/assembly/signaler/anomaly/receive_signal(datum/signal/signal)
if(..())
for(var/obj/effect/anomaly/A in get_turf(src))
A.anomalyNeutralize()
/obj/item/assembly/signaler/anomaly/attack_self()
return
//Anomaly cores
/obj/item/assembly/signaler/anomaly/pyro
name = "\improper pyroclastic anomaly core"
desc = "The neutralized core of a pyroclastic anomaly. It feels warm to the touch. It'd probably be valuable for research."
icon_state = "pyro_core"
anomaly_type = /obj/effect/anomaly/pyro
origin_tech = "plasmatech=7"
/obj/item/assembly/signaler/anomaly/grav
name = "\improper gravitational anomaly core"
desc = "The neutralized core of a gravitational anomaly. It feels much heavier than it looks. It'd probably be valuable for research."
icon_state = "grav_core"
anomaly_type = /obj/effect/anomaly/grav
origin_tech = "magnets=7"
/obj/item/assembly/signaler/anomaly/flux
name = "\improper flux anomaly core"
desc = "The neutralized core of a flux anomaly. Touching it makes your skin tingle. It'd probably be valuable for research."
icon_state = "flux_core"
anomaly_type = /obj/effect/anomaly/flux
origin_tech = "powerstorage=7"
/obj/item/assembly/signaler/anomaly/bluespace
name = "\improper bluespace anomaly core"
desc = "The neutralized core of a bluespace anomaly. It keeps phasing in and out of view. It'd probably be valuable for research."
icon_state = "anomaly_core"
anomaly_type = /obj/effect/anomaly/bluespace
origin_tech = "bluespace=7"
/obj/item/assembly/signaler/anomaly/vortex
name = "\improper vortex anomaly core"
desc = "The neutralized core of a vortex anomaly. It won't sit still, as if some invisible force is acting on it. It'd probably be valuable for research."
icon_state = "vortex_core"
anomaly_type = /obj/effect/anomaly/bhole
origin_tech = "engineering=7"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 24 KiB

+1 -1
View File
@@ -1465,7 +1465,6 @@
#include "code\modules\events\abductor.dm"
#include "code\modules\events\alien_infestation.dm"
#include "code\modules\events\anomaly.dm"
#include "code\modules\events\anomaly_atmos.dm"
#include "code\modules\events\anomaly_bluespace.dm"
#include "code\modules\events\anomaly_flux.dm"
#include "code\modules\events\anomaly_grav.dm"
@@ -2312,6 +2311,7 @@
#include "code\modules\research\rdmachines.dm"
#include "code\modules\research\research.dm"
#include "code\modules\research\server.dm"
#include "code\modules\research\anomaly\anomaly.dm"
#include "code\modules\research\designs\AI_module_designs.dm"
#include "code\modules\research\designs\autolathe_designs.dm"
#include "code\modules\research\designs\biogenerator_designs.dm"