From 3b6d04550c561cad3dff731c10ca3b1556d7bbb8 Mon Sep 17 00:00:00 2001 From: CHOMPStation2StaffMirrorBot <94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:18:58 -0700 Subject: [PATCH] [MIRROR] Anomaly Harvesting (#12512) Co-authored-by: Guti <32563288+TheCaramelion@users.noreply.github.com> Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> --- code/__defines/anomaly.dm | 16 ++ code/__defines/research.dm | 2 +- code/__defines/research/techweb_nodes.dm | 3 + code/_helpers/global_lists_vr.dm | 4 +- code/datums/outfits/jobs/science.dm | 5 + code/game/jobs/job/science.dm | 1 + .../objects/effects/anomalies/_anomalies.dm | 59 +++++- .../anomalies/anomalies_bioscrambler.dm | 15 ++ .../effects/anomalies/anomalies_bluespace.dm | 41 ++++ .../anomalies/anomalies_dimensional.dm | 26 +++ .../effects/anomalies/anomalies_dust.dm | 13 ++ .../effects/anomalies/anomalies_flux.dm | 21 ++ .../effects/anomalies/anomalies_gravity.dm | 13 ++ .../anomalies/anomalies_hallucination.dm | 14 ++ .../anomalies/anomalies_pyroclastic.dm | 34 ++- .../effects/anomalies/anomalies_weather.dm | 56 ++++- .../anomalies/anomalies_weather_themes.dm | 8 +- .../effects/anomalies/anomaly_stats.dm | 191 +++++++++++++++++ .../effects/anomalies/anomaly_stats_mods.dm | 87 ++++++++ code/game/objects/items/devices/anomaly.dm | 43 ---- code/game/objects/items/devices/multitool.dm | 7 + .../objects/items/robot/robot_upgrades.dm | 23 ++ .../machinery/anomaly_harvester.dm | 17 ++ .../objects/items/weapons/storage/belt.dm | 4 +- code/modules/anomalies/anomaly.dm | 162 ++++++++++++++ code/modules/anomalies/anomaly_harvester.dm | 200 ++++++++++++++++++ .../silicon/robot/robot_modules/station.dm | 3 +- code/modules/power/singularity/emitter.dm | 26 ++- code/modules/projectiles/projectile/energy.dm | 13 ++ code/modules/research/anomaly/anomaly_core.dm | 4 +- .../research/tg/designs/boards/science.dm | 9 + .../research/tg/designs/misc_designs.dm | 14 +- .../research/tg/designs/prosfab_designs.dm | 7 + .../research/tg/designs/tool_designs.dm | 11 + .../research/tg/designs/weapon_designs.dm | 11 + .../tg/experisci/experiment/instances/misc.dm | 16 ++ .../tg/techwebs/nodes/research_nodes.dm | 49 ++++- code/modules/telesci/telesci_computer.dm | 9 +- .../tools/suspension_generator.dm | 19 +- icons/obj/device.dmi | Bin 108128 -> 108736 bytes icons/obj/devices/tool.dmi | Bin 17638 -> 17824 bytes icons/obj/machines/anomaly_harvester.dmi | Bin 0 -> 1231 bytes maps/groundbase/gb-z2.dmm | 25 ++- maps/stellar_delight/stellar_delight1.dmm | 27 ++- maps/tether/tether-01-surface1.dmm | 40 +++- .../interfaces/AnomalyHarvester/Sample.tsx | 62 ++++++ .../interfaces/AnomalyHarvester/index.tsx | 45 ++++ .../tgui/interfaces/AnomalyHarvester/types.ts | 13 ++ .../tgui/interfaces/AnomalyScanner.tsx | 104 +++++++++ vorestation.dme | 6 +- 50 files changed, 1484 insertions(+), 94 deletions(-) create mode 100644 code/game/objects/effects/anomalies/anomaly_stats.dm create mode 100644 code/game/objects/effects/anomalies/anomaly_stats_mods.dm delete mode 100644 code/game/objects/items/devices/anomaly.dm create mode 100644 code/game/objects/items/weapons/circuitboards/machinery/anomaly_harvester.dm create mode 100644 code/modules/anomalies/anomaly.dm create mode 100644 code/modules/anomalies/anomaly_harvester.dm create mode 100644 icons/obj/machines/anomaly_harvester.dmi create mode 100644 tgui/packages/tgui/interfaces/AnomalyHarvester/Sample.tsx create mode 100644 tgui/packages/tgui/interfaces/AnomalyHarvester/index.tsx create mode 100644 tgui/packages/tgui/interfaces/AnomalyHarvester/types.ts create mode 100644 tgui/packages/tgui/interfaces/AnomalyScanner.tsx diff --git a/code/__defines/anomaly.dm b/code/__defines/anomaly.dm index ef3db08b37..03ccb13e0f 100644 --- a/code/__defines/anomaly.dm +++ b/code/__defines/anomaly.dm @@ -47,3 +47,19 @@ #define DIMENSIONAL_ANOMALY "dimensional_anomaly" #define WEATHER_ANOMALY "weather_anomaly" #define DUST_ANOMALY "dust_anomaly" + +#define ANOMALY_PARTICLE_SIGMA "Sigma particles" +#define ANOMALY_PARTICLE_DELTA "Delta particles" +#define ANOMALY_PARTICLE_ZETA "Zeta particles" +#define ANOMALY_PARTICLE_EPSILON "Epsilon particles" + +#define ANOMALY_PARTICLE_ALL list( \ + ANOMALY_PARTICLE_SIGMA, \ + ANOMALY_PARTICLE_DELTA, \ + ANOMALY_PARTICLE_ZETA, \ + ANOMALY_PARTICLE_EPSILON \ +) + +#define ANOMALY_DECAYING "Decaying" +#define ANOMALY_STABLE "Stable" +#define ANOMALY_GROWING "Growing" diff --git a/code/__defines/research.dm b/code/__defines/research.dm index 15aee3327d..778afa580f 100644 --- a/code/__defines/research.dm +++ b/code/__defines/research.dm @@ -35,7 +35,7 @@ #define TECHWEB_TIER_5_POINTS 200 //! Amount of points gained per second by a single R&D server, see: [research][code/controllers/subsystem/research.dm] -#define TECHWEB_SINGLE_SERVER_INCOME 1 +#define TECHWEB_SINGLE_SERVER_INCOME 0.2 //! Swab cell line types #define CELL_LINE_TABLE_SLUDGE "cell_line_sludge_table" diff --git a/code/__defines/research/techweb_nodes.dm b/code/__defines/research/techweb_nodes.dm index 186d476878..c596ec298f 100644 --- a/code/__defines/research/techweb_nodes.dm +++ b/code/__defines/research/techweb_nodes.dm @@ -4,6 +4,8 @@ #define TECHWEB_NODE_ALIEN_SURGERY "alien_surgery" #define TECHWEB_NODE_ALIENTECH "alientech" #define TECHWEB_NODE_ANOMALY_RESEARCH "anomaly_research" +#define TECHWEB_NODE_ANOMALY_HARVESTING "anomaly_harvesting" +#define TECHWEB_NODE_APPLIED_ANOMALY_HARVESTING "applied_anomaly_harvesting" #define TECHWEB_NODE_ANOMALY_SHELLS "anomaly_shells" #define TECHWEB_NODE_TELEKINETIC_RESEARCH "telekinetic_research" #define TECHWEB_NODE_APPLIED_BLUESPACE "applied_bluespace" @@ -144,6 +146,7 @@ #define TECHWEB_NODE_TACKLE_ADVANCED "tackle_advanced" #define TECHWEB_NODE_TELECOMS "telecoms" #define TECHWEB_NODE_UNREGULATED_BLUESPACE "unregulated_bluespace" +#define TECHWEB_NODE_XENOARCHEOLOGY "xenoarcheology" #define TECHWEB_NODE_XENOBIOLOGY "xenobiology" #define TECHWEB_NODE_TELEPORTER "teleporter" #define TECHWEB_NODE_CONFETTI "confetti" diff --git a/code/_helpers/global_lists_vr.dm b/code/_helpers/global_lists_vr.dm index 9484f44fe6..967187ebe6 100644 --- a/code/_helpers/global_lists_vr.dm +++ b/code/_helpers/global_lists_vr.dm @@ -1280,7 +1280,9 @@ GLOBAL_LIST_INIT(area_or_turf_fail_types, typecacheof(list( /obj/item/disposable_teleporter/slime, \ /obj/item/slimepotion, \ /obj/item/slime_extract, \ - /obj/item/reagent_containers/food/snacks/monkeycube + /obj/item/reagent_containers/food/snacks/monkeycube, \ + /obj/item/anomaly_releaser, \ + /obj/item/research_sample #define CIRCUIT_GRIPPER \ /obj/item/cell/device, \ diff --git a/code/datums/outfits/jobs/science.dm b/code/datums/outfits/jobs/science.dm index 9552e84bdb..5311de6b03 100644 --- a/code/datums/outfits/jobs/science.dm +++ b/code/datums/outfits/jobs/science.dm @@ -50,3 +50,8 @@ backpack = /obj/item/storage/backpack satchel_one = /obj/item/storage/backpack/satchel/norm suit = /obj/item/clothing/suit/storage/toggle/labcoat/roboticist + +/datum/decl/hierarchy/outfit/job/science/scientist/anomalist + name = OUTFIT_JOB_NAME(JOB_ALT_ANOMALIST) + l_pocket = /obj/item/anomaly_scanner + r_pocket = /obj/item/anomaly_releaser/science diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm index 7271181aa1..7c1fbe459f 100644 --- a/code/game/jobs/job/science.dm +++ b/code/game/jobs/job/science.dm @@ -103,6 +103,7 @@ title = JOB_ALT_ANOMALIST title_blurb = "An " + JOB_ALT_ANOMALIST + " is a " + JOB_SCIENTIST + " whose expertise is analyzing alien artifacts. They are familar with the most common methods of testing artifact \ function. They work closely with " + JOB_ALT_XENOARCHAEOLOGIST + "s, or Miners, if either role is present." + title_outfit = /datum/decl/hierarchy/outfit/job/science/scientist/anomalist /datum/alt_title/phoron_research title = JOB_ALT_PHORON_RESEARCHER diff --git a/code/game/objects/effects/anomalies/_anomalies.dm b/code/game/objects/effects/anomalies/_anomalies.dm index 5afd62f428..9d882cb189 100644 --- a/code/game/objects/effects/anomalies/_anomalies.dm +++ b/code/game/objects/effects/anomalies/_anomalies.dm @@ -19,6 +19,10 @@ var/immortal = FALSE var/move_chance = ANOMALY_MOVECHANCE + // Anomaly harvesting stuff + var/datum/anomaly_stats/stats + var/danger_mult = 1 + /obj/effect/anomaly/Initialize(mapload, new_lifespan, drops_core = TRUE) . = ..() @@ -51,6 +55,7 @@ /obj/effect/anomaly/process(seconds_per_tick) anomalyEffect(seconds_per_tick) + anomalyPulse() if(death_time < world.time && !immortal) if(loc) detonate() @@ -60,12 +65,27 @@ STOP_PROCESSING(SSobj, src) QDEL_NULL(countdown) QDEL_NULL(anomaly_core) + if(stats) + QDEL_NULL(stats) return ..() /obj/effect/anomaly/proc/anomalyEffect(seconds_per_tick) - if(prob(move_chance)) + if(prob(move_chance) && !locate(/obj/effect/suspension_field) in get_turf(src)) move_anomaly() +// Used in anomaly harvesting - Normal anomalies shouldn't pulse +/obj/effect/anomaly/proc/anomalyPulse() + if(!stats) + return FALSE + if(world.time < stats.next_activation) + return FALSE + + stats.pulse_effect() + if(QDELETED(src)) + return FALSE + stats.next_activation = world.time + rand(stats.min_activation, stats.max_activation) + return TRUE + /obj/effect/anomaly/proc/move_anomaly() step(src, pick(GLOB.alldirs)) @@ -85,21 +105,56 @@ anomaly_core = null qdel(src) -/obj/effect/anomaly/proc/stabilize(anchor = FALSE, has_core = TRUE) +/obj/effect/anomaly/proc/stabilize(anchor = FALSE, has_core = TRUE, add_stats = FALSE) immortal = TRUE name = (has_core ? "stable " : "hollow ") + name if(!has_core) QDEL_NULL(anomaly_core) if(anchor) move_chance = 0 + if(!stats && add_stats) + stats = new /datum/anomaly_stats + stats.attached_anomaly = WEAKREF(src) + stats.calculate_points() + density = TRUE + return /obj/effect/anomaly/attackby(obj/item/I, mob/user) if(istype(I, /obj/item/analyzer)) if(anomaly_core) to_chat(user, span_notice("Analyzing... [src]'s stabilized field is fluctuating along frequency [format_frequency(anomaly_core.frequency)], code [anomaly_core.code].")) return TRUE + if(istype(I, /obj/item/anomaly_scanner)) + var/obj/item/anomaly_scanner/scanner = I + if(stats) + if(!do_after(user, 1 SECOND, src)) + return + scanner.buffered_anomaly = WEAKREF(src) + scanner.tgui_interact(user) + return TRUE return ..() +/obj/effect/anomaly/bullet_act(obj/item/projectile/proj) + if(stats && istype(stats.modifier, /datum/anomaly_modifiers/reflective) && prob(stats.severity/1.5)) + balloon_alert_visible("reflected!") + + var/new_x = proj.x = pick(0, 0, 0, -1, 1, -2, 2) + var/new_y = proj.y = pick(0, 0, 0, -1, 1, -2, 2) + + var/turf/curloc = get_step(proj, get_dir(proj, proj.starting)) + + proj.penetrating += 1 + + proj.redirect(new_x, new_y, curloc, null) + return FALSE + + if(istype(proj, /obj/item/projectile/energy/anomaly)) + var/obj/item/projectile/energy/anomaly/anom_proj = proj + if(stats) + stats.particle_hit(anom_proj.particle_type) + + return FALSE + /proc/generate_anomaly(turf/anomalycenter, type = FLUX_ANOMALY, anomalyrange = 5, has_changed_lifespan = TRUE, drops_core = TRUE) var/turf/local_turf = pick(RANGE_TURFS(anomalyrange, anomalycenter)) if(!local_turf) diff --git a/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm b/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm index 2a64422a5d..9c5562ca0f 100644 --- a/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm +++ b/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm @@ -5,6 +5,7 @@ pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE layer = ABOVE_MOB_LAYER lifespan = ANOMALY_COUNTDOWN_TIMER * 2 + danger_mult = 1.1 /// Who are we moving towards? var/datum/weakref/pursuit_target @@ -21,6 +22,8 @@ /obj/effect/anomaly/bioscrambler/anomalyEffect(seconds_per_tick) . = ..() + if(stats) + return if(!COOLDOWN_FINISHED(src, pulse_cooldown)) return @@ -87,3 +90,15 @@ /obj/effect/anomaly/bioscrambler/detonate() COOLDOWN_RESET(src, pulse_cooldown) anomalyEffect() + +/obj/effect/anomaly/bioscrambler/anomalyPulse() + if(!..()) + return + + switch(stats.severity) + if(0 to 15) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread + sparks.set_up(3, 1, src) + sparks.start() + else + anomalyEffect() diff --git a/code/game/objects/effects/anomalies/anomalies_bluespace.dm b/code/game/objects/effects/anomalies/anomalies_bluespace.dm index a079eb15ce..b2379c52e9 100644 --- a/code/game/objects/effects/anomalies/anomalies_bluespace.dm +++ b/code/game/objects/effects/anomalies/anomalies_bluespace.dm @@ -7,6 +7,7 @@ var/teleport_range = 1 ///Distance we can teleport someone passively var/teleport_distance = 4 + danger_mult = 1.1 /obj/effect/anomaly/bluespace/Initialize(mapload, new_lifespan) . = ..() @@ -92,3 +93,43 @@ color = COLOR_BLUE_LIGHT duration = 1 SECONDS amount_to_scale = 5 + +/obj/effect/anomaly/bluespace/anomalyPulse() + if(!..()) + return + + switch(stats.severity) + if(0 to 15) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread + sparks.set_up(3, 1, src) + sparks.start() + if(16 to 33) + pulse_teleport(4, 1) + if(34 to 65) + pulse_teleport(5, 2) + else + pulse_teleport(6, 3) + +/obj/effect/anomaly/bluespace/proc/pulse_teleport(range, count) + var/list/possible = list() + + for(var/obj/item/radio/beacon in GLOB.all_beacons) + var/turf/turf = get_turf(beacon) + if(!turf) + continue + if(!check_teleport_valid(src, turf)) + continue + possible += beacon + + var/chosen = pick(possible) + + var/list/things = list() + for(var/atom/movable/thing in orange(range, get_turf(src))) + if(istype(thing, /obj/item/radio/beacon) || iseffect(thing) || isEye(thing)) + continue + if(thing.anchored) + continue + things += thing + + for(var/i in 1 to count) + do_teleport(pick(things), get_turf(chosen)) diff --git a/code/game/objects/effects/anomalies/anomalies_dimensional.dm b/code/game/objects/effects/anomalies/anomalies_dimensional.dm index be5dcc94f7..9d50def69c 100644 --- a/code/game/objects/effects/anomalies/anomalies_dimensional.dm +++ b/code/game/objects/effects/anomalies/anomalies_dimensional.dm @@ -4,6 +4,7 @@ anomaly_core = /obj/item/assembly/signaler/anomaly/dimensional lifespan = ANOMALY_COUNTDOWN_TIMER * 20 move_chance = 0 + danger_mult = 0.8 /// Range of effect, if left alone anomaly will convert a 2(range)+1 squared area. var/range = 3 /// List of turfs this anomaly will try to transform before relocating @@ -40,6 +41,8 @@ /obj/effect/anomaly/dimensional/proc/transmute_area() if(!theme) prepare_area() + if(stats) + return if(!target_turfs.len) if(teleports_left <= 0 && !immortal) detonate() @@ -88,3 +91,26 @@ icon = 'icons/effects/effects.dmi' icon_state = "shieldsparkles" duration = 3 + +/obj/effect/anomaly/dimensional/anomalyPulse() + if(!..()) + return + + switch(stats.severity) + if(0 to 15) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread + sparks.set_up(3, 1, src) + sparks.start() + if(16 to 33) + pulse_change(2) + if(34 to 65) + pulse_change(4) + else + pulse_change(8) + +/obj/effect/anomaly/dimensional/proc/pulse_change(count) + var/turf/turf + + for(var/i in 1 to count) + turf = pick(target_turfs) + theme.apply_theme(turf, show_effect = TRUE) diff --git a/code/game/objects/effects/anomalies/anomalies_dust.dm b/code/game/objects/effects/anomalies/anomalies_dust.dm index 9997e15ba3..5e89063582 100644 --- a/code/game/objects/effects/anomalies/anomalies_dust.dm +++ b/code/game/objects/effects/anomalies/anomalies_dust.dm @@ -6,6 +6,7 @@ pass_flags = PASSTABLE | PASSGRILLE layer = ABOVE_MOB_LAYER lifespan = ANOMALY_COUNTDOWN_TIMER * 1.5 + danger_mult = 0.75 move_chance = 80 @@ -71,3 +72,15 @@ /obj/effect/anomaly/dust/detonate() COOLDOWN_RESET(src, pulse_cooldown) anomalyEffect() + +/obj/effect/anomaly/dust/anomalyPulse() + if(!..()) + return + + switch(stats.severity) + if(0 to 15) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread + sparks.set_up(3, 1, src) + sparks.start() + else + anomalyEffect() diff --git a/code/game/objects/effects/anomalies/anomalies_flux.dm b/code/game/objects/effects/anomalies/anomalies_flux.dm index 97aa3dc13d..fc9a63c417 100644 --- a/code/game/objects/effects/anomalies/anomalies_flux.dm +++ b/code/game/objects/effects/anomalies/anomalies_flux.dm @@ -61,3 +61,24 @@ /obj/effect/anomaly/flux/minor/Initialize(mapload, new_lifespan, emp_zap = FLUX_NO_EMP) return ..() + +/obj/effect/anomaly/flux/anomalyPulse() + if(!..()) + return + switch(stats.severity) + if(0 to 15) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread + sparks.set_up(3, 1, src) + sparks.start() + if(16 to 33) + tesla_zap(src, 2, 1000, FALSE, FALSE) + if(34 to 65) + tesla_zap(src, 3, 1000, FALSE, FALSE) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(tesla_zap), src, 3, 1500, FALSE, FALSE), 3 SECONDS) + else + tesla_zap(src, 4, 1000, FALSE, TRUE) + addtimer(CALLBACK(src, PROC_REF(highSevPulse)), 3 SECONDS) + +/obj/effect/anomaly/flux/proc/highSevPulse() + tesla_zap(src, 4, 1250, FALSE, FALSE) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(tesla_zap), src, 4, 1500, FALSE, FALSE), 3 SECONDS) diff --git a/code/game/objects/effects/anomalies/anomalies_gravity.dm b/code/game/objects/effects/anomalies/anomalies_gravity.dm index bb80156112..519c03f4b4 100644 --- a/code/game/objects/effects/anomalies/anomalies_gravity.dm +++ b/code/game/objects/effects/anomalies/anomalies_gravity.dm @@ -16,6 +16,8 @@ /obj/effect/anomaly/grav/anomalyEffect(seconds_per_tick) ..() + if(stats) + return boing = TRUE for(var/obj/O in orange(4, src)) if(!O.anchored) @@ -93,3 +95,14 @@ */ /obj/effect/temp_visual/circle_wave/gravity color = COLOR_NAVY + +/obj/effect/anomaly/grav/anomalyPulse() + if(!..()) + return + switch(stats.severity) + if(0 to 15) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread + sparks.set_up(3, 1, src) + sparks.start() + else + anomalyEffect() diff --git a/code/game/objects/effects/anomalies/anomalies_hallucination.dm b/code/game/objects/effects/anomalies/anomalies_hallucination.dm index 7390896a38..9cfe28a14e 100644 --- a/code/game/objects/effects/anomalies/anomalies_hallucination.dm +++ b/code/game/objects/effects/anomalies/anomalies_hallucination.dm @@ -2,6 +2,7 @@ name = "hallucination anomaly" icon_state = "hallucination" anomaly_core = /obj/item/assembly/signaler/anomaly/hallucination + danger_mult = 0.9 /// Time passed since the last effect, increased by seconds_per_tick of the SSobj var/ticks = 0 /// How many seconds between each small hallucination pulses @@ -23,6 +24,8 @@ /obj/effect/anomaly/hallucination/anomalyEffect(seconds_per_tick) . = ..() + if(stats) + return ticks += seconds_per_tick if(ticks < release_delay) return @@ -109,3 +112,14 @@ ///Subtype for the SM that doesn't spawn decoys, because otherwise the whole area gets flooded with dummies. /obj/effect/anomaly/hallucination/supermatter spawn_decoys = FALSE + +/obj/effect/anomaly/hallucination/anomalyPulse() + if(!..()) + return + switch(stats.severity) + if(0 to 15) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread + sparks.set_up(3, 1, src) + sparks.start() + else + anomalyEffect() diff --git a/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm b/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm index bac080489c..576fd154c0 100644 --- a/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm +++ b/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm @@ -1,6 +1,7 @@ /obj/effect/anomaly/pyro name = "pyroclastic anomaly" icon_state = "pyroclastic" + danger_mult = 1.3 var/ticks = 0 /// How many seconds between each gas release var/releasedelay = 15 SECONDS @@ -12,23 +13,40 @@ /obj/effect/anomaly/pyro/anomalyEffect(seconds_per_tick) ..() + if(stats) + return ticks += seconds_per_tick if(ticks < releasedelay) return FALSE else ticks -= releasedelay - var/turf/simulated/floor/tile = get_turf(src) - if(istype(tile)) - tile.assume_gas(GAS_PHORON, 10, T20C) - tile.hotspot_expose(700, 400) + burst() return TRUE -/obj/effect/anomaly/pyro/detonate() +/obj/effect/anomaly/pyro/proc/burst(moles = 10, temperature = 700, volume = 400) var/turf/simulated/floor/tile = get_turf(src) if(istype(tile)) - tile.assume_gas(GAS_PHORON, 10, T20C) - tile.hotspot_expose(700, 400) + tile.assume_gas(GAS_PHORON, moles, T20C) + tile.hotspot_expose(temperature, volume) + +/obj/effect/anomaly/pyro/detonate() + burst() var/new_colour = pick(/mob/living/simple_mob/slime/xenobio/red, /mob/living/simple_mob/slime/xenobio/orange) - var/mob/living/simple_mob/slime/xenobio/pyro = new new_colour(tile) + var/mob/living/simple_mob/slime/xenobio/pyro = new new_colour(get_turf(src)) pyro.enrage() + +/obj/effect/anomaly/pyro/anomalyPulse() + if(!..()) + return + switch(stats.severity) + if(0 to 15) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread + sparks.set_up(3, 1, src) + sparks.start() + if(16 to 33) + burst() + if(34 to 65) + burst(20, 900, 600) + else + burst(30, 110, 800) diff --git a/code/game/objects/effects/anomalies/anomalies_weather.dm b/code/game/objects/effects/anomalies/anomalies_weather.dm index baa4366de2..ca21a910c3 100644 --- a/code/game/objects/effects/anomalies/anomalies_weather.dm +++ b/code/game/objects/effects/anomalies/anomalies_weather.dm @@ -44,6 +44,12 @@ addtimer(CALLBACK(src, PROC_REF(start_weather)), telegraph, TIMER_DELETE_ME) +/obj/effect/anomaly/weather/proc/add_turfs(list/turf/to_add) + for(var/turf/turf in to_add) + if(isspace(turf)) + continue + affected_turfs.Add(turf) + /obj/effect/anomaly/weather/proc/find_adjacent_impacted_area(check_dir) var/limit = 10 var/turf/next_turf = get_step(src, check_dir) @@ -73,6 +79,9 @@ turf = GetBelow(turf) selected_weather.affect_turf(turf) + if(stats) + return + for(var/mob/mob as anything in GLOB.player_list) if(get_area(mob) in affected_areas) selected_weather.hear_sounds(mob, TRUE) @@ -104,13 +113,13 @@ if(selected_weather.sounds) selected_weather.loop_sounds.stop() + for(var/turf/turf in affected_turfs) + selected_weather.remove_from_turf(turf) + for(var/area in affected_areas) for(var/mob/mob in area) selected_weather.hear_sounds(mob, FALSE) - for(var/turf/turf in affected_turfs) - selected_weather.remove_from_turf(turf) - /obj/effect/anomaly/weather/Destroy() clear_weather() . = ..() @@ -118,6 +127,47 @@ /obj/effect/anomaly/weather/proc/update_reagent(reagent) selected_weather.update_reagent(reagent) +/obj/effect/anomaly/weather/anomalyPulse() + if(!..()) + return + switch(stats.severity) + if(0 to 15) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread + sparks.set_up(3, 1, src) + sparks.start() + affected_areas.Cut() + affected_turfs.Cut() + if(16 to 33) + clear_weather() + affected_turfs.Cut() + if(!istype(selected_weather, /datum/anomalous_weather/rain)) + selected_weather = new /datum/anomalous_weather/rain + update_reagent(REAGENT_ID_WATER) + add_turfs(circleviewturfs(src, 3)) + start_weather() + if(34 to 65) + clear_weather() + affected_turfs.Cut() + if(!istype(selected_weather, /datum/anomalous_weather/rain)) + selected_weather = new /datum/anomalous_weather/rain + update_reagent(pick(REAGENT_ID_WATER, REAGENT_ID_ICE, REAGENT_ID_ORANGEJUICE)) + add_turfs(circlerangeturfs(src, 4)) + start_weather() + else + clear_weather() + affected_turfs.Cut() + if(!istype(selected_weather, /datum/anomalous_weather/rain/storm)) + selected_weather = new /datum/anomalous_weather/rain/storm + + var/reagent_id = pick(SSchemistry.chemical_reagents) + if(reagent_id in GLOB.obtainable_chemical_blacklist) + update_reagent(REAGENT_ID_WATER) // You get WATER. + else + update_reagent(reagent_id) + + add_turfs(circlerangeturfs(src, 5)) + start_weather() + /obj/effect/anomaly/weather/rain selected_weather = /datum/anomalous_weather/rain diff --git a/code/game/objects/effects/anomalies/anomalies_weather_themes.dm b/code/game/objects/effects/anomalies/anomalies_weather_themes.dm index 1afbb5d225..8290f6f11f 100644 --- a/code/game/objects/effects/anomalies/anomalies_weather_themes.dm +++ b/code/game/objects/effects/anomalies/anomalies_weather_themes.dm @@ -57,7 +57,7 @@ T.vis_contents -= visuals /datum/anomalous_weather/proc/affect_turf(turf/to_affect) - if(iswall(to_affect)) + if(iswall(to_affect) || isopenturf(to_affect)) return for(var/atom/thing in to_affect) @@ -130,7 +130,7 @@ drench_message = "Rain falls on you, drenching you in water." /datum/anomalous_weather/rain/do_special(turf/simulated/T) - if(prob(2)) + if(prob(2) && !isopenturf(T)) T.wet_floor(1) /datum/anomalous_weather/rain/blood @@ -153,9 +153,9 @@ drench_message = "Rain falls on you, completely soaking you." /datum/anomalous_weather/rain/storm/do_special(turf/simulated/T) - if(prob(3)) + if(prob(3) && !isopenturf(T)) T.wet_floor(1) - if(prob(0.025)) + if(prob(0.025) && !isopenturf(T)) lightning_strike(T) /datum/anomalous_weather/rain/acid diff --git a/code/game/objects/effects/anomalies/anomaly_stats.dm b/code/game/objects/effects/anomalies/anomaly_stats.dm new file mode 100644 index 0000000000..0174b331ed --- /dev/null +++ b/code/game/objects/effects/anomalies/anomaly_stats.dm @@ -0,0 +1,191 @@ +/datum/anomaly_stats + var/severity = 1 + var/stability + var/max_health + + var/danger_type + var/unstable_type + var/containment_type + var/transformation_type + + var/datum/anomaly_modifiers/modifier + + var/datum/weakref/attached_anomaly + var/datum/weakref/attached_harvester + + var/next_activation + // Total of points we'll get once the anomaly does a pulse + var/points + var/curr_health + var/flags + + var/min_activation = 45 SECONDS + var/max_activation = 90 SECONDS + +/datum/anomaly_stats/New() + randomize_particle_types() + severity = rand(5, 15) + max_health = rand(50, 150) + curr_health = max_health + stability = ANOMALY_STABLE + +/datum/anomaly_stats/Destroy(force) + QDEL_NULL(modifier) + return ..() + +/datum/anomaly_stats/proc/randomize_particle_types() + var/list/particles = list(ANOMALY_PARTICLE_SIGMA, ANOMALY_PARTICLE_DELTA, ANOMALY_PARTICLE_ZETA, ANOMALY_PARTICLE_EPSILON) + particles = shuffle(particles) + danger_type = particles[1] + unstable_type = particles[2] + containment_type = particles[3] + transformation_type = particles[4] + +/datum/anomaly_stats/proc/calculate_points() + var/total = 10 + + var/obj/effect/anomaly/anomaly = attached_anomaly.resolve() + + if(!anomaly) + return + + total += severity/5 + total *= curr_health/max_health + total *= anomaly.danger_mult + + if(modifier) + total *= modifier.get_value() + + points = total + + return points + +/datum/anomaly_stats/proc/particle_hit(particle) + // I don't really like this, but switch() expects a constant expression + if(particle == danger_type) + update_severity(1, 5) + return + else if(particle == unstable_type) + update_state(TRUE) + return + else if(particle == containment_type) + update_state(FALSE) + update_health(-1, -10) + return + else if(particle == transformation_type) + update_modifiers() + return + return + +/datum/anomaly_stats/proc/update_severity(lower, upper) + var/obj/effect/anomaly/anom = attached_anomaly.resolve() + if(!istype(anom)) + attached_anomaly = null + return + var/sev_change = rand(lower, upper) + severity += sev_change + + if(severity >= 100) + kill_anomaly(TRUE) + return + + var/scale_factor = 1.0+(severity/100) + var/matrix/M = matrix() + M.Scale(scale_factor, scale_factor) + animate(anom, transform = M, time = 1 SECOND) + + // These don't have the wibbly filter + if(!istype(anom, /obj/effect/anomaly/bioscrambler) && !istype(anom, /obj/effect/anomaly/dimensional)) + apply_wibbly_filters(anom) + + calculate_points() + return + +/datum/anomaly_stats/proc/update_health(lower, upper) + var/health_change = rand(lower, upper) + curr_health += health_change + + if(curr_health <= 0) + kill_anomaly(FALSE) + return + + calculate_points() + return + +/datum/anomaly_stats/proc/kill_anomaly(critical) + var/obj/effect/anomaly/anom = attached_anomaly.resolve() + if(!istype(anom)) + attached_anomaly = null + return + if(critical) + anom.detonate() + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + QDEL_NULL(anom) + return + +/datum/anomaly_stats/proc/update_state(unstable) + var/obj/effect/anomaly/anom = attached_anomaly.resolve() + + if(!istype(anom)) + return + + if(locate(/obj/effect/suspension_field) in get_turf(anom)) + return + + switch(stability) + if(ANOMALY_STABLE) + if(unstable && prob(15)) + stability = ANOMALY_GROWING + else if(prob(15)) + stability = ANOMALY_DECAYING + return + if(ANOMALY_GROWING) + if(!unstable && prob(15)) + stability = ANOMALY_STABLE + return + if(ANOMALY_DECAYING) + if(unstable && prob(15)) + stability = ANOMALY_STABLE + else + return + return + +/datum/anomaly_stats/proc/update_modifiers() + var/picked_mod = pick(subtypesof(/datum/anomaly_modifiers)) + + // Tough luck. No mod for you. + if(istype(modifier, picked_mod)) + return + + if(modifier) + modifier.on_remove(attached_anomaly) + modifier = null + + modifier = new picked_mod + modifier.on_add(attached_anomaly) + calculate_points() + return + +/datum/anomaly_stats/proc/get_activation_countdown() + return (next_activation - world.time)/10 + +/datum/anomaly_stats/proc/pulse_effect() + if(stability == ANOMALY_DECAYING) + update_health(-1, -10) + else if(stability == ANOMALY_GROWING) + update_severity(1, 10) + + if(prob(5)) + if(stability == ANOMALY_STABLE) + stability = pick(ANOMALY_DECAYING, ANOMALY_GROWING) + else + stability = ANOMALY_STABLE + + if(attached_harvester) + var/obj/machinery/anomaly_harvester/harvester = attached_harvester.resolve() + if(!istype(harvester)) + return + + harvester.add_points(points) diff --git a/code/game/objects/effects/anomalies/anomaly_stats_mods.dm b/code/game/objects/effects/anomalies/anomaly_stats_mods.dm new file mode 100644 index 0000000000..c36a57c214 --- /dev/null +++ b/code/game/objects/effects/anomalies/anomaly_stats_mods.dm @@ -0,0 +1,87 @@ +/datum/anomaly_modifiers + var/name + var/description + var/value + var/obj/effect/anomaly/attached_anomaly = null + +/datum/anomaly_modifiers/proc/get_description() + return description + +/datum/anomaly_modifiers/proc/get_value() + return value + +/datum/anomaly_modifiers/proc/on_add(datum/weakref/anomaly) + attached_anomaly = anomaly.resolve() + if(!istype(attached_anomaly)) + return FALSE + return TRUE + +/datum/anomaly_modifiers/proc/on_remove(datum/weakref/anomaly) + attached_anomaly = anomaly.resolve() + if(!istype(attached_anomaly)) + return FALSE + return TRUE + +/datum/anomaly_modifiers/reflective + name = "Reflective" + description = "A protective coating was detected." + value = 1.2 + +/datum/anomaly_modifiers/invisible + name = "Invisible" + description = "Light wave distortion was detected." + value = 1.5 + +/datum/anomaly_modifiers/invisible/on_add(datum/weakref/anomaly) + if(!..()) + return + addtimer(CALLBACK(attached_anomaly, TYPE_PROC_REF(/atom/movable, cloak)), 2 SECONDS) + +/datum/anomaly_modifiers/invisible/on_remove(datum/weakref/anomaly) + if(!..()) + return + addtimer(CALLBACK(attached_anomaly, TYPE_PROC_REF(/atom/movable, uncloak)), 2 SECONDS) + +/* +/datum/anomaly_modifiers/hidden + name = "Hidden" + description = "Interference detected. Some data cannot be read." + value = 0.15 +*/ + +/datum/anomaly_modifiers/move + name = "Move" + description = "Anomalous anchoring could not be detected." + value = 1.4 + +/datum/anomaly_modifiers/move/on_add(datum/weakref/anomaly) + if(!..()) + return + attached_anomaly.move_chance = ANOMALY_MOVECHANCE + +/datum/anomaly_modifiers/move/on_remove(datum/weakref/anomaly) + if(!..()) + return + attached_anomaly.move_chance = 0 + +/datum/anomaly_modifiers/fast + name = "Faster Pulses" + description = "Anomalous pulses are more common." + value = 0.9 + +/datum/anomaly_modifiers/fast/on_add(datum/weakref/anomaly) + if(!..()) + return + + var/datum/anomaly_stats/stats = attached_anomaly.stats + stats.min_activation = 25 SECONDS + stats.max_activation = 45 SECONDS + +/datum/anomaly_modifiers/fast/on_remove(datum/weakref/anomaly) + if(!..()) + return + + var/datum/anomaly_stats/stats = attached_anomaly.stats + + stats.min_activation = initial(stats.min_activation) + stats.max_activation = initial(stats.max_activation) diff --git a/code/game/objects/items/devices/anomaly.dm b/code/game/objects/items/devices/anomaly.dm deleted file mode 100644 index 0fe6e77191..0000000000 --- a/code/game/objects/items/devices/anomaly.dm +++ /dev/null @@ -1,43 +0,0 @@ -/obj/item/anomaly_neutralizer - name = "anomaly neutralizer" - desc = "A one-use device capable of instantly neutralizing anomalous or otherworldly entities." - icon = 'icons/obj/devices/tool.dmi' - icon_state = "neutralyzer" - w_class = ITEMSIZE_SMALL - slot_flags = SLOT_BELT - item_flags = NOBLUDGEON - -/obj/item/anomaly_neutralizer/Initialize(mapload) - . = ..() - - AddComponent(/datum/component/effect_remover, \ - success_feedback = "You neutralize %THEEFFECT with %THEWEAPON, frying its circuitry in the process.", \ - on_clear_callback = CALLBACK(src, PROC_REF(on_anomaly_neutralized)), \ - effects_we_clear = list(/obj/effect/anomaly)) - -/obj/item/anomaly_neutralizer/proc/on_anomaly_neutralized(obj/effect/anomaly/target, mob/living/user) - target.anomalyNeutralize() - on_use(target, user) - -/obj/item/anomaly_neutralizer/proc/on_use(obj/effect/target, mob/living/user) - var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread - sparks.set_up(3, 1, src) - sparks.start() - qdel(src) - -/obj/item/anomaly_releaser - icon = 'icons/obj/devices/syndie_gadget.dmi' - icon_state = "anomaly_releaser" - name = "anomaly releaser" - desc = "Single-use injector that releases and stabilizes anomalies by injecting an unknown substance." - throwforce = 0 - w_class = ITEMSIZE_SMALL - throw_speed = 3 - throw_range = 5 - - ///icon state after being used up - var/used_icon_state = "anomaly_releaser_used" - ///are we used? if used we can't be used again - var/used = FALSE - ///Can we be used infinitely? - var/infinite = FALSE diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index d88b6ef31e..1f8406147e 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -100,3 +100,10 @@ icon_state = "multitool" toolspeed = 0.1 origin_tech = list(TECH_MAGNET = 5, TECH_ENGINEERING = 5) + +// Alien multitool only has those icon states +/obj/item/multitool/alien/update_icon() + if(accepting_refs) + icon_state = "multitool_ref_scan" + return + icon_state = "multitool" diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index a75eba2a57..c47c9ec042 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -546,6 +546,29 @@ to_chat(R, span_notice("Letter compartment upgraded!")) return TRUE +// Anomaly Gun +/obj/item/borg/upgrade/restricted/anomalygun + name = "robot mounted particle gun" + desc = "A anomaly particle gun adapted for installation in cyborgs, allows them to shoot different particles upon anomalies." + icon_state = "cyborg_upgrade2" + item_state = "cyborg_upgrade" + module_flags = BORG_MODULE_SCIENCE + require_module = TRUE + +/obj/item/borg/upgrade/restricted/anomalygun/action(mob/user, mob/living/silicon/robot/R) + if(..()) return FALSE + + if(!R.supports_upgrade(type)) + generic_error(user, R, type) + return FALSE + + if(R.has_restricted_upgrade(type)) + generic_error(user, R, type) + return FALSE + + R.module.modules += new/obj/item/gun/energy/anomaly/mounted(R.module) + return TRUE + /* ############################################### # Unsorted section. All cargo modules go here.# ###############################################*/ diff --git a/code/game/objects/items/weapons/circuitboards/machinery/anomaly_harvester.dm b/code/game/objects/items/weapons/circuitboards/machinery/anomaly_harvester.dm new file mode 100644 index 0000000000..a7a32ea1dd --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/anomaly_harvester.dm @@ -0,0 +1,17 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/circuitboard/anomaly_harvester + name = T_BOARD("anomaly harvester") + build_path = /obj/machinery/anomaly_harvester + board_type = new /datum/frame/frame_types/machine + origin_tech = list(TECH_DATA = 1) + req_components = list( + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stack/cable_coil = 5, + /obj/item/stack/material/phoron = 5, + /obj/item/stack/material/diamond = 1 + ) diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index 9383b94286..39d068656d 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -86,7 +86,9 @@ /obj/item/stack/nanopaste, /obj/item/geiger, /obj/item/reagent_scanner, - /obj/item/lightpainter + /obj/item/lightpainter, + /obj/item/anomaly_releaser, + /obj/item/anomaly_scanner ) /obj/item/storage/belt/utility/full diff --git a/code/modules/anomalies/anomaly.dm b/code/modules/anomalies/anomaly.dm new file mode 100644 index 0000000000..fa70de057b --- /dev/null +++ b/code/modules/anomalies/anomaly.dm @@ -0,0 +1,162 @@ +/obj/item/anomaly_neutralizer + name = "anomaly neutralizer" + desc = "A one-use device capable of instantly neutralizing anomalous or otherworldly entities." + icon = 'icons/obj/devices/tool.dmi' + icon_state = "neutralyzer" + w_class = ITEMSIZE_SMALL + slot_flags = SLOT_BELT + item_flags = NOBLUDGEON + +/obj/item/anomaly_neutralizer/Initialize(mapload) + . = ..() + + AddComponent(/datum/component/effect_remover, \ + success_feedback = "You neutralize %THEEFFECT with %THEWEAPON, frying its circuitry in the process.", \ + on_clear_callback = CALLBACK(src, PROC_REF(on_anomaly_neutralized)), \ + effects_we_clear = list(/obj/effect/anomaly)) + +/obj/item/anomaly_neutralizer/proc/on_anomaly_neutralized(obj/effect/anomaly/target, mob/living/user) + target.anomalyNeutralize() + on_use(target, user) + +/obj/item/anomaly_neutralizer/proc/on_use(obj/effect/target, mob/living/user) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread + sparks.set_up(3, 1, src) + sparks.start() + qdel(src) + +/obj/item/anomaly_releaser + icon = 'icons/obj/devices/syndie_gadget.dmi' + icon_state = "anomaly_releaser" + name = "advanced anomaly releaser" + desc = "Single-use injector that releases and stabilizes anomalies by injecting an unknown substance." + throwforce = 0 + w_class = ITEMSIZE_SMALL + throw_speed = 3 + throw_range = 5 + + ///icon state after being used up + var/used_icon_state = "anomaly_releaser_used" + ///are we used? if used we can't be used again + var/used = FALSE + ///Can we be used infinitely? + var/infinite = FALSE + //If the created anomaly leaves a core behind + var/has_core = TRUE + //If this will anchor the anomaly in place + var/will_anchor = TRUE + // If it will apply stats to it + var/gives_stats = TRUE + +/obj/item/anomaly_releaser/science + icon = 'icons/obj/devices/tool.dmi' + icon_state = "sci_releaser" + name = "scientific anomaly releaser" + used_icon_state = "sci_releaser_used" + has_core = FALSE + +// The one for antags and evil-doers +/obj/item/anomaly_releaser/antag + has_core = TRUE + will_anchor = TRUE + gives_stats = FALSE // Evil and fucked up... + desc = "Single-use injector that releases and stabilizes anomalies by injecting an unknown substance. This one seems odd." + +/obj/item/anomaly_scanner + name = "anomaly scanner" + desc = "A hand-held anomaly scanner, able to distinguish the particles that might affect a stable anomaly." + icon = 'icons/obj/device.dmi' + icon_state = "anom_scanner" + slot_flags = SLOT_BELT + w_class = ITEMSIZE_SMALL + throw_speed = 5 + throw_range = 10 + matter = list(MAT_STEEL = 200) + + pickup_sound = 'sound/items/pickup/device.ogg' + drop_sound = 'sound/items/drop/device.ogg' + + var/datum/weakref/buffered_anomaly = null + +/obj/item/anomaly_scanner/attack_self(mob/living/user) + . = ..(user) + if(.) + return TRUE + tgui_interact(user) + +/obj/item/anomaly_scanner/tgui_static_data(mob/user) + . = ..() + if(isrobot(loc)) + var/mob/living/silicon/robot/robot_owner = loc + .["theme"] = robot_owner.get_ui_theme() + +/obj/item/anomaly_scanner/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, custom_state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AnomalyScanner", name) + ui.open() + +/obj/item/anomaly_scanner/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = list() + var/obj/effect/anomaly/anom = buffered_anomaly.resolve() + + if(!istype(anom)) + return data + + var/datum/anomaly_stats/stats = anom.stats + + data["anomaly_name"] = anom.name + data["severity"] = stats.severity + data["stability"] = stats.stability + data["point_output"] = stats.points + data["danger_type"] = stats.danger_type + data["unstable_type"] = stats.unstable_type + data["containment_type"] = stats.containment_type + data["transformation_type"] = stats.transformation_type + if(stats.modifier) + data["modifier"] = stats.modifier.get_description() + data["countdown"] = stats.get_activation_countdown() + + return data + +/obj/item/gun/energy/anomaly + name = "anomalous particle gun" + desc = "A handheld particle emitter, used to safely release a specific particle frequency." + icon_state = "taserblue" + fire_delay = 4 + projectile_type = /obj/item/projectile/energy/anomaly + fire_sound = 'sound/weapons/taser2.ogg' + recoil_mode = 0 + accuracy = 30 + + var/particle = ANOMALY_PARTICLE_SIGMA + +/obj/item/gun/energy/anomaly/mounted + name = "mounted particle gun" + self_recharge = 1 + use_external_power = 1 + +/obj/item/gun/energy/anomaly/attack_self(mob/user) + var/chosen_particle = tgui_input_list(user, "Select particle type", "Particle Selection", ANOMALY_PARTICLE_ALL) + if(!chosen_particle) + return + + particle = chosen_particle + balloon_alert_visible("changed to [chosen_particle]") + ..() + +/obj/item/gun/energy/anomaly/consume_next_projectile() + var/obj/item/cell/battery = power_supply + + if(use_external_power) + battery = get_external_power_supply() + + if(!battery || !battery.checked_use(charge_cost)) + return null + var/mob/living/M = loc + if(istype(M)) + M.hud_used.update_ammo_hud(M, src) + var/obj/item/projectile/energy/anomaly/projectile = new + if(particle) + projectile.particle_type = particle + return projectile diff --git a/code/modules/anomalies/anomaly_harvester.dm b/code/modules/anomalies/anomaly_harvester.dm new file mode 100644 index 0000000000..ac04897dc8 --- /dev/null +++ b/code/modules/anomalies/anomaly_harvester.dm @@ -0,0 +1,200 @@ +/obj/machinery/anomaly_harvester + name = "anomaly harvester" + desc = "A strange device that condenses anomalous energy into tangible material." + icon = 'icons/obj/machines/anomaly_harvester.dmi' + icon_state = "harvester" + density = TRUE + circuit = /obj/item/circuitboard/anomaly_harvester + active_power_usage = 40000 + idle_power_usage = 1000 + + var/points = 0 + var/points_to_create = 100 + var/efficiency = 1 + + var/datum/weakref/harvested + var/list/obj/item/research_sample/samples + +/obj/machinery/anomaly_harvester/Initialize(mapload) + . = ..() + default_apply_parts() + +/obj/machinery/anomaly_harvester/Destroy() + harvested = null + return ..() + +/obj/machinery/anomaly_harvester/RefreshParts() + var/efficient = 0 + var/rating = 0 + for(var/obj/item/stock_parts/manipulator/manipulator in component_parts) + efficient += manipulator.rating - 2 + for(var/obj/item/stock_parts/micro_laser/laser in component_parts) + rating += laser.rating - 2 + + efficiency = max(1, (efficient/10+1)) + points_to_create = min(100, (100 - (rating * 5))) + +/obj/machinery/anomaly_harvester/process() + ..() + if(stat & (NOPOWER|BROKEN) || !anchored) + update_use_power(USE_POWER_OFF) + else + update_use_power(USE_POWER_IDLE) + harvest_anomaly() + if(points && points >= points_to_create) + points -= points_to_create + generate_sample() + update_icon() + +/obj/machinery/anomaly_harvester/proc/add_points(add_points) + add_points *= efficiency + points += add_points + return + +/obj/machinery/anomaly_harvester/proc/harvest_anomaly() + if(!harvested) + return + + var/obj/effect/anomaly/anom = harvested.resolve() + if(!istype(anom)) + return + + var/datum/anomaly_stats/stats = anom.stats + + if(stats.stability == ANOMALY_DECAYING) + playsound(src, 'sound/machines/2beephigh.ogg', 75) + else if (stats.stability == ANOMALY_GROWING) + playsound(src, 'sound/machines/buzzbeep.ogg', 75) + +/obj/machinery/anomaly_harvester/attackby(obj/item/W, mob/user, attack_modifier, click_parameters) + add_fingerprint(user) + + if(default_deconstruction_screwdriver(user, W)) + return + if(default_deconstruction_crowbar(user, W)) + return + if(default_part_replacement(user, W)) + return + if(default_unfasten_wrench(user, W, 2 SECONDS)) + return + if(istype(W, /obj/item/anomaly_scanner)) + if(!anchored) + to_chat(user, span_danger("The [src] is not anchored!")) + return + var/obj/item/anomaly_scanner/scanner = W + if(scanner.buffered_anomaly && do_after(user, 2 SECONDS, src)) + attach_anomaly(scanner.buffered_anomaly) + return + + return ..() + +/obj/machinery/anomaly_harvester/default_unfasten_wrench(mob/user, obj/item/W, time) + . = ..() + harvested = null + +/obj/machinery/anomaly_harvester/proc/attach_anomaly(datum/weakref/anomaly) + var/obj/effect/anomaly/anom = anomaly.resolve() + if(!istype(anom)) + return + + var/datum/anomaly_stats/stats = anom.stats + if(stats.attached_harvester) + var/obj/machinery/anomaly_harvester/harvester = stats.attached_harvester.resolve() + harvester.harvested = null + harvester.update_icon() + stats.attached_harvester = null + harvested = anomaly + stats.attached_harvester = WEAKREF(src) + playsound(src, 'sound/machines/boobeebeep.ogg', 75, TRUE) + return TRUE + +/obj/machinery/anomaly_harvester/proc/generate_sample() + update_use_power(USE_POWER_ACTIVE) + playsound(src, 'sound/machines/ping.ogg', 50, TRUE) + switch(rand(1, 100)) + if(1 to 60) + new /obj/item/research_sample/common(src) + if(61 to 85) + new /obj/item/research_sample/uncommon(src) + if(86 to 95) + new /obj/item/research_sample/rare(src) + if(96 to 100) + new /obj/item/research_sample/bluespace(src) + else + new /obj/item/research_sample/common(src) + +/obj/machinery/anomaly_harvester/update_icon() + cut_overlays() + if(stat & (NOPOWER|BROKEN) || !anchored) + add_overlay("harvester_off") + else + add_overlay("harvester_on") + + if(harvested) + var/obj/effect/anomaly/anom = harvested.resolve() + if(!istype(anom)) + return + + var/datum/anomaly_stats/stats = anom.stats + + switch(stats.stability) + if(ANOMALY_STABLE) + add_overlay("harvester_stable") + if(ANOMALY_DECAYING) + add_overlay("harvester_decay") + else + add_overlay("harvester_grow") + +/obj/machinery/anomaly_harvester/attack_ai(mob/user) + return attack_hand(user) + +/obj/machinery/anomaly_harvester/attack_hand(mob/user) + if(..()) + return + tgui_interact(user) + +/obj/machinery/anomaly_harvester/tgui_state(mob/user) + return GLOB.tgui_default_state + +/obj/machinery/anomaly_harvester/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, custom_state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AnomalyHarvester", name) + ui.open() + +/obj/machinery/anomaly_harvester/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/sample_data = list() + for(var/obj/item/research_sample/sample in src) + UNTYPED_LIST_ADD(sample_data, list( + "name" = sample.name, + "icon" = sample.icon, + "icon_state" = sample.icon_state, + "ref" = REF(sample) + )) + + var/obj/effect/anomaly/anom = harvested?.resolve() + var/list/data = list( + "name" = anom, + "points" = points, + "pointsToGenerate" = points_to_create, + "samples" = sample_data + ) + + return data + +/obj/machinery/anomaly_harvester/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + . = ..() + if(.) + return + + switch(action) + if("release_sample") + var/obj/item/research_sample/sample = locate(params["ref"]) in src + if(!istype(sample) || (sample.loc != src)) + return FALSE + sample.forceMove(get_turf(src)) + return TRUE + if("release_all") + for(var/obj/item/research_sample/sample in src) + sample.forceMove(get_turf(src)) + return TRUE diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station.dm b/code/modules/mob/living/silicon/robot/robot_modules/station.dm index db07152997..c8145770ec 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/station.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/station.dm @@ -680,7 +680,7 @@ /obj/item/robot_module/robot/research name = "research module" channels = list(CHANNEL_SCIENCE = 1) - supported_upgrades = list(/obj/item/borg/upgrade/restricted/advrped) + supported_upgrades = list(/obj/item/borg/upgrade/restricted/advrped, /obj/item/borg/upgrade/restricted/anomalygun) pto_type = PTO_SCIENCE /obj/item/robot_module/robot/research/create_equipment(var/mob/living/silicon/robot/robot) @@ -706,6 +706,7 @@ // Anomaly handling src.modules += new /obj/item/analyzer(src) src.modules += new /obj/item/assembly/signaler(src) + src.modules += new /obj/item/anomaly_scanner(src) src.emag += new /obj/item/hand_tele(src) diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index e0634cb52f..eb807b54d7 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -23,6 +23,10 @@ var/state = 0 var/locked = 0 + // Anomaly harvesting stuff + var/anomalous = FALSE + var/particle = ANOMALY_PARTICLE_SIGMA + var/burst_delay = 2 var/initial_fire_delay = 100 @@ -59,13 +63,13 @@ if(!src.locked) if(src.active==1) src.active = 0 - to_chat(user, "You turn off [src].") - message_admins("Emitter turned off by [key_name(user, user.client)](?) in ([x],[y],[z] - JMP)") + balloon_alert_visible("turned off") + message_admins("Emitter turned off by [key_name(user, user.client)](?) in ([x],[y],[z] - JMP)",0,1) log_game("EMITTER([x],[y],[z]) OFF by [key_name(user)]") investigate_log("turned " + span_red("off") + " by [user.key]","singulo") else src.active = 1 - to_chat(user, "You turn on [src].") + balloon_alert_visible("turned on") src.shot_number = 0 src.fire_delay = get_initial_fire_delay() message_admins("Emitter turned on by [key_name(user, user.client)](?) in ([x],[y],[z] - JMP)") @@ -223,6 +227,18 @@ else to_chat(user, span_warning("Access denied.")) return + if(istype(W, /obj/item/anomaly_scanner)) + anomalous = !anomalous + burst_delay = anomalous ? 3 : 8 + to_chat(user, span_notice("The beam is now set to [anomalous ? "anomalous." : "normal."]")) + return + if(W.has_tool_quality(TOOL_MULTITOOL) && anomalous) + var/chosen_particle = tgui_input_list(user, "Select particle type", "Particle Selection", ANOMALY_PARTICLE_ALL) + if(!chosen_particle) + return + particle = chosen_particle + balloon_alert_visible("changed to [chosen_particle]") + return ..() return @@ -282,4 +298,8 @@ return burst_delay /obj/machinery/power/emitter/proc/get_emitter_beam() + if(anomalous) + var/obj/item/projectile/energy/anomaly/projectile = new /obj/item/projectile/energy/anomaly(get_turf(src)) + projectile.particle_type = particle + return projectile return new /obj/item/projectile/beam/emitter(get_turf(src)) diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm index d68009bbf3..9c5ef5fbc6 100644 --- a/code/modules/projectiles/projectile/energy.dm +++ b/code/modules/projectiles/projectile/energy.dm @@ -335,3 +335,16 @@ /obj/item/projectile/energy/flash/flare flash_range = 2 hud_state = "grenade_dummy" + +/obj/item/projectile/energy/anomaly + name = "anomaly emitter projectile" + light_color = "#be008f" + icon_state = "purple_laser" + damage = 5 + speed = 1.6 + var/particle_type + +/obj/item/projectile/energy/anomaly/Initialize(mapload, particle) + . = ..() + if(particle) + particle_type = particle diff --git a/code/modules/research/anomaly/anomaly_core.dm b/code/modules/research/anomaly/anomaly_core.dm index 84eb0f7e17..bc885a955c 100644 --- a/code/modules/research/anomaly/anomaly_core.dm +++ b/code/modules/research/anomaly/anomaly_core.dm @@ -44,12 +44,12 @@ return FALSE var/obj/effect/anomaly/anomaly = new core.anomaly_type(get_turf(core)) - anomaly.stabilize() + anomaly.stabilize(releaser.will_anchor, releaser.has_core, releaser.gives_stats) if(!releaser.infinite) releaser.icon_state = releaser.used_icon_state releaser.used = TRUE - releaser.name = "used " + name + releaser.name = "used " + releaser.name qdel(src) return ..() diff --git a/code/modules/research/tg/designs/boards/science.dm b/code/modules/research/tg/designs/boards/science.dm index fbf9bb1adf..d9563771ee 100644 --- a/code/modules/research/tg/designs/boards/science.dm +++ b/code/modules/research/tg/designs/boards/science.dm @@ -205,3 +205,12 @@ RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_RESEARCH ) departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + +/datum/design_techweb/board/anomaly_harvester + name = "Anomaly Harvester" + id = "anomaly_harvester" + build_path = /obj/item/circuitboard/anomaly_harvester + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_RESEARCH + ) + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE diff --git a/code/modules/research/tg/designs/misc_designs.dm b/code/modules/research/tg/designs/misc_designs.dm index 44a5eaada2..bd53173d1b 100644 --- a/code/modules/research/tg/designs/misc_designs.dm +++ b/code/modules/research/tg/designs/misc_designs.dm @@ -289,8 +289,20 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SCIENCE +/datum/design_techweb/sci_anomaly_releaser + name = "Scientific Anomaly Releaser" + desc = "A one-time use device, reactivates anomalies and stabilizes them, but leaves no core behind." + id = "sci_anomaly_releaser" + build_type = PROTOLATHE + materials = list(MAT_STEEL = SHEET_MATERIAL_AMOUNT, MAT_PHORON = SHEET_MATERIAL_AMOUNT * 1.5) + build_path = /obj/item/anomaly_releaser/science + category = list( + RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_SCIENCE + ) + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + /datum/design_techweb/anomaly_releaser - name = "Anomaly Releaser" + name = "Advanced Anomaly Releaser" desc = "A one-time use device, reactivates anomalies and stabilizes them." id = "anomaly_releaser" build_type = PROTOLATHE diff --git a/code/modules/research/tg/designs/prosfab_designs.dm b/code/modules/research/tg/designs/prosfab_designs.dm index 83a84b2bdb..dc80674309 100644 --- a/code/modules/research/tg/designs/prosfab_designs.dm +++ b/code/modules/research/tg/designs/prosfab_designs.dm @@ -702,3 +702,10 @@ id = "prosthetic_teshari" // req_tech = list(TECH_DATA = 3, TECH_BIO = 4) build_path = /obj/item/disk/species/teshari + +/datum/design_techweb/prosfab/robot_upgrade/advanced/anomgun + name = "Anomalous Particle Gun Module" + desc = "An anomalous particle gun, for anomaly harvesting." + id = "borg_anomgun_module" + materials = list(MAT_STEEL = 4000, MAT_GLASS = 3500, MAT_PHORON = 1500, MAT_DIAMOND = 1500, MAT_URANIUM = 1500) + build_path = /obj/item/borg/upgrade/restricted/anomalygun diff --git a/code/modules/research/tg/designs/tool_designs.dm b/code/modules/research/tg/designs/tool_designs.dm index 18540c10bc..a0be2be50d 100644 --- a/code/modules/research/tg/designs/tool_designs.dm +++ b/code/modules/research/tg/designs/tool_designs.dm @@ -1015,3 +1015,14 @@ RND_CATEGORY_TOOLS ) departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_CARGO + +/datum/design_techweb/anomaly_scanner + name = "Anomaly Scanner" + id = "anomaly_scanner" + materials = list(MAT_STEEL = 1000, MAT_GLASS = 500) + build_path = /obj/item/anomaly_scanner + build_type = PROTOLATHE + category = list( + RND_CATEGORY_TOOLS + ) + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE diff --git a/code/modules/research/tg/designs/weapon_designs.dm b/code/modules/research/tg/designs/weapon_designs.dm index b0a551dd29..8a02203730 100644 --- a/code/modules/research/tg/designs/weapon_designs.dm +++ b/code/modules/research/tg/designs/weapon_designs.dm @@ -960,3 +960,14 @@ RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_RANGED ) departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + +/datum/design_techweb/anomaly_gun + name = "Handheld Anomalous Particle Releaser" + id = "anom_gun" + build_type = PROTOLATHE + materials = list(MAT_STEEL = 4000, MAT_GLASS = 3500, MAT_PHORON = 1500, MAT_DIAMOND = 1500, MAT_URANIUM = 1500) + build_path = /obj/item/gun/energy/anomaly + category = list( + RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_RANGED + ) + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE diff --git a/code/modules/research/tg/experisci/experiment/instances/misc.dm b/code/modules/research/tg/experisci/experiment/instances/misc.dm index 906105e6c2..8a18e94b51 100644 --- a/code/modules/research/tg/experisci/experiment/instances/misc.dm +++ b/code/modules/research/tg/experisci/experiment/instances/misc.dm @@ -87,3 +87,19 @@ /obj/item/clothing/suit/bomb_suit = 1, /obj/item/clothing/suit/bio_suit = 1, ) + +/datum/experiment/scanning/points/anomaly + name = "Anomaly Research Scans" + description = "Anomalies. What are they? Where do they come from? Why are they here? Get close and personal with some of them, and observe their strange nature." + required_points = 4 + required_atoms = list( + /obj/effect/anomaly/bioscrambler = 1, + /obj/effect/anomaly/bluespace = 1, + /obj/effect/anomaly/dimensional = 1, + /obj/effect/anomaly/dust = 1, + /obj/effect/anomaly/flux = 1, + /obj/effect/anomaly/grav = 1, + /obj/effect/anomaly/hallucination = 1, + /obj/effect/anomaly/pyro = 1, + /obj/effect/anomaly/weather = 1, + ) diff --git a/code/modules/research/tg/techwebs/nodes/research_nodes.dm b/code/modules/research/tg/techwebs/nodes/research_nodes.dm index f91f4e8900..3ef323b425 100644 --- a/code/modules/research/tg/techwebs/nodes/research_nodes.dm +++ b/code/modules/research/tg/techwebs/nodes/research_nodes.dm @@ -99,24 +99,59 @@ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) announce_channels = list(CHANNEL_SCIENCE) +/datum/techweb_node/xenoarch + id = TECHWEB_NODE_XENOARCHEOLOGY + display_name = "Xenoarcheology Research" + description = "Researching those who came before us, extracting artifacts of great value, and harnessing their powers." + prereq_ids = list(TECHWEB_NODE_FUNDIMENTAL_SCI) + design_ids = list( + "ano_scanner", + "xenoarch_multitool", + "excavationdrill", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + announce_channels = list(CHANNEL_SCIENCE) + /datum/techweb_node/anomaly_research id = TECHWEB_NODE_ANOMALY_RESEARCH display_name = "Anomaly Research" description = "Delving into the study of mysterious anomalies to investigate methods to refine and harness their unpredictable energies." prereq_ids = list(TECHWEB_NODE_APPLIED_BLUESPACE) design_ids = list( - "xenoarch_multitool", - "excavationdrill", - "ano_scanner", - //"anomaly_refinery", "anomaly_neutralizer", - "anomaly_releaser", + "sci_anomaly_releaser", "reactive_armour", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) announce_channels = list(CHANNEL_SCIENCE) -// Decided that we were not keen on this being able to be printed freely as we immediately saw undesirable behaviour //CHOMPEdit - Re-enable +/datum/techweb_node/anomaly_harvesting + id = TECHWEB_NODE_ANOMALY_HARVESTING + display_name = "Anomaly Harvesting" + description = "Harness the power of the mysterious anomalies, refining their energies into tangible materials." + prereq_ids = list(TECHWEB_NODE_ANOMALY_RESEARCH) + design_ids = list( + "anomaly_harvester", + "anomaly_scanner", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + announce_channels = list(CHANNEL_SCIENCE) + +/datum/techweb_node/applied_anomaly_harvesting + id = TECHWEB_NODE_APPLIED_ANOMALY_HARVESTING + display_name = "Applied Anomaly Harvesting" + description = "Advanced research in the anomaly field, allowing sophisticated tools to aid in their study." + prereq_ids = list(TECHWEB_NODE_ANOMALY_HARVESTING) + design_ids = list( + "anomaly_releaser", + "anom_gun", + "borg_anomgun_module" + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) + announce_channels = list(CHANNEL_SCIENCE) + discount_experiments = list(/datum/experiment/scanning/points/anomaly = TECHWEB_TIER_3_POINTS) + +// Decided that we were not keen on this being able to be printed freely as we immediately saw undesirable behaviour // CHOMPEnable Start /datum/techweb_node/telekinetics id = TECHWEB_NODE_TELEKINETIC_RESEARCH display_name = "Applied Telekinetics Research" @@ -127,4 +162,4 @@ ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) announce_channels = list(CHANNEL_SCIENCE) -// //CHOMPEdit - Re-enable +// CHOMPEnable End diff --git a/code/modules/telesci/telesci_computer.dm b/code/modules/telesci/telesci_computer.dm index 9aab06a9b4..05e708ce56 100644 --- a/code/modules/telesci/telesci_computer.dm +++ b/code/modules/telesci/telesci_computer.dm @@ -189,17 +189,10 @@ /obj/machinery/computer/telescience/proc/telefail() COOLDOWN_START(src, teleport_cooldown, (2 SECONDS)) switch(rand(99)) - if(0 to 80) + if(0 to 85) sparks() visible_message(span_warning("The telepad weakly fizzles.")) return - if(81 to 85) - sparks() - var/anomaly = pick(FLUX_ANOMALY, GRAVITATIONAL_ANOMALY, PYRO_ANOMALY, HALLUCINATION_ANOMALY, BIOSCRAMBLER_ANOMALY, DIMENSIONAL_ANOMALY, WEATHER_ANOMALY) - generate_anomaly(get_turf(telepad), anomaly, 1, FALSE) - for(var/mob/living/carbon/human/human in viewers(telepad, null)) - to_chat(human, span_warning("The telepad crackles with energy, as a tear in reality is created!")) - return if(86 to 90) // Irradiate everyone in telescience! for(var/obj/machinery/telepad/E in GLOB.machines) diff --git a/code/modules/xenoarcheaology/tools/suspension_generator.dm b/code/modules/xenoarcheaology/tools/suspension_generator.dm index c269f56f6a..214526e9da 100644 --- a/code/modules/xenoarcheaology/tools/suspension_generator.dm +++ b/code/modules/xenoarcheaology/tools/suspension_generator.dm @@ -1,6 +1,6 @@ /obj/machinery/suspension_gen name = "suspension field generator" - desc = "It has stubby bolts up against it's treads for stabilising. Used to be required for artifact removal but now merely works as a monster deterrant." + desc = "It has stubby bolts up against it's treads for stabilising. Used to hold anomalies stable in place." icon = 'icons/obj/xenoarchaeology.dmi' icon_state = "suspension" density = 1 @@ -8,7 +8,7 @@ var/obj/item/cell/cell var/obj/item/card/id/auth_card var/locked = 1 - var/power_use = 5 + var/power_use = 15 var/obj/effect/suspension_field/suspension_field /obj/machinery/suspension_gen/Initialize(mapload) @@ -153,6 +153,12 @@ M.Weaken(5) M.visible_message(span_blue("[icon2html(M,viewers(M))] [M] begins to float in the air!"),"You feel tingly and light, but it is difficult to move.") + for(var/obj/effect/anomaly/anom in T) + anom.immortal = TRUE + anom.move_chance = 0 + if(!anom.stats) + anom.stats = new /datum/anomaly_stats(anom) + suspension_field = new(T) visible_message(span_blue("[icon2html(src,viewers(src))] [src] activates with a low hum.")) icon_state = "suspension_on" @@ -181,6 +187,15 @@ to_chat(M, span_info("You no longer feel like floating.")) M.Weaken(3) + for(var/obj/effect/anomaly/anom in T) + if(anom.stats) + var/datum/anomaly_stats/anom_stats = anom.stats + if(istype(anom_stats.modifier, /datum/anomaly_modifiers/move)) + anom.move_chance = initial(anom.move_chance) + continue + else + anom.move_chance = initial(anom.move_chance) + visible_message(span_blue("[icon2html(src,viewers(src))] [src] deactivates with a gentle shudder.")) qdel(suspension_field) suspension_field = null diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 9855dbcdc2f5b3d79679bcc5cce579b998f69bac..62eeac68c57b199349a88f1e0654121269d99073 100644 GIT binary patch delta 21266 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 J^rl_-{{dvVjmZE2 literal 17638 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 literal 0 HcmV?d00001 diff --git a/maps/groundbase/gb-z2.dmm b/maps/groundbase/gb-z2.dmm index bc6ab3f3d6..9efe0bea88 100644 --- a/maps/groundbase/gb-z2.dmm +++ b/maps/groundbase/gb-z2.dmm @@ -6512,6 +6512,7 @@ /obj/machinery/requests_console/preset/research{ pixel_y = 30 }, +/obj/machinery/anomaly_harvester, /turf/simulated/floor/tiled, /area/groundbase/science/rnd) "rI" = ( @@ -7172,6 +7173,7 @@ /turf/simulated/floor/tiled/white, /area/groundbase/medical/triage) "tI" = ( +/obj/machinery/rnd/destructive_analyzer, /turf/simulated/floor/tiled/dark, /area/groundbase/science/rnd) "tJ" = ( @@ -10461,13 +10463,32 @@ /area/groundbase/dorms/room1) "Dm" = ( /obj/structure/table/standard, -/obj/item/retail_scanner/science, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/structure/noticeboard{ pixel_x = 32 }, +/obj/item/assembly/signaler/anomaly/flux{ + pixel_y = 13; + pixel_x = 7 + }, +/obj/item/anomaly_scanner{ + pixel_x = 2; + pixel_y = -2 + }, +/obj/item/anomaly_scanner{ + pixel_x = 5; + pixel_y = 3 + }, +/obj/item/anomaly_releaser/science{ + pixel_y = -2; + pixel_x = -5 + }, +/obj/item/anomaly_releaser/science{ + pixel_y = -5; + pixel_x = -5 + }, /turf/simulated/floor/tiled, /area/groundbase/science/rnd) "Dn" = ( @@ -11032,6 +11053,7 @@ dir = 8 }, /obj/machinery/light, +/obj/machinery/power/emitter, /turf/simulated/floor/tiled, /area/groundbase/science/rnd) "EN" = ( @@ -17896,6 +17918,7 @@ dir = 1; pixel_y = -30 }, +/obj/item/retail_scanner/science, /turf/simulated/floor/tiled, /area/groundbase/science/rnd) "Yc" = ( diff --git a/maps/stellar_delight/stellar_delight1.dmm b/maps/stellar_delight/stellar_delight1.dmm index 27c648a57a..0f6034c37e 100644 --- a/maps/stellar_delight/stellar_delight1.dmm +++ b/maps/stellar_delight/stellar_delight1.dmm @@ -1300,6 +1300,7 @@ /obj/structure/reagent_dispensers/acid{ pixel_x = 32 }, +/obj/machinery/power/emitter, /turf/simulated/floor/tiled/steel_grid, /area/rnd/research) "cx" = ( @@ -9831,6 +9832,8 @@ /obj/item/pen, /obj/item/packageWrap, /obj/item/packageWrap, +/obj/item/multitool/scioutpost, +/obj/item/retail_scanner/science, /turf/simulated/floor/tiled/steel_grid, /area/rnd/research) "tP" = ( @@ -11863,8 +11866,26 @@ "yq" = ( /obj/structure/table/standard, /obj/machinery/recharger, -/obj/item/retail_scanner/science, -/obj/item/multitool/scioutpost, +/obj/item/assembly/signaler/anomaly/flux{ + pixel_y = 13; + pixel_x = 7 + }, +/obj/item/anomaly_scanner{ + pixel_x = 5; + pixel_y = 3 + }, +/obj/item/anomaly_scanner{ + pixel_x = 2; + pixel_y = -2 + }, +/obj/item/anomaly_releaser/science{ + pixel_y = -5; + pixel_x = -5 + }, +/obj/item/anomaly_releaser/science{ + pixel_y = -2; + pixel_x = -5 + }, /turf/simulated/floor/tiled/steel_grid, /area/rnd/research) "yr" = ( @@ -11906,6 +11927,7 @@ /obj/machinery/disposal/wall{ dir = 1 }, +/obj/machinery/anomaly_harvester, /turf/simulated/floor/tiled/steel_grid, /area/rnd/research) "yw" = ( @@ -22240,6 +22262,7 @@ "UA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/rnd/destructive_analyzer, /turf/simulated/floor/tiled/dark, /area/rnd/research) "UB" = ( diff --git a/maps/tether/tether-01-surface1.dmm b/maps/tether/tether-01-surface1.dmm index 814db18360..7da3136b52 100644 --- a/maps/tether/tether-01-surface1.dmm +++ b/maps/tether/tether-01-surface1.dmm @@ -3101,6 +3101,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, +/obj/machinery/anomaly_harvester, /turf/simulated/floor/tiled, /area/rnd/hardstorage) "afh" = ( @@ -8602,6 +8603,7 @@ /area/tether/surfacebase/surface_one_hall) "aoR" = ( /obj/machinery/light/small, +/obj/machinery/power/emitter, /turf/simulated/floor/tiled, /area/rnd/hardstorage) "aoS" = ( @@ -28631,6 +28633,14 @@ /obj/machinery/disposal, /turf/simulated/floor/plating, /area/crew_quarters/sleep/maintDorm2) +"aYy" = ( +/obj/structure/table/rack/shelf/steel, +/obj/item/assembly/signaler/anomaly/flux{ + pixel_y = 13; + pixel_x = 7 + }, +/turf/simulated/floor/tiled, +/area/rnd/hardstorage) "aYz" = ( /obj/structure/sink{ pixel_y = 20 @@ -28640,6 +28650,18 @@ }, /turf/simulated/floor/plating, /area/crew_quarters/sleep/maintDorm2) +"aYA" = ( +/obj/structure/table/rack/shelf/steel, +/obj/item/anomaly_releaser/science{ + pixel_y = 2; + pixel_x = 3 + }, +/obj/item/anomaly_releaser/science{ + pixel_y = 1; + pixel_x = -3 + }, +/turf/simulated/floor/tiled, +/area/rnd/hardstorage) "aYB" = ( /obj/structure/disposalpipe/trunk{ dir = 4 @@ -28647,6 +28669,18 @@ /obj/machinery/disposal, /turf/simulated/floor/plating, /area/crew_quarters/sleep/maintDorm1) +"aYC" = ( +/obj/structure/table/rack/shelf/steel, +/obj/item/anomaly_scanner{ + pixel_x = 2; + pixel_y = -2 + }, +/obj/item/anomaly_scanner{ + pixel_x = 5; + pixel_y = 3 + }, +/turf/simulated/floor/tiled, +/area/rnd/hardstorage) "aYE" = ( /obj/structure/toilet{ pixel_y = 10 @@ -45942,8 +45976,8 @@ auK avh abm abw -abw -abw +aYC +aYy abv afA abv @@ -46227,7 +46261,7 @@ avh abm abw abw -abw +aYA adM afU abI diff --git a/tgui/packages/tgui/interfaces/AnomalyHarvester/Sample.tsx b/tgui/packages/tgui/interfaces/AnomalyHarvester/Sample.tsx new file mode 100644 index 0000000000..95a6a5cef9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/AnomalyHarvester/Sample.tsx @@ -0,0 +1,62 @@ +import { useBackend } from 'tgui/backend'; +import { Box, Button, DmIcon, Section, Stack } from 'tgui-core/components'; +import { capitalize } from 'tgui-core/string'; +import type { Data } from './types'; + +export const SampleDisplay = (props) => { + const { act, data } = useBackend(); + const { samples } = data; + + return ( +
act('release_all')} + > + Release All + + } + > + + {samples.length > 0 && + samples.map((sample) => { + return ( + + + + + + + + {capitalize(sample.name)} + + + + + + + + ); + })} + +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/AnomalyHarvester/index.tsx b/tgui/packages/tgui/interfaces/AnomalyHarvester/index.tsx new file mode 100644 index 0000000000..932222bc4d --- /dev/null +++ b/tgui/packages/tgui/interfaces/AnomalyHarvester/index.tsx @@ -0,0 +1,45 @@ +import { useBackend } from 'tgui/backend'; +import { Window } from 'tgui/layouts'; +import { LabeledList, ProgressBar, Stack } from 'tgui-core/components'; +import { capitalize } from 'tgui-core/string'; +import { SampleDisplay } from './Sample'; +import type { Data } from './types'; + +export const AnomalyHarvester = (props) => { + const { act, data } = useBackend(); + const { points, pointsToGenerate, name } = data; + + const progress = (points / pointsToGenerate) * 100; + return ( + + + + + + + + + {!!name && {capitalize(name)}} + {`${progress.toFixed()}%`} + + + + + + + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/AnomalyHarvester/types.ts b/tgui/packages/tgui/interfaces/AnomalyHarvester/types.ts new file mode 100644 index 0000000000..bd4531143e --- /dev/null +++ b/tgui/packages/tgui/interfaces/AnomalyHarvester/types.ts @@ -0,0 +1,13 @@ +export type Data = { + name: string | null; + points: number; + pointsToGenerate: number; + samples: Sample[]; +}; + +type Sample = { + name: string; + icon: string; + icon_state: string; + ref: string; +}; diff --git a/tgui/packages/tgui/interfaces/AnomalyScanner.tsx b/tgui/packages/tgui/interfaces/AnomalyScanner.tsx new file mode 100644 index 0000000000..fddc7bc0dc --- /dev/null +++ b/tgui/packages/tgui/interfaces/AnomalyScanner.tsx @@ -0,0 +1,104 @@ +import { useBackend } from 'tgui/backend'; +import { Window } from 'tgui/layouts'; +import { LabeledList, NoticeBox, Section, Stack } from 'tgui-core/components'; +import { round } from 'tgui-core/math'; +import { capitalizeAll } from 'tgui-core/string'; + +type Data = { + anomaly_name: string; + severity: number; + stability: string; + point_output: number; + danger_type: string; + unstable_type: string; + containment_type: string; + transformation_type: string; + modifier?: string; + countdown: number; +}; + +const colorMap = { + Decaying: 'yellow', + Stable: 'green', +} as const; + +function getColor(stability: string): string { + return colorMap[stability] ?? 'bad'; +} + +export const AnomalyScanner = (props) => { + const { data } = useBackend(); + + const { + anomaly_name, + severity, + stability, + point_output, + danger_type, + unstable_type, + containment_type, + transformation_type, + modifier, + countdown, + theme, + } = data; + + return ( + + + {anomaly_name ? ( + + +
+ + + {severity}% + + + {stability} + + + {round(point_output, 0)} + + + {round(countdown, 0)} seconds + + +
+
+ +
+ + + {danger_type} + + + {unstable_type} + + + {containment_type} + + + {transformation_type} + + +
+
+ {modifier && ( + +
+ {modifier} +
+
+ )} +
+ ) : ( + No anomaly scanned + )} +
+
+ ); +}; diff --git a/vorestation.dme b/vorestation.dme index dfc17497ee..bb39e1de6d 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -1637,6 +1637,8 @@ #include "code\game\objects\effects\anomalies\anomalies_weather_themes.dm" #include "code\game\objects\effects\anomalies\anomaly_placer.dm" #include "code\game\objects\effects\anomalies\anomaly_spawner.dm" +#include "code\game\objects\effects\anomalies\anomaly_stats.dm" +#include "code\game\objects\effects\anomalies\anomaly_stats_mods.dm" #include "code\game\objects\effects\chem\chemsmoke.dm" #include "code\game\objects\effects\chem\coating.dm" #include "code\game\objects\effects\chem\foam.dm" @@ -1721,7 +1723,6 @@ #include "code\game\objects\items\devices\advnifrepair.dm" #include "code\game\objects\items\devices\ai_detector.dm" #include "code\game\objects\items\devices\aicard.dm" -#include "code\game\objects\items\devices\anomaly.dm" #include "code\game\objects\items\devices\binoculars.dm" #include "code\game\objects\items\devices\body_snatcher_vr.dm" #include "code\game\objects\items\devices\chameleonproj.dm" @@ -1893,6 +1894,7 @@ #include "code\game\objects\items\weapons\circuitboards\computer\shuttle.dm" #include "code\game\objects\items\weapons\circuitboards\computer\supply.dm" #include "code\game\objects\items\weapons\circuitboards\computer\telecomms.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\anomaly_harvester.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\biogenerator.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\cloning.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\engineering.dm" @@ -2377,6 +2379,8 @@ #include "code\modules\alarm\fire_alarm.dm" #include "code\modules\alarm\motion_alarm.dm" #include "code\modules\alarm\power_alarm.dm" +#include "code\modules\anomalies\anomaly.dm" +#include "code\modules\anomalies\anomaly_harvester.dm" #include "code\modules\artifice\cursedform.dm" #include "code\modules\artifice\deadringer.dm" #include "code\modules\artifice\telecube.dm"