From 84ffa263cacbf592ff1d8cd9099f08691bf29880 Mon Sep 17 00:00:00 2001 From: Fox McCloud Date: Sun, 10 Jan 2021 14:46:37 -0500 Subject: [PATCH] Anomaly Refactor and Rework (#15259) * Anomaly Refactor and Rework * tweaks * tweaks --- code/__DEFINES/gamemode.dm | 1 + code/__HELPERS/lists.dm | 15 + code/game/mecha/mecha_construction_paths.dm | 48 +-- code/game/mecha/mecha_parts.dm | 5 + code/game/objects/effects/anomalies.dm | 339 ++++++++++++++------ code/modules/assembly/signaler.dm | 17 - code/modules/countdown/countdown.dm | 30 +- code/modules/events/anomaly.dm | 54 ++-- code/modules/events/anomaly_atmos.dm | 52 --- code/modules/events/anomaly_bluespace.dm | 65 +--- code/modules/events/anomaly_flux.dm | 17 +- code/modules/events/anomaly_grav.dm | 8 +- code/modules/events/anomaly_pyro.dm | 31 +- code/modules/events/anomaly_vortex.dm | 10 +- code/modules/events/event.dm | 9 + code/modules/events/event_container.dm | 1 - code/modules/research/anomaly/anomaly.dm | 53 +++ icons/obj/assemblies/new_assemblies.dmi | Bin 10012 -> 25026 bytes paradise.dme | 2 +- 19 files changed, 415 insertions(+), 342 deletions(-) delete mode 100644 code/modules/events/anomaly_atmos.dm create mode 100644 code/modules/research/anomaly/anomaly.dm diff --git a/code/__DEFINES/gamemode.dm b/code/__DEFINES/gamemode.dm index 497d8349ce1..9aee8f85eba 100644 --- a/code/__DEFINES/gamemode.dm +++ b/code/__DEFINES/gamemode.dm @@ -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" diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index f302d96347d..aab920f55fd 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -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 diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm index 4ea78db674a..01ac7cf8d7d 100644 --- a/code/game/mecha/mecha_construction_paths.dm +++ b/code/game/mecha/mecha_construction_paths.dm @@ -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.") ) diff --git a/code/game/mecha/mecha_parts.dm b/code/game/mecha/mecha_parts.dm index 6b8122e69d9..4bb7f96e66f 100644 --- a/code/game/mecha/mecha_parts.dm +++ b/code/game/mecha/mecha_parts.dm @@ -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, "The anomaly core socket only accepts bluespace anomaly cores!") + /obj/item/mecha_parts/part/phazon_torso name="Phazon Torso" icon_state = "phazon_harness" diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index ed4f5162447..a1211ec9aa1 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -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, "Analyzing... [src]'s unstable field is fluctuating along frequency [aSignal.code]:[format_frequency(aSignal.frequency)].") + to_chat(user, "Analyzing... [src]'s unstable field is fluctuating along frequency [format_frequency(aSignal.frequency)], code [aSignal.code].") /////////////////////// /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 diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index 0c3fcfec3ac..c4a7d7b59ec 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -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 diff --git a/code/modules/countdown/countdown.dm b/code/modules/countdown/countdown.dm index 714590c5b23..cbac113f32a 100644 --- a/code/modules/countdown/countdown.dm +++ b/code/modules/countdown/countdown.dm @@ -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 = "[displayed_text]" + maptext = "[displayed_text]" 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) diff --git a/code/modules/events/anomaly.dm b/code/modules/events/anomaly.dm index 68edfb68200..c806fac3ce0 100644 --- a/code/modules/events/anomaly.dm +++ b/code/modules/events/anomaly.dm @@ -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) diff --git a/code/modules/events/anomaly_atmos.dm b/code/modules/events/anomaly_atmos.dm deleted file mode 100644 index fa512cb522b..00000000000 --- a/code/modules/events/anomaly_atmos.dm +++ /dev/null @@ -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() diff --git a/code/modules/events/anomaly_bluespace.dm b/code/modules/events/anomaly_bluespace.dm index 929612cf6f9..b90e8b86b01 100644 --- a/code/modules/events/anomaly_bluespace.dm +++ b/code/modules/events/anomaly_bluespace.dm @@ -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) diff --git a/code/modules/events/anomaly_flux.dm b/code/modules/events/anomaly_flux.dm index 714ae1e9d19..350e21cb496 100644 --- a/code/modules/events/anomaly_flux.dm +++ b/code/modules/events/anomaly_flux.dm @@ -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) diff --git a/code/modules/events/anomaly_grav.dm b/code/modules/events/anomaly_grav.dm index 03b9c2247f6..4acf530c081 100644 --- a/code/modules/events/anomaly_grav.dm +++ b/code/modules/events/anomaly_grav.dm @@ -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) diff --git a/code/modules/events/anomaly_pyro.dm b/code/modules/events/anomaly_pyro.dm index 0a5dc14bc3a..2caa8dc4a0c 100644 --- a/code/modules/events/anomaly_pyro.dm +++ b/code/modules/events/anomaly_pyro.dm @@ -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) diff --git a/code/modules/events/anomaly_vortex.dm b/code/modules/events/anomaly_vortex.dm index 76a952dba12..76058cfa574 100644 --- a/code/modules/events/anomaly_vortex.dm +++ b/code/modules/events/anomaly_vortex.dm @@ -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) diff --git a/code/modules/events/event.dm b/code/modules/events/event.dm index d7fa555ca5e..dc6016d2c1f 100644 --- a/code/modules/events/event.dm +++ b/code/modules/events/event.dm @@ -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) diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index 6bb7394fdb4..6eee71921b9 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -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)), diff --git a/code/modules/research/anomaly/anomaly.dm b/code/modules/research/anomaly/anomaly.dm new file mode 100644 index 00000000000..c8401b6ed99 --- /dev/null +++ b/code/modules/research/anomaly/anomaly.dm @@ -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" diff --git a/icons/obj/assemblies/new_assemblies.dmi b/icons/obj/assemblies/new_assemblies.dmi index 89b665cd635e8cdf880605caf8d4ba292c79528f..971a42e6143eb14ee64fca22fd9737ba9c8dcbcb 100644 GIT binary patch literal 25026 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 z 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 DRL2Jg diff --git a/paradise.dme b/paradise.dme index 2e7219ff97d..49361d16747 100644 --- a/paradise.dme +++ b/paradise.dme @@ -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"