From d33201164d5e00018ef10a8973ae6035300f1faf Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 25 Sep 2026 18:07:05 -0700 Subject: [PATCH 001/105] Rebalance the Event Horizon rifle and anomaly core supply The Event Horizon rifle kit is no longer researchable. The rifle is now a research-cache unique with three shots, no recharge, a minute between shots, on-screen range and a reality tear that no longer gibs mobs. Anomaly cores are scarce again. Cargo no longer sells raw cores. Boffin sells a limited weighted rotation of raw cores and anomaly charts, priced by rarity. A chart points the buying ship at a planet or derelict, and the anomaly only appears when that ship docks there. Planets get all nine anomaly types on a per-planet chance by zone; they move and keep their stock effects but stay on their site. The planetary pyroclastic anomaly shoots flame jets instead of venting plasma. --- .../projectiles/guns/energy/beam_rifle.dm | 10 +- code/modules/unit_tests/_unit_tests.dm | 1 + .../unit_tests/voidcrew_anomaly_trade.dm | 292 +++++++++++++ .../unit_tests/voidcrew_shop_catalog.dm | 3 + tgstation.dme | 3 + voidcrew/_DEFINES/overmap_zones.dm | 19 +- voidcrew/datums/mapgen/PlanetGenerator.dm | 8 +- voidcrew/datums/mapgen/planet_anomalies.dm | 299 +++++++++++-- .../objects/items/event_horizon_rifle.dm | 48 +++ voidcrew/modules/cargo/anomaly_packs.dm | 32 ++ .../dynamic_events/events/anomalies.dm | 2 +- voidcrew/modules/loot/themes/research.dm | 4 +- .../code/modules/overmap/space_ruin.dm | 5 +- voidcrew/modules/shuttle/helm/_helm.dm | 9 +- voidcrew/modules/trade/anomaly_charts.dm | 408 ++++++++++++++++++ voidcrew/modules/trade/rumor_charts.dm | 18 +- voidcrew/modules/trade/shop.dm | 111 ++++- .../trade/shop_catalog_outfitter_vendors.dm | 86 ++++ wiki/content/research.md | 2 +- wiki/content/trader-outposts.md | 14 +- 20 files changed, 1292 insertions(+), 82 deletions(-) create mode 100644 code/modules/unit_tests/voidcrew_anomaly_trade.dm create mode 100644 voidcrew/edits/objects/items/event_horizon_rifle.dm create mode 100644 voidcrew/modules/cargo/anomaly_packs.dm create mode 100644 voidcrew/modules/trade/anomaly_charts.dm diff --git a/code/modules/projectiles/guns/energy/beam_rifle.dm b/code/modules/projectiles/guns/energy/beam_rifle.dm index e5e36337ae2..198e5bfa9df 100644 --- a/code/modules/projectiles/guns/energy/beam_rifle.dm +++ b/code/modules/projectiles/guns/energy/beam_rifle.dm @@ -21,16 +21,10 @@ selfcharge = TRUE self_charge_amount = STANDARD_ENERGY_GUN_SELF_CHARGE_RATE * 10 -/obj/item/gun/energy/event_horizon/Initialize(mapload) - . = ..() - AddComponent(/datum/component/scope, range_modifier = 4) +// VOIDCREW EDIT REMOVAL: scope component and "must be scoped" check. It fires on screen +// only; see voidcrew/edits/objects/items/event_horizon_rifle.dm. /obj/item/gun/energy/event_horizon/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread) - - if(!HAS_TRAIT(user, TRAIT_USER_SCOPED)) - balloon_alert(user, "must be scoped!") - return - . = ..() message_admins("[ADMIN_LOOKUPFLW(user)] has fired an anti-existential beam at [ADMIN_VERBOSEJMP(user)].") diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 865ec5c355a..71599d2fcb3 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -333,6 +333,7 @@ #include "verify_config_tags.dm" #include "verify_emoji_names.dm" #include "voidcrew_ammo_box_materials.dm" +#include "voidcrew_anomaly_trade.dm" #include "voidcrew_assault_pod.dm" #include "voidcrew_autopilot_course.dm" #include "voidcrew_autotranslate_morph.dm" diff --git a/code/modules/unit_tests/voidcrew_anomaly_trade.dm b/code/modules/unit_tests/voidcrew_anomaly_trade.dm new file mode 100644 index 00000000000..9e1b8883aa8 --- /dev/null +++ b/code/modules/unit_tests/voidcrew_anomaly_trade.dm @@ -0,0 +1,292 @@ +// Fork defines are included after upstream unit tests, so the signal and zone values +// below are the literals behind them: COMSIG_VOIDCREW_SHIP_DOCKED is +// "voidcrew_ship_docked" (voidcrew/_DEFINES/ship_defines.dm). + +/// The nine raw anomaly crates are gone from every cargo console. +/datum/unit_test/voidcrew_anomaly_cargo_hidden/Run() + var/list/raw_packs = list( + /datum/supply_pack/science/raw_flux_anomaly, + /datum/supply_pack/science/raw_hallucination_anomaly, + /datum/supply_pack/science/raw_grav_anomaly, + /datum/supply_pack/science/raw_vortex_anomaly, + /datum/supply_pack/science/raw_ectoplasm_anomaly, + /datum/supply_pack/science/raw_bluespace_anomaly, + /datum/supply_pack/science/raw_pyro_anomaly, + /datum/supply_pack/science/raw_bioscrambler_anomaly, + /datum/supply_pack/science/raw_dimensional_anomaly, + ) + for(var/pack_type in raw_packs) + var/datum/supply_pack/pack = allocate(pack_type) + TEST_ASSERT_NULL(pack.contains, "[pack_type] still has contents, so SSshuttle registers it") + for(var/pack_id in SSshuttle.supply_packs) + var/datum/supply_pack/pack = SSshuttle.supply_packs[pack_id] + for(var/item in pack.contains) + if(ispath(item, /obj/item/raw_anomaly_core)) + TEST_FAIL("[pack.type] sells [item] over cargo") + +/// Boffin's core and chart rotations: every type, the right price band, one unit, +/// no discounts, and sold slots turn over instead of refilling. +/datum/unit_test/voidcrew_anomaly_boffin_shelves/Run() + var/list/core_prices = list( + /obj/item/raw_anomaly_core/flux = 25000, + /obj/item/raw_anomaly_core/grav = 25000, + /obj/item/raw_anomaly_core/hallucination = 25000, + /obj/item/raw_anomaly_core/pyro = 25000, + /obj/item/raw_anomaly_core/bioscrambler = 30000, + /obj/item/raw_anomaly_core/ectoplasm = 30000, + /obj/item/raw_anomaly_core/dimensional = 30000, + /obj/item/raw_anomaly_core/bluespace = 35000, + /obj/item/raw_anomaly_core/vortex = 35000, + ) + var/list/chart_prices = list( + /obj/effect/anomaly/flux = 12500, + /obj/effect/anomaly/grav = 12500, + /obj/effect/anomaly/hallucination = 12500, + /obj/effect/anomaly/pyro = 12500, + /obj/effect/anomaly/bioscrambler = 15000, + /obj/effect/anomaly/ectoplasm = 15000, + /obj/effect/anomaly/dimensional = 15000, + /obj/effect/anomaly/bluespace = 17500, + /obj/effect/anomaly/bhole = 17500, + ) + + var/datum/outpost_shop/shop = allocate(/datum/outpost_shop/vendor/skunkworks, null) + var/datum/shop_rotation/cores + var/datum/shop_rotation/charts + for(var/datum/shop_rotation/rotation as anything in shop.live_rotations) + if(istype(rotation, /datum/shop_rotation/skunk_cores)) + cores = rotation + else if(istype(rotation, /datum/shop_rotation/skunk_anomaly_charts)) + charts = rotation + TEST_ASSERT_NOTNULL(cores, "Boffin has no raw core rotation") + TEST_ASSERT_NOTNULL(charts, "Boffin has no anomaly chart rotation") + + var/list/cores_seen = list() + for(var/datum/shop_sku/sku_type as anything in cores.pool) + var/item = initial(sku_type.item_path) + TEST_ASSERT(item in core_prices, "[sku_type] sells [item], which is not a raw anomaly core") + TEST_ASSERT_EQUAL(initial(sku_type.price_credits), core_prices[item], "[sku_type] is in the wrong price band") + TEST_ASSERT(!initial(sku_type.fixed_price), "[sku_type] ignores favor and specials") + TEST_ASSERT(!initial(sku_type.contract_reward), "[sku_type] can be paid out by contracts") + TEST_ASSERT_EQUAL(initial(sku_type.stock_max), 1, "[sku_type] stocks more than one unit") + cores_seen[item] = cores.pool[sku_type] + TEST_ASSERT_EQUAL(length(cores_seen), 9, "Boffin's core rotation does not cover all nine types") + TEST_ASSERT(cores_seen[/obj/item/raw_anomaly_core/flux] > cores_seen[/obj/item/raw_anomaly_core/bioscrambler], "Uncommon cores are not rarer than common ones") + TEST_ASSERT(cores_seen[/obj/item/raw_anomaly_core/bioscrambler] > cores_seen[/obj/item/raw_anomaly_core/vortex], "Rare cores are not rarer than uncommon ones") + + var/list/charts_seen = list() + for(var/datum/shop_sku/anomaly_chart/sku_type as anything in charts.pool) + var/anomaly = initial(sku_type.anomaly_type) + var/base_type + for(var/candidate in chart_prices) + if(ispath(anomaly, candidate)) + base_type = candidate + break + TEST_ASSERT_NOTNULL(base_type, "[sku_type] points at [anomaly], which is not one of the nine anomaly types") + TEST_ASSERT_EQUAL(initial(sku_type.price_credits), chart_prices[base_type], "[sku_type] is in the wrong price band") + TEST_ASSERT(!initial(sku_type.fixed_price), "[sku_type] ignores favor and specials") + var/obj/effect/anomaly/anomaly_path = anomaly + TEST_ASSERT(initial(anomaly_path.immortal) && initial(anomaly_path.site_bound), "[sku_type] surfaces an anomaly that times out or can leave its site") + charts_seen[base_type] = TRUE + TEST_ASSERT_EQUAL(length(charts_seen), 9, "Boffin's chart rotation does not cover all nine types") + + for(var/datum/shop_rotation/rotation as anything in list(cores, charts)) + var/list/on_shelf = list() + for(var/datum/shop_sku/sku as anything in shop.skus) + if(sku.rotation == rotation) + on_shelf += sku + TEST_ASSERT(length(on_shelf) >= 1 && length(on_shelf) <= rotation.slots, "[rotation.type] put [length(on_shelf)] SKUs on the shelf") + var/datum/shop_sku/sold = on_shelf[1] + TEST_ASSERT_EQUAL(sold.stock, 1, "[sold.type] stocked [sold.stock] units") + sold.discount_pct = 30 + TEST_ASSERT_EQUAL(sold.get_credit_price(), round(sold.price_credits * 0.7, 5), "A special did not discount [sold.type]") + var/sold_type = sold.type + sold.stock = 0 + shop.convoy_restock() + TEST_ASSERT(!(sold in shop.skus), "The convoy refilled a sold [sold_type] in place") + var/list/after = list() + for(var/datum/shop_sku/sku as anything in shop.skus) + if(sku.rotation == rotation) + after += sku.type + TEST_ASSERT_EQUAL(length(after), length(on_shelf), "The convoy did not replace the sold slot") + TEST_ASSERT(!(sold_type in after), "The sold slot came back as the same [sold_type]") + TEST_ASSERT_EQUAL(length(unique_list(after)), length(after), "The rotation shelved the same SKU twice") + +/// Raw cores take the normal favor discount, and the better of favor or special wins. +/datum/unit_test/voidcrew_anomaly_core_favor/Run() + var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) + shop.add_sku(/datum/shop_sku/skunk/anomaly_core/vortex, "rotating") + var/datum/shop_sku/skunk/anomaly_core/sku = shop.skus[1] + var/obj/structure/overmap/ship/ship = allocate(/obj/structure/overmap/ship) + var/mob/living/carbon/human/buyer = allocate(/mob/living/carbon/human/consistent) + buyer.mind_initialize() + allocated += buyer.mind + var/datum/team/voidcrew/team = allocate(/datum/team/voidcrew) + team.ship = ship + buyer.mind.ship_teams = list(team) + sku.discount_pct = 0 + TEST_ASSERT_EQUAL(sku.get_credit_price(buyer), 35000, "A stranger got a discount") + ship.trader_favor = list() + ship.trader_favor[shop.favor_key()] = 6 // FAVOR_TIER_TRUSTED, 15% off + TEST_ASSERT_EQUAL(sku.get_credit_price(buyer), 29750, "A Trusted crew did not get the normal favor discount") + sku.discount_pct = 30 + TEST_ASSERT_EQUAL(sku.get_credit_price(buyer), 24500, "The better special did not win over favor") + sku.discount_pct = 10 + TEST_ASSERT_EQUAL(sku.get_credit_price(buyer), 29750, "Favor and special stacked, or the better one lost") + buyer.mind.ship_teams = null + team.ship = null + +/// Buying a chart takes the money and puts a sealed anomaly rumor on the ship. +/datum/unit_test/voidcrew_anomaly_chart_purchase/Run() + var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) + shop.add_sku(/datum/shop_sku/anomaly_chart/grav, "rotating") + var/datum/shop_sku/anomaly_chart/sku = shop.skus[1] + var/obj/structure/overmap/ship/ship = allocate(/obj/structure/overmap/ship) + var/mob/living/carbon/human/buyer = allocate(/mob/living/carbon/human/consistent) + buyer.mind_initialize() + allocated += buyer.mind + var/datum/team/voidcrew/team = allocate(/datum/team/voidcrew) + team.ship = ship + buyer.mind.ship_teams = list(team) + var/datum/bank_account/account = allocate(/datum/bank_account, "Anomaly chart test", null, 1, FALSE) + account.account_balance = 20000 + var/obj/item/card/id/advanced/id_card = allocate(/obj/item/card/id/advanced) + qdel(id_card.registered_account) + id_card.registered_account = account + TEST_ASSERT(buyer.put_in_hands(id_card), "Buyer could not carry their paying ID") + + TEST_ASSERT(sku.try_purchase(buyer, null), "Chart purchase failed") + TEST_ASSERT_EQUAL(account.account_balance, 7500, "The chart charged the wrong amount") + TEST_ASSERT_EQUAL(length(ship.pending_rumors), 1, "Purchase did not upload a sealed chart") + var/datum/rumor_chart/anomaly/chart = ship.pending_rumors[1] + TEST_ASSERT(istype(chart), "The sealed chart is not an anomaly chart") + TEST_ASSERT_EQUAL(chart.anomaly_type, /obj/effect/anomaly/grav/planetary, "The chart names the wrong anomaly") + TEST_ASSERT(!chart.revealed && !chart.surfaced, "A fresh chart is already revealed") + TEST_ASSERT(!sku.try_purchase(buyer, null), "A one-unit chart sold twice") + TEST_ASSERT_EQUAL(account.account_balance, 7500, "A refused purchase took money") + + qdel(ship) + TEST_ASSERT(QDELETED(chart), "Hull loss left its sealed chart alive") + buyer.mind.ship_teams = null + team.ship = null + +/// Test chart that skips site generation and spawn-point search +/datum/rumor_chart/anomaly/unit_test + var/obj/structure/overmap/test_site + var/turf/test_turf + +/datum/rumor_chart/anomaly/unit_test/pick_site(obj/structure/overmap/ship/ship) + return test_site + +/datum/rumor_chart/anomaly/unit_test/find_spawn_turf(obj/structure/overmap/site) + return test_turf + +/// Nothing on reveal, nothing for other ships or other sites, one anomaly when the +/// buyer docks at the charted site, and a lost site re-seals the chart. +/datum/unit_test/voidcrew_anomaly_chart_arrival + var/list/obj/effect/anomaly/spawned = list() + +/datum/unit_test/voidcrew_anomaly_chart_arrival/Destroy() + QDEL_LIST(spawned) + return ..() + +/datum/unit_test/voidcrew_anomaly_chart_arrival/Run() + var/obj/structure/overmap/ship/buyer = allocate(/obj/structure/overmap/ship) + var/obj/structure/overmap/ship/stranger = allocate(/obj/structure/overmap/ship) + var/obj/structure/overmap/space_ruin/site = allocate(/obj/structure/overmap/space_ruin) + var/obj/structure/overmap/space_ruin/elsewhere = allocate(/obj/structure/overmap/space_ruin) + var/turf/spot = run_loc_floor_top_right + + var/datum/rumor_chart/anomaly/unit_test/chart = new + chart.anomaly_type = /obj/effect/anomaly/flux/planetary + chart.test_site = site + chart.test_turf = spot + buyer.add_pending_rumor(chart) + + TEST_ASSERT_EQUAL(buyer.reveal_pending_rumor(chart), site, "Reveal did not chart the site") + TEST_ASSERT(!QDELETED(chart) && (chart in buyer.active_anomaly_charts), "Revealing consumed the chart before arrival") + TEST_ASSERT(!(chart in buyer.pending_rumors), "The revealed chart is still sealed on the helm") + TEST_ASSERT_NULL(locate(/obj/effect/anomaly) in spot, "Revealing the chart spawned the anomaly") + + stranger.docked = site + SEND_SIGNAL(stranger, "voidcrew_ship_docked") + TEST_ASSERT_NULL(locate(/obj/effect/anomaly) in spot, "Another crew's arrival surfaced the buyer's anomaly") + + buyer.docked = elsewhere + SEND_SIGNAL(buyer, "voidcrew_ship_docked") + TEST_ASSERT_NULL(locate(/obj/effect/anomaly) in spot, "Docking at a different site surfaced the anomaly") + + buyer.docked = site + SEND_SIGNAL(buyer, "voidcrew_ship_docked") + var/obj/effect/anomaly/anomaly = locate(/obj/effect/anomaly) in spot + if(anomaly) + spawned += anomaly + TEST_ASSERT_NOTNULL(anomaly, "The buyer docked at the site and no anomaly formed") + TEST_ASSERT(istype(anomaly, /obj/effect/anomaly/flux/planetary), "The wrong anomaly formed") + TEST_ASSERT(QDELETED(chart), "The chart outlived its anomaly") + + SEND_SIGNAL(buyer, "voidcrew_ship_docked") + var/count = 0 + for(var/obj/effect/anomaly/extra in spot) + count++ + spawned |= extra + TEST_ASSERT_EQUAL(count, 1, "A second arrival surfaced another anomaly") + + // A site that disappears before arrival hands the chart back sealed + buyer.docked = null + stranger.docked = null + var/datum/rumor_chart/anomaly/unit_test/second = new + second.anomaly_type = /obj/effect/anomaly/flux/planetary + second.test_site = elsewhere + second.test_turf = spot + buyer.add_pending_rumor(second) + TEST_ASSERT_EQUAL(buyer.reveal_pending_rumor(second), elsewhere, "Second reveal did not chart its site") + qdel(elsewhere) + TEST_ASSERT(!QDELETED(second), "Losing the site deleted the paid chart") + TEST_ASSERT((second in buyer.pending_rumors) && !(second in buyer.active_anomaly_charts), "Losing the site did not re-seal the chart") + TEST_ASSERT(!second.revealed, "The re-sealed chart still counts as revealed") + +/// Every anomaly type can seed on planets, as immortal site-bound subtypes, rarer +/// for the dangerous ones. +/datum/unit_test/voidcrew_planet_anomaly_table/Run() + var/list/base_types = list( + /obj/effect/anomaly/flux, + /obj/effect/anomaly/grav, + /obj/effect/anomaly/hallucination, + /obj/effect/anomaly/pyro, + /obj/effect/anomaly/bioscrambler, + /obj/effect/anomaly/ectoplasm, + /obj/effect/anomaly/dimensional, + /obj/effect/anomaly/bluespace, + /obj/effect/anomaly/bhole, + ) + var/list/weights = list() + for(var/base_type in base_types) + for(var/obj/effect/anomaly/entry as anything in GLOB.voidcrew_planet_anomalies) + if(!ispath(entry, base_type)) + continue + TEST_ASSERT(initial(entry.immortal), "[entry] times out on a planet") + TEST_ASSERT(initial(entry.site_bound), "[entry] can wander off its planet") + weights[base_type] = GLOB.voidcrew_planet_anomalies[entry] + TEST_ASSERT(weights[base_type], "[base_type] never seeds on planets") + TEST_ASSERT(weights[/obj/effect/anomaly/pyro] > weights[/obj/effect/anomaly/dimensional], "Uncommon planet anomalies are not rarer than common ones") + TEST_ASSERT(weights[/obj/effect/anomaly/dimensional] > weights[/obj/effect/anomaly/bhole], "Rare planet anomalies are not rarer than uncommon ones") + // Literals 1/2/3 = ZONE_GREEN/YELLOW/RED: every band can roll one, deeper bands more often + TEST_ASSERT_EQUAL(planet_anomaly_chance(1), 5, "Wrong green planet anomaly chance") + TEST_ASSERT_EQUAL(planet_anomaly_chance(2), 15, "Wrong yellow planet anomaly chance") + TEST_ASSERT_EQUAL(planet_anomaly_chance(3), 25, "Wrong red planet anomaly chance") + +/// The planetary pyroclastic anomaly burns whoever is next to it and never touches the air. +/datum/unit_test/voidcrew_planet_pyro_jets/Run() + var/obj/effect/anomaly/pyro/planetary/pyro = allocate(/obj/effect/anomaly/pyro/planetary) + var/turf/open/origin = get_turf(pyro) + var/turf/next_door = get_step(origin, NORTH) + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent, next_door) + var/datum/gas_mixture/air = origin.return_air() + var/moles_before = air.total_moles() + pyro.anomalyEffect(pyro.burst_delay) + TEST_ASSERT(victim.fire_stacks > 0, "Someone standing next to the burst was not set alight") + TEST_ASSERT(victim.getFireLoss() > 0, "Someone standing next to the burst took no burns") + air = origin.return_air() + TEST_ASSERT_EQUAL(air.total_moles(), moles_before, "The planetary pyroclastic anomaly released gas") + victim.extinguish_mob() diff --git a/code/modules/unit_tests/voidcrew_shop_catalog.dm b/code/modules/unit_tests/voidcrew_shop_catalog.dm index bbe4508086f..9f0881b9cd1 100644 --- a/code/modules/unit_tests/voidcrew_shop_catalog.dm +++ b/code/modules/unit_tests/voidcrew_shop_catalog.dm @@ -24,6 +24,9 @@ continue shops_checked++ var/list/every_sku = shop.sku_types + shop.rotating_pool + shop.rare_pool + shop.chart_pool + for(var/datum/shop_rotation/rotation as anything in shop.live_rotations) + for(var/sku_type in rotation.pool) + every_sku += sku_type for(var/datum/shop_sku/sku_type as anything in every_sku) if(!ispath(sku_type, /datum/shop_sku)) TEST_FAIL("[shop_type] lists [sku_type], which is not a /datum/shop_sku") diff --git a/tgstation.dme b/tgstation.dme index bd2724e7502..415ca5850d0 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6798,6 +6798,7 @@ #include "voidcrew\edits\mobs\respawn_timer.dm" #include "voidcrew\edits\mobs\ruin_icons.dm" #include "voidcrew\edits\mobs\ship_join_menu.dm" +#include "voidcrew\edits\objects\items\event_horizon_rifle.dm" #include "voidcrew\edits\objects\items\extinguisher.dm" #include "voidcrew\edits\objects\items\kinetic_accelerator_modkits.dm" #include "voidcrew\edits\objects\structures\closet_containment.dm" @@ -6913,6 +6914,7 @@ #include "voidcrew\modules\captain_management\captain_management.dm" #include "voidcrew\modules\captain_management\command_transfer.dm" #include "voidcrew\modules\captain_management\ship_applications.dm" +#include "voidcrew\modules\cargo\anomaly_packs.dm" #include "voidcrew\modules\cargo\bank_account.dm" #include "voidcrew\modules\cargo\bank_machine.dm" #include "voidcrew\modules\cargo\exports.dm" @@ -7358,6 +7360,7 @@ #include "voidcrew\modules\storage\smart_locker.dm" #include "voidcrew\modules\surgery\experimental_dissection.dm" #include "voidcrew\modules\teams\_team.dm" +#include "voidcrew\modules\trade\anomaly_charts.dm" #include "voidcrew\modules\trade\blueprint_imprinter.dm" #include "voidcrew\modules\trade\modsuit_bench.dm" #include "voidcrew\modules\trade\outpost.dm" diff --git a/voidcrew/_DEFINES/overmap_zones.dm b/voidcrew/_DEFINES/overmap_zones.dm index 4116c638962..7b9e7e3458f 100644 --- a/voidcrew/_DEFINES/overmap_zones.dm +++ b/voidcrew/_DEFINES/overmap_zones.dm @@ -118,7 +118,8 @@ #define ZONE_PLANET_SPAWNER_SPACING 24 /** - * How many anomalies a planet may seed, per zone. + * Percent chance a planet seeds an anomaly, per zone. At most one per planet: they are + * meant to be a rare find, and a planet rebuilds with a fresh roll each time it reloads. * * Anomalies used to be a ship-scoped dynamic event, which made them something that * happened TO a crew in their own corridors with nowhere to stand back to. On a planet @@ -126,19 +127,17 @@ * open ground, and the crew chose to walk over there. Approaching one is a decision, and * a crew carrying a neutralizer (Anomaly Research, tier 3) gets a core out of it. * - * Green stays empty for the same reason it seeds no megafauna: it is where a crew takes - * its first landing. + * Green gets the occasional one, deeper bands more often. */ -#define ZONE_PLANET_ANOMALY_BUDGET_GREEN 0 -#define ZONE_PLANET_ANOMALY_BUDGET_YELLOW 2 -#define ZONE_PLANET_ANOMALY_BUDGET_RED 3 +#define ZONE_PLANET_ANOMALY_CHANCE_GREEN 5 +#define ZONE_PLANET_ANOMALY_CHANCE_YELLOW 15 +#define ZONE_PLANET_ANOMALY_CHANCE_RED 25 -/// Minimum tiles between two planet anomalies, so a budget of 3 is three separate finds -/// rather than one lethal clearing. +/// Minimum tiles between two planet anomalies, should a planet ever seed more than one #define ZONE_PLANET_ANOMALY_SPACING 20 -/// Cap on random turf draws while placing the anomaly budget. A planet whose open ground -/// is nearly all taken simply seeds fewer than its budget rather than spinning. +/// Cap on random turf draws while placing a planet's anomaly. A planet whose open ground +/// is nearly all taken simply goes without rather than spinning. #define PLANET_ANOMALY_PLACEMENT_ATTEMPTS 400 /// Multiplier on ore mined per planet rock wall (mineralAmt), per zone, green stays baseline (x1). Applied in /turf/closed/mineral/proc/zone_scaled_ore_amount() diff --git a/voidcrew/datums/mapgen/PlanetGenerator.dm b/voidcrew/datums/mapgen/PlanetGenerator.dm index 399c382326f..4b3ab8e1531 100644 --- a/voidcrew/datums/mapgen/PlanetGenerator.dm +++ b/voidcrew/datums/mapgen/PlanetGenerator.dm @@ -397,7 +397,7 @@ var/mob_chance_mult = 1 var/mob_upgrade_prob = 0 var/spawner_budget = ZONE_PLANET_SPAWNER_BUDGET_GREEN - var/anomaly_budget = ZONE_PLANET_ANOMALY_BUDGET_GREEN + var/anomaly_chance = ZONE_PLANET_ANOMALY_CHANCE_GREEN // Megafauna are apex content and stay out of the shallow end entirely - a green-zone // planet is where a crew takes its first landing. var/megafauna_allowed = FALSE @@ -418,13 +418,13 @@ mob_chance_mult = ZONE_PLANET_MOB_CHANCE_MULT_YELLOW mob_upgrade_prob = ZONE_PLANET_MOB_UPGRADE_PROB_YELLOW spawner_budget = ZONE_PLANET_SPAWNER_BUDGET_YELLOW - anomaly_budget = ZONE_PLANET_ANOMALY_BUDGET_YELLOW + anomaly_chance = ZONE_PLANET_ANOMALY_CHANCE_YELLOW megafauna_allowed = TRUE if(ZONE_RED) mob_chance_mult = ZONE_PLANET_MOB_CHANCE_MULT_RED mob_upgrade_prob = ZONE_PLANET_MOB_UPGRADE_PROB_RED spawner_budget = ZONE_PLANET_SPAWNER_BUDGET_RED - anomaly_budget = ZONE_PLANET_ANOMALY_BUDGET_RED + anomaly_chance = ZONE_PLANET_ANOMALY_CHANCE_RED megafauna_allowed = TRUE // Structure spawners and megafauna are placed after the pass, not during it. Both are @@ -562,6 +562,8 @@ var/spawners_placed = place_budgeted_spawners(spawner_candidates, spawner_budget) var/megafauna_placed = place_planet_megafauna(megafauna_candidates) + // One anomaly at most, and only on a successful roll: they are a rare find + var/anomaly_budget = prob(anomaly_chance) ? 1 : 0 var/anomalies_placed = place_budgeted_anomalies(turfs, anomaly_budget) log_world("[name] terrain population finished in [(REALTIMEOFDAY - start_time)/10]s! \ diff --git a/voidcrew/datums/mapgen/planet_anomalies.dm b/voidcrew/datums/mapgen/planet_anomalies.dm index d48ca372ae5..8339c6c92de 100644 --- a/voidcrew/datums/mapgen/planet_anomalies.dm +++ b/voidcrew/datums/mapgen/planet_anomalies.dm @@ -7,74 +7,285 @@ * has one route between compartments, so "avoid the gravitational anomaly" and "reach * engineering" were frequently the same tile. * - * The same object on open planet ground is the opposite proposition. It is stationary, - * it is lit and visible from well outside its own reach, and nothing brought it to the - * crew, the crew walked to it. Standing next to one is a decision, and a crew that - * researched Anomaly Research (tier 3) and printed a neutralizer turns that decision - * into an anomaly core. + * The same object on open planet ground is the opposite proposition. Nothing brought it + * to the crew, the crew walked to it, and a crew that researched Anomaly Research + * (tier 3) and printed a neutralizer turns it into an anomaly core. * * These are the ONLY anomalies that spawn naturally. The ship-scoped controls in * voidcrew/modules/dynamic_events/events/anomalies.dm are all weight 0 / admin-only. + * Boffin's anomaly charts (voidcrew/modules/trade/anomaly_charts.dm) spawn the same + * subtypes inside derelicts and on planets. * - * Two properties separate a planet anomaly from its parent: + * Every anomaly type can turn up, with its stock behaviour: they wander, the vortex eats + * what it reaches and the dimensional anomaly rewrites the ground around it. Planets are + * rebuilt when a crew leaves, so the damage does not outlast the visit. What differs + * from the station versions: * * - `immortal`: planets are prebuilt in the lobby and released minutes into the round, * so a normal ANOMALY_COUNTDOWN_TIMER anomaly would detonate and vanish long before - * anybody could land and look at it. Immortal also suppresses detonate(), which is - * correct here: the payoff for finding one is the core, not the explosion. - * - `move_chance = 0`: a wandering hazard cannot be routed around, and one that drifts - * into a landing site turns a considered approach into an ambush. Planet anomalies - * stay where the generator put them. + * anybody could land and look at it. Immortal also suppresses detonate(), so the + * payoff for finding one is the core, not the explosion. + * - `site_bound`: the anomaly stays on its own site (see /datum/component/anomaly_site_leash). + * It never wanders into the cordon, onto a neighbour's site on a shared z-level, onto a + * docked ship or into a planet's landing strip, and the dimensional anomaly relocates + * within the site instead of across the sector. + * - the pyroclastic anomaly spits short jets of flame instead of venting plasma. The + * stock version's gas release gives every planet turf it spreads to a private air + * mix that never goes back to the shared one (voidcrew/edits/planetary_shared_air.dm), + * so a wandering one leaves an ever-growing trail of active air. The jets are + * visual effects plus direct burns: they never touch atmos. + * - hallucination decoys stay off. Decoys are separate, unbound anomalies with their own + * timers, spawned in a cluster around the real one; on a planet they would wander off + * the site like any unbound anomaly. */ /** - * Weighted table of anomaly types a planet may seed. - * - * Deliberately not the full anomaly roster. Excluded, and why: - * - * - bioscrambler: swapped limbs need surgery, so the injury outlives the trip home. - * - vortex: eats what it reaches, and there is nothing to do about it but not be there. - * - dimensional: rewrites surrounding turfs into a themed set, which on generated - * terrain carves a chunk of somebody's station out of the landscape. - * - pyroclastic: dumps 1000K plasma into open air every few seconds. On a planet with - * planetary_atmos that is a fire with a whole biome to spread through. - * - ectoplasm: scales off orbiting ghost count, which has nothing to do with the planet. + * Weighted table of anomaly types a planet may seed, in three rarity bands that match + * the price bands Boffin sells their cores and charts in. Whether a planet gets one at + * all is a per-zone roll (ZONE_PLANET_ANOMALY_CHANCE_*, see planet_anomaly_chance()). */ GLOBAL_LIST_INIT(voidcrew_planet_anomalies, list( - /obj/effect/anomaly/flux/planetary = 30, - /obj/effect/anomaly/grav/planetary = 30, + // Common + /obj/effect/anomaly/flux/planetary = 25, + /obj/effect/anomaly/grav/planetary = 25, /obj/effect/anomaly/hallucination/planetary = 25, - /obj/effect/anomaly/bluespace/planetary = 15, + /obj/effect/anomaly/pyro/planetary = 25, + // Uncommon + /obj/effect/anomaly/bioscrambler/planetary = 12, + /obj/effect/anomaly/ectoplasm/planetary = 12, + /obj/effect/anomaly/dimensional/planetary = 12, + // Rare + /obj/effect/anomaly/bluespace/planetary = 5, + /obj/effect/anomaly/bhole/planetary = 5, )) -/// Dense, and shocks whatever touches it. The clearest of the four: it does nothing at -/// all until something makes contact with it. +/// Percent chance a planet in `zone_band` seeds its one anomaly +/proc/planet_anomaly_chance(zone_band) + switch(zone_band) + if(ZONE_YELLOW) + return ZONE_PLANET_ANOMALY_CHANCE_YELLOW + if(ZONE_RED) + return ZONE_PLANET_ANOMALY_CHANCE_RED + return ZONE_PLANET_ANOMALY_CHANCE_GREEN + +/obj/effect/anomaly + /// Whether this anomaly is leashed to the site it formed on (see anomaly_site_leash) + var/site_bound = FALSE + +// Chains onto the upstream Initialize: runs after it, before any subtype's own body. +/obj/effect/anomaly/Initialize(mapload, new_lifespan) + . = ..() + if(site_bound && . != INITIALIZE_HINT_QDEL) + AddComponent(/datum/component/anomaly_site_leash) + /obj/effect/anomaly/flux/planetary immortal = TRUE - move_chance = 0 + site_bound = TRUE -/// Pulls loose objects and unsecured people in from a few tiles out. The one with reach, -/// so it reads as a hazard at a distance rather than a trap. /obj/effect/anomaly/grav/planetary immortal = TRUE - move_chance = 0 + site_bound = TRUE -/** - * Pulses hallucinations at anyone within a few tiles. Harmless in the sense that matters - * here: it does no damage and leaves nothing behind once the crew walks away. - * - * Decoys are off. On a station they are a science minigame. Scan the cluster, find the - * one that answers. On a planet they would be three extra processing objects and three - * extra ghost points of interest per anomaly, sitting on a z-level that is prebuilt and - * then left alone for most of the round, in service of a puzzle nobody came here to do. - */ /obj/effect/anomaly/hallucination/planetary immortal = TRUE - move_chance = 0 + site_bound = TRUE spawn_decoys = FALSE -/// Dense, and throws whatever touches it a short distance. Planets are a single cordoned -/// z-level, so it can only ever relocate somebody within the same landmass. +/** + * Every few seconds it spits one to three jets of flame, three or four tiles long, + * stopped by anything dense and by the edge of its site. Anyone in a jet or standing + * next to the anomaly at the burst is set alight and takes a light burn. The flames + * are temp visuals only: no gas, no hotspots, nothing for SSair to process. + */ +/obj/effect/anomaly/pyro/planetary + immortal = TRUE + site_bound = TRUE + /// Seconds between bursts + var/burst_delay = 4 + /// Seconds since the last burst + var/burst_timer = 0 + /// Most jets in one burst + var/max_jets = 3 + /// Jet length range, in tiles + var/jet_length_min = 3 + var/jet_length_max = 4 + /// Fire stacks given to anyone caught + var/burn_stacks = 3 + /// Burn damage dealt to anyone caught + var/burn_damage = 5 + +/obj/effect/anomaly/pyro/planetary/anomalyEffect(seconds_per_tick) + // No ..(): the parent vents plasma. Only the base proc's drift is kept. +#ifndef UNIT_TESTS + if(SPT_PROB(move_chance, seconds_per_tick)) + move_anomaly() +#endif + burst_timer += seconds_per_tick + if(burst_timer < burst_delay) + return + burst_timer = 0 + spit_flames() + +/obj/effect/anomaly/pyro/planetary/proc/spit_flames() + var/turf/origin = get_turf(src) + if(!origin) + return + var/datum/component/anomaly_site_leash/leash = GetComponent(/datum/component/anomaly_site_leash) + var/list/burned = list() + for(var/turf/adjacent in range(1, origin)) + burn_turf(adjacent, burned) + var/list/directions = GLOB.alldirs.Copy() + for(var/_ in 1 to rand(1, max_jets)) + var/jet_dir = pick_n_take(directions) + var/turf/current = origin + for(var/__ in 1 to rand(jet_length_min, jet_length_max)) + var/turf/next = get_step(current, jet_dir) + if(!next || next.is_blocked_turf(exclude_mobs = TRUE)) + break + if(leash && !leash.allows(next)) + break + new /obj/effect/temp_visual/fire(next) + burn_turf(next, burned) + current = next + playsound(src, 'sound/effects/fire_puff.ogg', 50, TRUE) + +/// Sets anyone living on `target` alight, once per burst +/obj/effect/anomaly/pyro/planetary/proc/burn_turf(turf/target, list/burned) + for(var/mob/living/victim in target) + if(victim in burned) + continue + burned += victim + victim.adjust_fire_stacks(burn_stacks) + victim.ignite_mob() + victim.apply_damage(burn_damage, BURN) + +/obj/effect/anomaly/bioscrambler/planetary + immortal = TRUE + site_bound = TRUE + +/obj/effect/anomaly/ectoplasm/planetary + immortal = TRUE + site_bound = TRUE + +/obj/effect/anomaly/dimensional/planetary + immortal = TRUE + site_bound = TRUE + +/// Never converts ground off its own site: no docked hull, no cordon, no neighbour. +/obj/effect/anomaly/dimensional/planetary/prepare_area(new_theme_path) + . = ..() + var/datum/component/anomaly_site_leash/leash = GetComponent(/datum/component/anomaly_site_leash) + if(!leash) + return + for(var/turf/target as anything in target_turfs.Copy()) + if(!leash.allows(target)) + target_turfs -= target + +/// Upstream relocates to a random station area with a sector-wide announcement. Here it +/// jumps to another spot on the same site, quietly. +/obj/effect/anomaly/dimensional/planetary/relocate() + var/datum/component/anomaly_site_leash/leash = GetComponent(/datum/component/anomaly_site_leash) + var/turf/new_turf = leash?.random_open_turf() + if(new_turf) + forceMove(new_turf) + prepare_area() + /obj/effect/anomaly/bluespace/planetary immortal = TRUE - move_chance = 0 + site_bound = TRUE + +/obj/effect/anomaly/bhole/planetary + immortal = TRUE + site_bound = TRUE + +/** + * # Anomaly site leash + * + * Keeps a wandering anomaly on the site it formed on. Bounds are taken from the site's + * map footprint when the anomaly appears: the whole footprint for a planet, minus the + * landing strip along its bottom, or the ruin template's own rectangle for a space + * ruin. On top of that it never enters a ship (/area/shuttle), the cordon or open space + * (/area/space), or another z-level. + * + * Every way an anomaly moves itself (random drift, the bioscrambler's pursuit, deadchat + * steering of the ectoplasm anomaly) goes through Move(), so blocking PRE_MOVE covers + * them. The dimensional anomaly's forceMove relocation asks random_open_turf() instead. + */ +/datum/component/anomaly_site_leash + /// The z-level the anomaly formed on + var/home_z + /// Inclusive bounds, null when the anomaly formed outside any known site + var/low_x + var/low_y + var/high_x + var/high_y + +/datum/component/anomaly_site_leash/Initialize() + if(!istype(parent, /obj/effect/anomaly)) + return COMPONENT_INCOMPATIBLE + var/turf/home = get_turf(parent) + if(!home) + return COMPONENT_INCOMPATIBLE + home_z = home.z + derive_bounds(home) + +/datum/component/anomaly_site_leash/RegisterWithParent() + RegisterSignal(parent, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_pre_move)) + +/datum/component/anomaly_site_leash/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_MOVABLE_PRE_MOVE) + +/datum/component/anomaly_site_leash/proc/derive_bounds(turf/home) + var/datum/map_footprint/footprint = map_region_for_turf(home) + if(!istype(footprint)) + return + low_x = footprint.low_x + low_y = footprint.low_y + high_x = footprint.high_x + high_y = footprint.high_y + if(istype(footprint.owner, /obj/structure/overmap/planet)) + var/obj/structure/overmap/planet/planet = footprint.owner + var/strip_top = planet.get_dock_strip_top_y(footprint.level) + // An anomaly placed inside the strip by hand keeps the full footprint rather + // than being frozen in place. + if(!isnull(strip_top) && home.y > strip_top) + low_y = max(low_y, strip_top + 1) + else if(istype(footprint.owner, /obj/structure/overmap/space_ruin)) + var/obj/structure/overmap/space_ruin/ruin = footprint.owner + var/turf/corner = ruin.ruin_bottom_left + if(corner && ruin.ruin_template?.width && ruin.ruin_template?.height) + low_x = max(low_x, corner.x) + low_y = max(low_y, corner.y) + high_x = min(high_x, corner.x + ruin.ruin_template.width - 1) + high_y = min(high_y, corner.y + ruin.ruin_template.height - 1) + +/// Whether the anomaly may stand on `destination` +/datum/component/anomaly_site_leash/proc/allows(turf/destination) + if(!isturf(destination) || destination.z != home_z) + return FALSE + if(!isnull(low_x) && (destination.x < low_x || destination.x > high_x || destination.y < low_y || destination.y > high_y)) + return FALSE + if(istype(destination, /turf/cordon)) + return FALSE + var/area/destination_area = get_area(destination) + if(istype(destination_area, /area/shuttle) || istype(destination_area, /area/space)) + return FALSE + return TRUE + +/datum/component/anomaly_site_leash/proc/on_pre_move(atom/movable/source, atom/new_loc) + SIGNAL_HANDLER + if(!allows(new_loc)) + return COMPONENT_MOVABLE_BLOCK_PRE_MOVE + +/// A random open, walkable turf the anomaly may stand on, or null +/datum/component/anomaly_site_leash/proc/random_open_turf(attempts = 60) + if(isnull(low_x)) + return null + for(var/_ in 1 to attempts) + var/turf/candidate = locate(rand(low_x, high_x), rand(low_y, high_y), home_z) + if(!isopenturf(candidate) || isgroundlessturf(candidate) || candidate.density) + continue + if(!allows(candidate)) + continue + return candidate + return null diff --git a/voidcrew/edits/objects/items/event_horizon_rifle.dm b/voidcrew/edits/objects/items/event_horizon_rifle.dm new file mode 100644 index 00000000000..6039a35271e --- /dev/null +++ b/voidcrew/edits/objects/items/event_horizon_rifle.dm @@ -0,0 +1,48 @@ +// Event Horizon rifle rebalance. It is a rare loot find rather than a research print: +// three shots that never recharge, a minute between shots, on-screen range only, and a +// reality tear that eats the room but not the people in it. + +/datum/techweb_node/unregulated_bluespace + design_ids = list( + "desynchronizer", + ) + +/obj/item/gun/energy/event_horizon + selfcharge = FALSE + can_charge = FALSE + /// Time between shots. + var/shot_cooldown_time = 1 MINUTES + COOLDOWN_DECLARE(shot_cooldown) + +/obj/item/gun/energy/event_horizon/get_cell(atom/movable/interface, mob/user) + return null // Nothing may reach the cell to top it up. + +/obj/item/gun/energy/event_horizon/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread) + if(!COOLDOWN_FINISHED(src, shot_cooldown)) + balloon_alert(user, "ready in [round(COOLDOWN_TIMELEFT(src, shot_cooldown) / (1 SECONDS))]s!") + return + . = ..() + if(.) + COOLDOWN_START(src, shot_cooldown, shot_cooldown_time) + +/obj/item/gun/energy/event_horizon/examine(mob/user) + . = ..() + if(!COOLDOWN_FINISHED(src, shot_cooldown)) + . += span_notice("It is still cycling. It can fire again in [DisplayTimeText(COOLDOWN_TIMELEFT(src, shot_cooldown))].") + +/obj/item/ammo_casing/energy/event_horizon + e_cost = LASER_SHOTS(3, STANDARD_CELL_CHARGE) + +/obj/projectile/beam/event_horizon + range = 9 + +/obj/reality_tear/temporary/start_disaster() + . = ..() + var/datum/component/singularity/singularity = GetComponent(/datum/component/singularity) + singularity?.consume_callback = CALLBACK(src, PROC_REF(consume_without_gibbing)) + +/// Consumes everything the tear reaches except living mobs, which it only throws around. +/obj/reality_tear/temporary/proc/consume_without_gibbing(atom/thing, datum/component/singularity/source) + if(isliving(thing)) + return + thing.singularity_act(source.singularity_size, src) diff --git a/voidcrew/modules/cargo/anomaly_packs.dm b/voidcrew/modules/cargo/anomaly_packs.dm new file mode 100644 index 00000000000..86a28ed4be7 --- /dev/null +++ b/voidcrew/modules/cargo/anomaly_packs.dm @@ -0,0 +1,32 @@ +/** + * Raw anomaly cores are off the cargo catalogue. + * + * The anomaly core cap is lifted in this fork (voidcrew/modules/research/edits/ + * _experiments.dm), so a 2000 cr crate per core made them a routine order. + * Boffin at the Quartermain Depot is now the only store that sells raw cores, + * on a small rotating shelf, with anomaly charts as the other way to hunt one + * (shop_catalog_outfitter_vendors.dm, anomaly_charts.dm). + * + * SSshuttle only registers packs with a non-null `contains`. Overriding the var + * to null does not work for these: upstream sets `contains = list(...)`, and a + * list default is built at New() time, after the null has been applied, so the + * pack comes back with its contents. Clearing it in New() drops each crate from + * every console without touching the upstream definitions. + */ +GLOBAL_LIST_INIT(voidcrew_removed_supply_packs, typecacheof(list( + /datum/supply_pack/science/raw_flux_anomaly, + /datum/supply_pack/science/raw_hallucination_anomaly, + /datum/supply_pack/science/raw_grav_anomaly, + /datum/supply_pack/science/raw_vortex_anomaly, + /datum/supply_pack/science/raw_ectoplasm_anomaly, + /datum/supply_pack/science/raw_bluespace_anomaly, + /datum/supply_pack/science/raw_pyro_anomaly, + /datum/supply_pack/science/raw_bioscrambler_anomaly, + /datum/supply_pack/science/raw_dimensional_anomaly, +))) + +// Chains onto the upstream New. +/datum/supply_pack/New() + . = ..() + if(GLOB.voidcrew_removed_supply_packs[type]) + contains = null diff --git a/voidcrew/modules/dynamic_events/events/anomalies.dm b/voidcrew/modules/dynamic_events/events/anomalies.dm index 4fe5da0002a..e62e181b613 100644 --- a/voidcrew/modules/dynamic_events/events/anomalies.dm +++ b/voidcrew/modules/dynamic_events/events/anomalies.dm @@ -7,7 +7,7 @@ * * ALL OF THESE ARE ADMIN-ONLY. Every control below is weight 0 / max_occurrences 0, and * none of them roll naturally. Anomalies now generate on planet surfaces instead, see - * voidcrew/datums/mapgen/planet_anomalies.dm and the ZONE_PLANET_ANOMALY_BUDGET_* defines. + * voidcrew/datums/mapgen/planet_anomalies.dm and the ZONE_PLANET_ANOMALY_CHANCE_* defines. * * The reason is that a shuttle is the worst possible venue for one. A ship has a single * route between compartments, so an anomaly spawned in a corridor is not a hazard the diff --git a/voidcrew/modules/loot/themes/research.dm b/voidcrew/modules/loot/themes/research.dm index d3d145dd4c2..0cc73c690c6 100644 --- a/voidcrew/modules/loot/themes/research.dm +++ b/voidcrew/modules/loot/themes/research.dm @@ -43,7 +43,6 @@ /obj/item/gun/energy/laser/retro = 6, /obj/item/gun/energy/recharge/ebow = 4, /obj/item/reagent_containers/cup/beaker/noreact = 4, - /obj/item/raw_anomaly_core/random = 4, /obj/item/blueprint/gun/laser_carbine = 3, /obj/item/ship_parts/science = 7, // lab hardware worn instead of carried: a sonar transceiver socketed @@ -52,6 +51,7 @@ ) loot_prime = list( /obj/item/stack/ore/bluespace_crystal/refined = 10, + /obj/item/raw_anomaly_core/random = 4, /obj/item/stock_parts/capacitor/super = 8, /obj/item/stock_parts/micro_laser/ultra = 8, /obj/item/stock_parts/matter_bin/super = 7, @@ -89,6 +89,8 @@ /obj/item/reagent_containers/cup/beaker/entangled = 2, /obj/item/clothing/gloves/fingerless/chronal_splint = 1, /obj/item/clothing/suit/toggle/labcoat/eventide_courier = 1, + // no longer researchable: three shots and no way to recharge it + /obj/item/gun/energy/event_horizon = 1, ) /obj/structure/closet/crate/zone_loot/research diff --git a/voidcrew/modules/overmap/code/modules/overmap/space_ruin.dm b/voidcrew/modules/overmap/code/modules/overmap/space_ruin.dm index 1875cd6f973..ee3ebd126c9 100644 --- a/voidcrew/modules/overmap/code/modules/overmap/space_ruin.dm +++ b/voidcrew/modules/overmap/code/modules/overmap/space_ruin.dm @@ -56,6 +56,9 @@ GLOBAL_LIST_EMPTY(space_ruin_signals) /// Rare ruins come from rumor charts, not natural seeding: tinted gold on /// the map, and cleaning one out never spawns a replacement. var/rare = FALSE + /// Spawned for one purpose (an anomaly chart's site): cleaning it out does not seed + /// a replacement, so the sector's ruin count stays where natural seeding left it. + var/no_replacement = FALSE /// Live missions currently pointed at this ruin; target picks prefer unclaimed ruins var/mission_claims = 0 /// A mission owns this ruin's lifecycle: the empty-ruin cleanup in @@ -761,7 +764,7 @@ GLOBAL_LIST_EMPTY(space_ruin_signals) // Spawn a new ruin somewhere else on the overmap BEFORE we delete ourselves. // Rare rumor ruins are one-shots: clearing one doesn't seed anything new. - if(!rare) + if(!rare && !no_replacement) spawn_replacement_ruin(old_template) // Delete this overmap object diff --git a/voidcrew/modules/shuttle/helm/_helm.dm b/voidcrew/modules/shuttle/helm/_helm.dm index 2932dcbf3b4..7fa09e83eca 100644 --- a/voidcrew/modules/shuttle/helm/_helm.dm +++ b/voidcrew/modules/shuttle/helm/_helm.dm @@ -1016,13 +1016,14 @@ var/datum/rumor_chart/chart = locate(params["chart"]) in current_ship.pending_rumors if(!chart) return - var/obj/structure/overmap/space_ruin/ruin = current_ship.reveal_pending_rumor(chart) - if(!ruin) + var/reveal_noun = chart.reveal_noun + var/obj/structure/overmap/site = current_ship.reveal_pending_rumor(chart) + if(!site) say("ERROR: Unable to pin down the rumor's coordinates. Retry shortly.") playsound(src, 'sound/machines/terminal/terminal_error.ogg', 30) return - var/list/coords = ruin.get_relative_overmap_coords() - say("Rumor decrypted: rare signal located at ([coords[1]], [coords[2]]). Charted under Rumors.") + var/list/coords = site.get_relative_overmap_coords() + say("Rumor decrypted: [reveal_noun] located at ([coords[1]], [coords[2]]). Charted under Rumors.") playsound(src, 'sound/machines/ping.ogg', 40) return if("reload_ship") diff --git a/voidcrew/modules/trade/anomaly_charts.dm b/voidcrew/modules/trade/anomaly_charts.dm new file mode 100644 index 00000000000..a11b91b0b6d --- /dev/null +++ b/voidcrew/modules/trade/anomaly_charts.dm @@ -0,0 +1,408 @@ +/** + * # Anomaly charts + * + * Boffin's other way to an anomaly core. A chart names one anomaly type. Buying + * it uploads a sealed rumor to the buyer's ship like a ruin chart; the helm's + * reveal button then picks the site, either a fresh ordinary derelict spawned in + * the chart's zone band or a terrain planet already in that band, and charts it + * under Rumors. + * + * Nothing spawns on reveal. The anomaly forms only when the BUYING hull docks at + * that site, somewhere inside the derelict or out on the planet away from the + * landing strip. A crew that gets there first finds an ordinary site. One chart + * surfaces one anomaly, then the chart is spent. + * + * If the site is cleaned up before the buyer arrives (another crew loaded and + * left a derelict, an admin deleted it), the chart goes back to the helm sealed + * and can be revealed again for a new site. It dies with the buying hull. + * + * The anomalies are the site-bound planetary subtypes from + * voidcrew/datums/mapgen/planet_anomalies.dm: immortal, stock behaviour, leashed + * to the site they formed on. + */ + +/// How far from the buyer's docking port a derelict anomaly prefers to form +#define ANOMALY_CHART_RUIN_MIN_DISTANCE 6 +/// Rows of ground kept clear between a planet's landing strip and a chart anomaly +#define ANOMALY_CHART_PLANET_CLEARANCE 12 +/// Random ground samples tried on a planet before giving up for this arrival +#define ANOMALY_CHART_PLANET_ATTEMPTS 400 + +/obj/structure/overmap/ship + /// Revealed anomaly charts still waiting for this ship to dock at their site + var/list/datum/rumor_chart/anomaly/active_anomaly_charts = list() + +/datum/rumor_chart/anomaly + name = "anomaly chart" + reveal_noun = "anomaly site" + keep_after_reveal = TRUE + spawn_zone = ZONE_YELLOW + /// The site-bound anomaly this chart surfaces + var/obj/effect/anomaly/anomaly_type + /// Percent chance the reveal tries a planet before a derelict + var/planet_chance = 50 + /// The ship that revealed the chart; only its arrival surfaces the anomaly + var/obj/structure/overmap/ship/buyer + /// The revealed site + var/datum/weakref/site_ref + /// Set once the anomaly exists + var/surfaced = FALSE + +/datum/rumor_chart/anomaly/Destroy() + release_site() + if(buyer) + UnregisterSignal(buyer, list(COMSIG_VOIDCREW_SHIP_DOCKED, COMSIG_QDELETING)) + buyer.active_anomaly_charts -= src + buyer.pending_rumors -= src + buyer = null + return ..() + +/datum/rumor_chart/anomaly/proc/waypoint_key() + return "anomaly_[REF(src)]" + +/datum/rumor_chart/anomaly/reveal(obj/structure/overmap/ship/ship) + if(QDELETED(ship) || revealed || !ispath(anomaly_type, /obj/effect/anomaly)) + return null + var/obj/structure/overmap/site = pick_site(ship) + if(!site) + return null + + revealed = TRUE + buyer = ship + site_ref = WEAKREF(site) + ship.active_anomaly_charts |= src + RegisterSignal(ship, COMSIG_VOIDCREW_SHIP_DOCKED, PROC_REF(on_buyer_docked)) + RegisterSignal(ship, COMSIG_QDELETING, PROC_REF(on_buyer_deleted)) + RegisterSignal(site, COMSIG_QDELETING, PROC_REF(on_site_deleted)) + + var/list/coords = site.get_relative_overmap_coords() + ship.add_waypoint(waypoint_key(), name, coords[1], coords[2], "Rumors", site) + log_game("Anomaly chart '[name]' revealed for [ship]: [site] ([site.type]) at ([coords[1]], [coords[2]])") + return site + +/** + * A planet or a fresh derelict in the chart's band, in random order, falling back + * to the other kind when the first has nothing to offer. + */ +/datum/rumor_chart/anomaly/proc/pick_site(obj/structure/overmap/ship/ship) + var/planet_first = prob(planet_chance) + var/obj/structure/overmap/site = planet_first ? pick_planet(ship) : spawn_derelict() + if(site) + return site + return planet_first ? spawn_derelict() : pick_planet(ship) + +/// A terrain planet in the chart's band that the buyer is not already docked at +/datum/rumor_chart/anomaly/proc/pick_planet(obj/structure/overmap/ship/ship) + var/list/candidates = list() + for(var/obj/structure/overmap/planet/planet as anything in GLOB.overmap_planets) + if(QDELETED(planet) || planet.unloading || !planet.is_terrain_planet()) + continue + if(!istype(get_turf(planet), /turf/open/overmap)) + continue + if(planet.get_effective_zone_band() != spawn_zone) + continue + // The anomaly waits for an arrival, so the site has to be somewhere to arrive at + if(ship.docked == planet) + continue + candidates += planet + if(!length(candidates)) + return null + return pick(candidates) + +/// A fresh ordinary derelict in the chart's band, left unloaded like any other signal +/datum/rumor_chart/anomaly/proc/spawn_derelict() + var/list/live_templates = list() + for(var/obj/structure/overmap/space_ruin/live as anything in GLOB.space_ruin_signals) + if(!QDELETED(live) && live.ruin_template) + live_templates[live.ruin_template] = TRUE + + var/list/weighted = list() + var/list/weighted_duplicates = list() + for(var/template_id in SSmapping.space_ruins_templates) + var/datum/map_template/ruin/space/template = SSmapping.space_ruins_templates[template_id] + if(!istype(template) || template.unpickable) + continue + // Oversized ruins take a whole z-level; keep charts to the ones that pack + if(template.width && !SSovermap.ruin_fits_in_slot(template)) + continue + if(live_templates[template]) + if(template.allow_duplicates) + weighted_duplicates[template] = template.placement_weight || 1 + continue + weighted[template] = template.placement_weight || 1 + if(!length(weighted)) + weighted = weighted_duplicates + if(!length(weighted)) + return null + + var/turf/spawn_turf = SSovermap.get_unused_overmap_square_in_zone_band(spawn_zone) + if(!spawn_turf) + return null + var/obj/structure/overmap/space_ruin/ruin = new(spawn_turf) + ruin.set_ruin_template(pick_weight(weighted)) + ruin.no_replacement = TRUE + return ruin + +/datum/rumor_chart/anomaly/proc/on_buyer_docked(obj/structure/overmap/ship/source) + SIGNAL_HANDLER + if(surfaced) + return + var/obj/structure/overmap/site = site_ref?.resolve() + if(!site || source.docked != site) + return + INVOKE_ASYNC(src, PROC_REF(surface_anomaly), site) + +/** + * The buyer has docked at the site: put the anomaly somewhere on it and tell the + * crew. If no spot is found the chart stays live for the next arrival. + */ +/datum/rumor_chart/anomaly/proc/surface_anomaly(obj/structure/overmap/site) + if(surfaced || QDELETED(src) || QDELETED(site) || QDELETED(buyer) || buyer.docked != site) + return FALSE + var/turf/spawn_turf = find_spawn_turf(site) + if(!spawn_turf) + buyer.ship_notify("Faint anomalous readings near [site.name], too unsteady to fix. They may settle on your next approach.", "SENSORS", SHIP_NOTIFY_WARNING, 'voidcrew/sound/warn.ogg', 25) + return FALSE + + surfaced = TRUE + var/obj/effect/anomaly/anomaly = new anomaly_type(spawn_turf) + var/where = describe_position(spawn_turf) + buyer.ship_notify("Anomalous readings: \a [anomaly] has formed [where].", "SENSORS", SHIP_NOTIFY_NOTICE, 'voidcrew/sound/notify.ogg', 50) + log_game("Anomaly chart '[name]' surfaced [anomaly] at [AREACOORD(spawn_turf)] for [buyer]") + qdel(src) + return TRUE + +/// "about 30 metres north of the ship", from the buyer's docking port +/datum/rumor_chart/anomaly/proc/describe_position(turf/spawn_turf) + var/turf/ship_turf = get_turf(buyer?.shuttle) + if(!ship_turf || ship_turf.z != spawn_turf.z) + return "on the site" + var/distance = get_dist(ship_turf, spawn_turf) + var/direction = dir2text(get_dir(ship_turf, spawn_turf)) + if(!direction || distance < 2) + return "right by the ship" + return "about [distance] metres [direction] of the ship" + +/datum/rumor_chart/anomaly/proc/find_spawn_turf(obj/structure/overmap/site) + if(istype(site, /obj/structure/overmap/space_ruin)) + return find_derelict_turf(site) + if(istype(site, /obj/structure/overmap/planet)) + return find_planet_turf(site) + return null + +/// Whether an anomaly may form on `candidate`: open walkable ground on the site itself +/datum/rumor_chart/anomaly/proc/is_valid_spot(turf/candidate, datum/map_footprint/footprint) + if(!isopenturf(candidate) || isgroundlessturf(candidate) || isspaceturf(candidate)) + return FALSE + if(islava(candidate) || istype(candidate, /turf/open/water)) + return FALSE + if(candidate.is_blocked_turf(exclude_mobs = TRUE)) + return FALSE + var/area/candidate_area = get_area(candidate) + if(istype(candidate_area, /area/shuttle) || istype(candidate_area, /area/space)) + return FALSE + if(footprint && !footprint.contains_turf(candidate)) + return FALSE + if(locate(/obj/effect/anomaly) in candidate) + return FALSE + return TRUE + +/// Open floor inside the derelict's own template, preferring a few steps from the ship +/datum/rumor_chart/anomaly/proc/find_derelict_turf(obj/structure/overmap/space_ruin/ruin) + var/turf/corner = ruin.ruin_bottom_left + if(!ruin.loaded || !corner || !ruin.ruin_template?.width || !ruin.ruin_template?.height) + return null + var/turf/far_corner = locate(corner.x + ruin.ruin_template.width - 1, corner.y + ruin.ruin_template.height - 1, corner.z) + if(!far_corner) + return null + var/turf/ship_turf = get_turf(buyer?.shuttle) + var/list/near = list() + var/list/far = list() + for(var/turf/candidate as anything in block(corner, far_corner)) + if(!is_valid_spot(candidate, ruin.footprint)) + continue + if(ship_turf && get_dist(candidate, ship_turf) < ANOMALY_CHART_RUIN_MIN_DISTANCE) + near += candidate + else + far += candidate + CHECK_TICK + if(length(far)) + return pick(far) + if(length(near)) + return pick(near) + return null + +/// Open ground on the planet, well clear of the landing strip +/datum/rumor_chart/anomaly/proc/find_planet_turf(obj/structure/overmap/planet/planet) + var/datum/map_footprint/footprint = planet.footprint + if(!planet.loaded || !footprint || isnull(footprint.low_x)) + return null + var/strip_top = planet.get_dock_strip_top_y(footprint.level) + if(isnull(strip_top)) + strip_top = footprint.low_y + var/min_x = footprint.low_x + 3 + var/max_x = footprint.high_x - 3 + var/max_y = footprint.high_y - 3 + var/min_y = min(strip_top + ANOMALY_CHART_PLANET_CLEARANCE, max_y) + min_y = max(min_y, strip_top + 1) + if(min_x > max_x || min_y > max_y) + return null + for(var/_ in 1 to ANOMALY_CHART_PLANET_ATTEMPTS) + var/turf/candidate = locate(rand(min_x, max_x), rand(min_y, max_y), footprint.z_value) + if(is_valid_spot(candidate, footprint)) + return candidate + return null + +/datum/rumor_chart/anomaly/proc/on_buyer_deleted(datum/source) + SIGNAL_HANDLER + qdel(src) + +/datum/rumor_chart/anomaly/proc/on_site_deleted(datum/source) + SIGNAL_HANDLER + if(surfaced) + return + INVOKE_ASYNC(src, PROC_REF(reseal)) + +/// Forgets the site, drops the waypoint and stops listening to the site +/datum/rumor_chart/anomaly/proc/release_site() + var/obj/structure/overmap/site = site_ref?.resolve() + if(site) + UnregisterSignal(site, COMSIG_QDELETING) + site_ref = null + if(buyer) + var/datum/ship_waypoint/waypoint = buyer.get_waypoint(waypoint_key()) + if(waypoint) + buyer.delete_waypoint(waypoint) + +/** + * The site vanished before the buyer arrived. The chart goes back on the helm, + * sealed, so the crew can reveal it again for a new site. + */ +/datum/rumor_chart/anomaly/proc/reseal() + if(QDELETED(src) || surfaced || QDELETED(buyer)) + return + var/obj/structure/overmap/ship/ship = buyer + release_site() + UnregisterSignal(ship, list(COMSIG_VOIDCREW_SHIP_DOCKED, COMSIG_QDELETING)) + ship.active_anomaly_charts -= src + buyer = null + revealed = FALSE + ship.pending_rumors |= src + ship.ship_notify("The site on the \"[name]\" chart has dropped off the scopes. The chart is sealed again and can be revealed from the helm for a new fix.", "HELM", SHIP_NOTIFY_WARNING, 'voidcrew/sound/warn.ogg', 25) + +/** + * # Anomaly chart SKU + * + * Sold on Boffin's chart rotation. No goods change hands: the sealed chart goes + * straight to the buyer's ship, and its reveal and arrival do the rest. Stock is + * one, and a sold chart's slot turns over to a different anomaly at the next + * convoy rather than refilling (see /datum/shop_rotation). + */ +/datum/shop_sku/anomaly_chart + category = "Anomalies" + icon_override = 'icons/obj/scrolls.dmi' + icon_state_override = "blueprints" + is_chart = TRUE + stock_min = 1 + stock_max = 1 + contract_reward = FALSE + /// The site-bound anomaly the chart surfaces + var/obj/effect/anomaly/anomaly_type + /// Zone band the chart's site is found in + var/spawn_zone = ZONE_YELLOW + +/datum/shop_sku/anomaly_chart/New() + . = ..() + if(!anomaly_type) + return + var/anomaly_name = initial(anomaly_type.name) + var/band_name = spawn_zone == ZONE_RED ? ZONE_NAME_RED : ZONE_NAME_YELLOW + name = "anomaly chart: [anomaly_name]" + desc = "Sensor logs on \a [anomaly_name] settling somewhere in the [band_name], either aboard a derelict or out on a planet. Uploaded sealed to your helm. The readings only firm up once your own ship is docked at the site." + +/datum/shop_sku/anomaly_chart/get_denial_reason(mob/living/user) + . = ..() + if(.) + return + if(!get_crew_ship(user)) + return "No crew registration, you need a ship to upload the chart to." + +/datum/shop_sku/anomaly_chart/try_purchase(mob/living/user, mob/living/basic/outpost_trader/vendor) + if(stock <= 0) + return FALSE + var/obj/structure/overmap/ship/ship = get_crew_ship(user) + if(!ship) + return FALSE + + var/credit_price = get_credit_price(user) + var/datum/bank_account/account + if(credit_price > 0) + account = get_account(user) + if(!account || !account.has_money(credit_price)) + return FALSE + + if(price_vouchers > 0 && !consume_trade_vouchers(user, price_vouchers)) + return FALSE + if(credit_price > 0 && !account.adjust_money(-credit_price, "Trader Outpost: [name]")) + return FALSE + + stock-- + ship.add_pending_rumor(create_chart()) + to_chat(user, span_notice("The chart is encrypted and beamed to [ship]'s helm console. Reveal it when your crew is ready to move.")) + return TRUE + +/// A fresh sealed chart for one purchase +/datum/shop_sku/anomaly_chart/proc/create_chart() + var/datum/rumor_chart/anomaly/chart = new + var/anomaly_name = initial(anomaly_type.name) + chart.name = capitalize(anomaly_name) + chart.desc = "[capitalize("\a [anomaly_name]")] in the [spawn_zone == ZONE_RED ? ZONE_NAME_RED : ZONE_NAME_YELLOW]. Nothing will show on the site until your ship docks there." + chart.anomaly_type = anomaly_type + chart.spawn_zone = spawn_zone + return chart + +// Three bands, the same as the raw cores, at half the core's list price. Normal +// favor discounts and specials apply. +// The two rarest point into the lawless deep. + +/datum/shop_sku/anomaly_chart/flux + anomaly_type = /obj/effect/anomaly/flux/planetary + price_credits = 12500 + +/datum/shop_sku/anomaly_chart/grav + anomaly_type = /obj/effect/anomaly/grav/planetary + price_credits = 12500 + +/datum/shop_sku/anomaly_chart/hallucination + anomaly_type = /obj/effect/anomaly/hallucination/planetary + price_credits = 12500 + +/datum/shop_sku/anomaly_chart/pyro + anomaly_type = /obj/effect/anomaly/pyro/planetary + price_credits = 12500 + +/datum/shop_sku/anomaly_chart/bioscrambler + anomaly_type = /obj/effect/anomaly/bioscrambler/planetary + price_credits = 15000 + +/datum/shop_sku/anomaly_chart/ectoplasm + anomaly_type = /obj/effect/anomaly/ectoplasm/planetary + price_credits = 15000 + +/datum/shop_sku/anomaly_chart/dimensional + anomaly_type = /obj/effect/anomaly/dimensional/planetary + price_credits = 15000 + +/datum/shop_sku/anomaly_chart/bluespace + anomaly_type = /obj/effect/anomaly/bluespace/planetary + price_credits = 17500 + spawn_zone = ZONE_RED + +/datum/shop_sku/anomaly_chart/vortex + anomaly_type = /obj/effect/anomaly/bhole/planetary + price_credits = 17500 + spawn_zone = ZONE_RED + +#undef ANOMALY_CHART_RUIN_MIN_DISTANCE +#undef ANOMALY_CHART_PLANET_CLEARANCE +#undef ANOMALY_CHART_PLANET_ATTEMPTS diff --git a/voidcrew/modules/trade/rumor_charts.dm b/voidcrew/modules/trade/rumor_charts.dm index b8ae9634427..bc8b43251ea 100644 --- a/voidcrew/modules/trade/rumor_charts.dm +++ b/voidcrew/modules/trade/rumor_charts.dm @@ -31,6 +31,11 @@ var/spawn_zone = ZONE_RED /// One successful reveal per paid chart; failed placement remains retryable. var/revealed = FALSE + /// What the helm calls the revealed target in its readout + var/reveal_noun = "rare signal" + /// Charts with work left after the reveal (anomaly charts wait for the crew to + /// arrive) manage their own lifetime instead of being deleted on reveal. + var/keep_after_reveal = FALSE /** * Spawns the chart's ruin at an unused square in the chart's zone band and @@ -78,18 +83,19 @@ ship_notify("Encrypted rumor data received: \"[chart.name]\". Reveal it from the helm console when ready.", "HELM", SHIP_NOTIFY_NOTICE, 'voidcrew/sound/notify.ogg', 50) /** - * Reveals a pending rumor: spawns its ruin, charts the waypoint and consumes - * the sealed entry. Returns the ruin, or null on failure (entry is kept). + * Reveals a pending rumor: spawns or picks its site, charts the waypoint and + * consumes the sealed entry. Returns the site, or null on failure (entry is kept). */ /obj/structure/overmap/ship/proc/reveal_pending_rumor(datum/rumor_chart/chart) if(!(chart in pending_rumors)) return null - var/obj/structure/overmap/space_ruin/ruin = chart.reveal(src) - if(!ruin) + var/obj/structure/overmap/site = chart.reveal(src) + if(!site) return null pending_rumors -= chart - qdel(chart) - return ruin + if(!chart.keep_after_reveal) + qdel(chart) + return site /** * Gets an unused overmap square in the given zone band (ZONE_RED/YELLOW/GREEN). diff --git a/voidcrew/modules/trade/shop.dm b/voidcrew/modules/trade/shop.dm index 8fd29a88169..68683a4d93a 100644 --- a/voidcrew/modules/trade/shop.dm +++ b/voidcrew/modules/trade/shop.dm @@ -10,6 +10,9 @@ * - CORE: the sku_types list, stocked every round. * - ROTATING: a few picks rolled from rotating_pool each round, limited supply. * - RARE: 1-2 showcase picks rolled from rare_pool, single unit each. + * - Weighted rotations (/datum/shop_rotation): small dedicated shelves with a + * weighted pool of their own. Every sold-out slot swaps for a different pick + * on convoy restock, so scarce goods never refill in place. * One credit-priced SKU per round also goes on special (discount_pct). * * Vouchers are deliberately the only road to the best stock ("the currency @@ -68,6 +71,10 @@ var/list/chart_pool = list() /// How many chart picks land on the shelf per round var/chart_picks = 3 + /// /datum/shop_rotation typepaths: dedicated weighted shelves (see below) + var/list/rotations = list() + /// Live rotation instances, one per entry in `rotations` + var/list/datum/shop_rotation/live_rotations = list() /// Live SKU instances (hold the shared per-round stock) var/list/datum/shop_sku/skus = list() /// Buyback typepaths: what this trader buys from players (see shop_buyback.dm) @@ -106,6 +113,11 @@ // Each outpost deals its own chart shelf. Separate purchases reveal fresh sites. for(var/sku_type in deal_chart_picks()) add_sku(sku_type, SHELF_ROTATING) + for(var/rotation_type in rotations) + var/datum/shop_rotation/rotation = new rotation_type + live_rotations += rotation + for(var/sku_type in rotation.deal(rotation.slots)) + add_rotation_sku(rotation, sku_type) roll_special() for(var/buyback_type in buyback_types) buybacks += new buyback_type @@ -113,6 +125,7 @@ /datum/outpost_shop/Destroy() QDEL_LIST(skus) QDEL_LIST(buybacks) + QDEL_LIST(live_rotations) outpost = null trader_npc = null return ..() @@ -162,6 +175,42 @@ sku.stock = FAVOR_UNIQUE_CREW_LIMIT skus += sku +/** + * Puts a SKU dealt by `rotation` on the rotating shelf and tags it, so the + * convoy swaps it through the rotation rather than the ordinary rotating pool. + */ +/datum/outpost_shop/proc/add_rotation_sku(datum/shop_rotation/rotation, sku_type) + add_sku(sku_type, SHELF_ROTATING) + var/datum/shop_sku/sku = skus[length(skus)] + sku.rotation = rotation + return sku + +/** + * Every sold-out rotation slot is replaced with a different weighted pick from + * the same rotation. Nothing refills in place: the shelf only ever shows what + * the convoy happened to bring. + */ +/datum/outpost_shop/proc/restock_rotations() + for(var/datum/shop_rotation/rotation as anything in live_rotations) + var/list/sold_out = list() + var/list/on_shelf = list() + for(var/datum/shop_sku/sku as anything in skus) + if(sku.rotation != rotation) + continue + on_shelf += sku.type + if(sku.stock <= 0) + sold_out += sku + for(var/datum/shop_sku/gone as anything in sold_out) + skus -= gone + qdel(gone) + // The sold type and everything still on the shelf are held back, so + // a slot always turns over into something different + var/replacement = rotation.pick_one(on_shelf) + if(!replacement) + continue + on_shelf += replacement + add_rotation_sku(rotation, replacement) + /** * Puts one random credit-priced SKU on special for the round (15-30% off). */ @@ -173,6 +222,8 @@ // get_credit_price if(sku.shelf == SHELF_FAVOR) continue + if(sku.fixed_price) + continue if(sku.price_credits > 0 && !sku.discount_pct) eligible += sku if(!length(eligible)) @@ -200,7 +251,7 @@ // a sold tip for an unrelated good. Named tips replenish separately above. var/list/depleted = list() for(var/datum/shop_sku/sku as anything in skus) - if(sku.shelf == SHELF_ROTATING && !sku.is_chart && sku.stock <= 0) + if(sku.shelf == SHELF_ROTATING && !sku.is_chart && !sku.rotation && sku.stock <= 0) depleted += sku if(length(depleted)) var/datum/shop_sku/gone = pick(depleted) @@ -211,6 +262,9 @@ qdel(gone) add_sku(length(unstocked) ? pick(unstocked) : pick(rotating_pool), SHELF_ROTATING) + // Weighted rotations turn their sold-out slots over + restock_rotations() + // Yesterday's special is over; roll a new one for(var/datum/shop_sku/sku as anything in skus) sku.discount_pct = initial(sku.discount_pct) @@ -284,6 +338,9 @@ // contract's pay bundle, that would leak the back room past its gate if(sku.shelf == SHELF_FAVOR) continue + // Scarce stock (anomaly cores) is sold over the counter only + if(!sku.contract_reward) + continue var/worth = get_sku_value(sku) if(worth <= 0) continue @@ -422,6 +479,12 @@ var/icon_state_override /// Cached base64 icon for the UI, computed once per instance var/cached_icon + /// The weighted rotation that dealt this SKU, if any (see /datum/shop_rotation) + var/datum/shop_rotation/rotation + /// Ignores specials and crew favor discounts: the price on the tag is the price + var/fixed_price = FALSE + /// Whether outpost contracts may pay this out as part of a reward bundle + var/contract_reward = TRUE /datum/shop_sku/New() ..() @@ -435,6 +498,7 @@ /datum/shop_sku/Destroy() shop = null + rotation = null return ..() /** @@ -444,7 +508,7 @@ * Without a buyer (catalog/static contexts) only the authored special shows. */ /datum/shop_sku/proc/get_credit_price(mob/living/user) - if(price_credits <= 0) + if(price_credits <= 0 || fixed_price) return price_credits var/pct = discount_pct if(user && shop) @@ -675,5 +739,48 @@ return team.ship return null +/** + * # Shop rotation + * + * A small dedicated shelf with its own weighted pool, for stock that should be + * scarce and changing rather than always on hand. `slots` distinct picks go up + * when the shop opens, each with whatever stock its SKU rolls (keep those at + * 1 for one-off goods). On every convoy restock each sold-out slot swaps for a + * different weighted pick (see /datum/outpost_shop/proc/restock_rotations). + * + * Kept apart from rotating_pool so a shop's ordinary rotating shelf is never + * diluted by it. A shop lists rotation typepaths in its `rotations` var. + */ +/datum/shop_rotation + /// SKU typepath -> weight. Higher weight turns up more often. + var/list/pool = list() + /// How many picks sit on the shelf at once + var/slots = 2 + +/** + * Up to `count` distinct weighted picks from the pool. + */ +/datum/shop_rotation/proc/deal(count) + var/list/picked = list() + for(var/_ in 1 to count) + var/choice = pick_one(picked) + if(!choice) + break + picked += choice + return picked + +/** + * One weighted pick, skipping anything in `exclude`. Null when nothing is left. + */ +/datum/shop_rotation/proc/pick_one(list/exclude) + var/list/candidates = list() + for(var/sku_type in pool) + if(exclude && (sku_type in exclude)) + continue + candidates[sku_type] = max(1, pool[sku_type]) + if(!length(candidates)) + return null + return pick_weight(candidates) + // The rumor SKU and every other chart line now live in shop_catalog_charts.dm, // keeping this file to machinery as its header describes. diff --git a/voidcrew/modules/trade/shop_catalog_outfitter_vendors.dm b/voidcrew/modules/trade/shop_catalog_outfitter_vendors.dm index 9640fdcd4df..44d0d6dbedc 100644 --- a/voidcrew/modules/trade/shop_catalog_outfitter_vendors.dm +++ b/voidcrew/modules/trade/shop_catalog_outfitter_vendors.dm @@ -13,6 +13,12 @@ * - Boffin's tier-2 parts and cells offer immediate upgrades while a crew is * still assembling or researching its fabrication equipment. Cargo remains * cheaper in bulk, and a working laboratory rewards making parts aboard ship. + * - Boffin is the only store that sells raw anomaly cores (cargo no longer + * carries them) and anomaly charts. Both sit on small weighted rotations of + * two slots, one unit each. A sold slot turns over to a different type at + * the next convoy. Both take the normal favor discounts and specials. The + * 400 cr core buyback is far below any core's price, so buying to resell + * loses money. * - The buyback ledger only wants what a ship can't print: anomaly cores, * slime extracts, and raw exotics out of the ground. No circuit boards. * Anything a lathe spits out is a money loop waiting to happen. @@ -50,6 +56,7 @@ "Gadgetry", "Ship Retrofit", "Power & Optics", + "Anomalies", "Job Packs", ) sku_types = list( @@ -84,6 +91,10 @@ /datum/shop_sku/skunk/rare/deluxe_parts, /datum/shop_sku/skunk/rare/hyper_cell, ) + rotations = list( + /datum/shop_rotation/skunk_cores, + /datum/shop_rotation/skunk_anomaly_charts, + ) buyback_types = list( /datum/shop_buyback/skunk/anomaly_core, /datum/shop_buyback/skunk/slime_extract, @@ -259,6 +270,81 @@ item_path = /obj/item/stock_parts/power_store/cell/hyper price_credits = 1200 +// ===== ANOMALIES ===== +// Raw cores still need the refinery and a bomb. Rarer types turn up less often +// and cost more. The charts for the same types live in anomaly_charts.dm. + +/datum/shop_rotation/skunk_cores + slots = 2 + pool = list( + /datum/shop_sku/skunk/anomaly_core/flux = 6, + /datum/shop_sku/skunk/anomaly_core/grav = 6, + /datum/shop_sku/skunk/anomaly_core/hallucination = 6, + /datum/shop_sku/skunk/anomaly_core/pyro = 6, + /datum/shop_sku/skunk/anomaly_core/bioscrambler = 3, + /datum/shop_sku/skunk/anomaly_core/ectoplasm = 3, + /datum/shop_sku/skunk/anomaly_core/dimensional = 3, + /datum/shop_sku/skunk/anomaly_core/bluespace = 1, + /datum/shop_sku/skunk/anomaly_core/vortex = 1, + ) + +/datum/shop_rotation/skunk_anomaly_charts + slots = 2 + pool = list( + /datum/shop_sku/anomaly_chart/flux = 6, + /datum/shop_sku/anomaly_chart/grav = 6, + /datum/shop_sku/anomaly_chart/hallucination = 6, + /datum/shop_sku/anomaly_chart/pyro = 6, + /datum/shop_sku/anomaly_chart/bioscrambler = 3, + /datum/shop_sku/anomaly_chart/ectoplasm = 3, + /datum/shop_sku/anomaly_chart/dimensional = 3, + /datum/shop_sku/anomaly_chart/bluespace = 1, + /datum/shop_sku/anomaly_chart/vortex = 1, + ) + +/// Raw cores: normal favor discounts and specials apply; contracts never pay them out +/datum/shop_sku/skunk/anomaly_core + category = "Anomalies" + stock_min = 1 + stock_max = 1 + contract_reward = FALSE + +/datum/shop_sku/skunk/anomaly_core/flux + item_path = /obj/item/raw_anomaly_core/flux + price_credits = 25000 + +/datum/shop_sku/skunk/anomaly_core/grav + item_path = /obj/item/raw_anomaly_core/grav + price_credits = 25000 + +/datum/shop_sku/skunk/anomaly_core/hallucination + item_path = /obj/item/raw_anomaly_core/hallucination + price_credits = 25000 + +/datum/shop_sku/skunk/anomaly_core/pyro + item_path = /obj/item/raw_anomaly_core/pyro + price_credits = 25000 + +/datum/shop_sku/skunk/anomaly_core/bioscrambler + item_path = /obj/item/raw_anomaly_core/bioscrambler + price_credits = 30000 + +/datum/shop_sku/skunk/anomaly_core/ectoplasm + item_path = /obj/item/raw_anomaly_core/ectoplasm + price_credits = 30000 + +/datum/shop_sku/skunk/anomaly_core/dimensional + item_path = /obj/item/raw_anomaly_core/dimensional + price_credits = 30000 + +/datum/shop_sku/skunk/anomaly_core/bluespace + item_path = /obj/item/raw_anomaly_core/bluespace + price_credits = 35000 + +/datum/shop_sku/skunk/anomaly_core/vortex + item_path = /obj/item/raw_anomaly_core/vortex + price_credits = 35000 + // ===== BOFFIN'S SPECIMEN LEDGER (buybacks) ===== // Nothing a lathe can print. Planet exotics and things that glow wrong. diff --git a/wiki/content/research.md b/wiki/content/research.md index c2821893582..da7a80ef113 100644 --- a/wiki/content/research.md +++ b/wiki/content/research.md @@ -94,7 +94,7 @@ A better **micro-laser** cuts the power draw, which matters: a scanner on the ch Feed a **refined anomaly core** to the destructive analyzer and it pays **200 points**. Nine core types exist and each pays once per techweb, so the full set is 1,800. Load an item and the analyzer tells you what it is worth before you pull the trigger. -Getting there is about 240 points of bluespace research: Bluespace Theory, Applied Bluespace, then **Anomaly Research** for the refinery. Raw cores come from anomalies that turn up aboard your ship as a [dynamic event](dynamic-events.md), and from research-themed loot caches. +Getting there is about 240 points of bluespace research: Bluespace Theory, Applied Bluespace, then **Anomaly Research** for the refinery. Raw cores come from Boffin at Quartermain Depot (see [Trader Outposts](trader-outposts.md)) and from research-themed loot caches. Neutralizing an anomaly on a [planet](planets.md) or at an anomaly chart's site gives you a finished core directly. Cores are the only items that pay research points when deconstructed. diff --git a/wiki/content/trader-outposts.md b/wiki/content/trader-outposts.md index f151690cc0e..b8d5474f344 100644 --- a/wiki/content/trader-outposts.md +++ b/wiki/content/trader-outposts.md @@ -45,7 +45,7 @@ Each outpost's concourse has its own side vendors, each with their own shopkeep | Halcyon | The Potting Shed | Fern | Seeds, growing supplies, the botany starter pack | | Halcyon | Pike's Bait & Tackle | Pike | Rods, bait and tackle, beside an indoor pond | | Halcyon | The Chowder Pot | Roux | The diner. Hot meals in tiers, galley staples, buys home cooking | -| Quartermain | The Skunkworks | Boffin | Research and fabrication gear, robotics and xenobiology starter packs | +| Quartermain | The Skunkworks | Boffin | Research and fabrication gear, robotics and xenobiology starter packs, raw anomaly cores and anomaly charts | | Quartermain | The Fitting Bay | Wick | Civilian through advanced MODsuits | | The Undertow | The Dregs | Dram | The cantina | | The Undertow | Patch-Up Clinic | Sawbones | Medical supplies, the genetics starter pack | @@ -96,6 +96,18 @@ Sold ruin charts restock with supply convoys. Buying another gives you another f More on what is inside them is on [Ruins](ruins.md). +### Anomaly cores and charts + +Boffin at the Skunkworks is the only place that sells **raw anomaly cores**. Cargo does not carry them. He has two on the shelf at a time, one of each. When one sells, the next convoy brings a different type. Rare types turn up less often. Raw cores still need the refinery and a bomb. Standing discounts and specials apply to cores and charts as usual (the better of the two, never both). + +Boffin also sells **anomaly charts** the same way. A chart names one anomaly. It uploads to your helm sealed, like a ruin chart, and the reveal marks either a derelict or a planet in the named band. The anomaly only forms once **your own ship** docks there. Another crew that gets there first finds nothing. Neutralize it for its core. If the site vanishes before you arrive, the chart goes back on your helm sealed and you can reveal it again. The chart is lost if your ship is. + +| Anomalies | Raw core | Chart | Chart band | +|---|---|---|---| +| Flux, gravitational, hallucination, pyroclastic | 25000 cr | 12500 cr | Contested | +| Bioscrambler, ectoplasm, dimensional | 30000 cr | 15000 cr | Contested | +| Bluespace, vortex | 35000 cr | 17500 cr | Lawless | + ## Trader contracts The main trader's **Contracts** menu is a second, separate mission board. Four offers stay posted, and they pay in **goods off that trader's own shelves** rather than money, which makes them worth taking when your account is empty. From ca0b2b6c90a9b6d4c10ae7bed14c5f53529ec73b Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 25 Sep 2026 18:18:32 -0700 Subject: [PATCH 002/105] Keep the Event Horizon scope, shorten its cooldown and block emitters The rifle keeps its upstream scope and range again, with 20 seconds between shots instead of a minute. Whoever the beam hits takes enough burn damage to die without being gibbed. The rifle can no longer be mounted in an emitter or turret, which fired it on their own power and skipped the shot limit and cooldown. --- .../projectiles/guns/energy/beam_rifle.dm | 10 ++++++++-- .../edits/objects/items/event_horizon_rifle.dm | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/code/modules/projectiles/guns/energy/beam_rifle.dm b/code/modules/projectiles/guns/energy/beam_rifle.dm index 198e5bfa9df..e5e36337ae2 100644 --- a/code/modules/projectiles/guns/energy/beam_rifle.dm +++ b/code/modules/projectiles/guns/energy/beam_rifle.dm @@ -21,10 +21,16 @@ selfcharge = TRUE self_charge_amount = STANDARD_ENERGY_GUN_SELF_CHARGE_RATE * 10 -// VOIDCREW EDIT REMOVAL: scope component and "must be scoped" check. It fires on screen -// only; see voidcrew/edits/objects/items/event_horizon_rifle.dm. +/obj/item/gun/energy/event_horizon/Initialize(mapload) + . = ..() + AddComponent(/datum/component/scope, range_modifier = 4) /obj/item/gun/energy/event_horizon/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread) + + if(!HAS_TRAIT(user, TRAIT_USER_SCOPED)) + balloon_alert(user, "must be scoped!") + return + . = ..() message_admins("[ADMIN_LOOKUPFLW(user)] has fired an anti-existential beam at [ADMIN_VERBOSEJMP(user)].") diff --git a/voidcrew/edits/objects/items/event_horizon_rifle.dm b/voidcrew/edits/objects/items/event_horizon_rifle.dm index 6039a35271e..4f366f7d38a 100644 --- a/voidcrew/edits/objects/items/event_horizon_rifle.dm +++ b/voidcrew/edits/objects/items/event_horizon_rifle.dm @@ -1,6 +1,6 @@ // Event Horizon rifle rebalance. It is a rare loot find rather than a research print: -// three shots that never recharge, a minute between shots, on-screen range only, and a -// reality tear that eats the room but not the people in it. +// three shots that never recharge and 20 seconds between shots. Whoever it hits dies but is +// not gibbed, and the reality tear eats the room but only throws people around. /datum/techweb_node/unregulated_bluespace design_ids = list( @@ -10,8 +10,10 @@ /obj/item/gun/energy/event_horizon selfcharge = FALSE can_charge = FALSE + // Emitters and turrets would fire it on their own power, skipping the shot limit and cooldown. + gun_flags = TURRET_INCOMPATIBLE /// Time between shots. - var/shot_cooldown_time = 1 MINUTES + var/shot_cooldown_time = 20 SECONDS COOLDOWN_DECLARE(shot_cooldown) /obj/item/gun/energy/event_horizon/get_cell(atom/movable/interface, mob/user) @@ -33,8 +35,13 @@ /obj/item/ammo_casing/energy/event_horizon e_cost = LASER_SHOTS(3, STANDARD_CELL_CHARGE) -/obj/projectile/beam/event_horizon - range = 9 +/// Whoever the beam hits is burned to death, not gibbed, so the body stays behind. +/obj/projectile/beam/event_horizon/on_hit(atom/target, blocked = 0, pierce_hit) + . = ..() + if(. != BULLET_ACT_HIT || !isliving(target)) + return + var/mob/living/victim = target + victim.adjustFireLoss(200) /obj/reality_tear/temporary/start_disaster() . = ..() From 0832ef40387ee62e16dd29f59c394a931759b45d Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Wed, 30 Sep 2026 01:22:37 -0700 Subject: [PATCH 003/105] Move the anomaly trade test into the Voidcrew test folder for the modularization check --- code/modules/unit_tests/_unit_tests.dm | 2 +- tools/ci/modularization_exceptions.json | 6 ++++++ .../modules/unit_tests/voidcrew_anomaly_trade.dm | 0 3 files changed, 7 insertions(+), 1 deletion(-) rename {code => voidcrew}/modules/unit_tests/voidcrew_anomaly_trade.dm (100%) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index e606437f527..d5572ac51f9 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -333,7 +333,7 @@ #include "verify_config_tags.dm" #include "verify_emoji_names.dm" #include "voidcrew_ammo_box_materials.dm" -#include "voidcrew_anomaly_trade.dm" +#include "../../../voidcrew/modules/unit_tests/voidcrew_anomaly_trade.dm" // VOIDCREW EDIT ADDITION #include "voidcrew_assault_pod.dm" #include "voidcrew_autopilot_course.dm" #include "voidcrew_autotranslate_morph.dm" diff --git a/tools/ci/modularization_exceptions.json b/tools/ci/modularization_exceptions.json index 7b42968dab8..afdd41dcb4f 100644 --- a/tools/ci/modularization_exceptions.json +++ b/tools/ci/modularization_exceptions.json @@ -77,6 +77,12 @@ ], "reason": "Voidcrew-only file, not in /tg/station; it predates the modular folders, so all of it is fork code." }, + "code/modules/unit_tests/voidcrew_shop_catalog.dm": { + "rules": [ + "markers" + ], + "reason": "Voidcrew-only file, not in /tg/station; it predates the modular folders, so all of it is fork code." + }, "code/modules/unit_tests/voidcrew_survey_archive.dm": { "rules": [ "markers" diff --git a/code/modules/unit_tests/voidcrew_anomaly_trade.dm b/voidcrew/modules/unit_tests/voidcrew_anomaly_trade.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_anomaly_trade.dm rename to voidcrew/modules/unit_tests/voidcrew_anomaly_trade.dm From 59b49e273ea38d2b89c44ba1d27f08333d508d5c Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:05:43 -0700 Subject: [PATCH 004/105] Ruin suit stock, base-tier suits, named charts and schematic loot removal --- voidcrew/machinery/suit_storage_unit.dm | 77 +++++++- voidcrew/modules/loot/abandoned_crate.dm | 5 +- voidcrew/modules/loot/themes/plunder.dm | 4 - voidcrew/modules/loot/themes/research.dm | 2 - voidcrew/modules/loot/themes/syndicate.dm | 17 -- .../outpost_checkpoint_rebuild.dm | 24 +++ voidcrew/modules/trade/rumor_charts.dm | 183 +++++++++++++++--- .../unit_tests/voidcrew_checkpoints.dm | 59 ++++++ .../unit_tests/voidcrew_launch_access.dm | 34 ++-- voidcrew/modules/unit_tests/voidcrew_loot.dm | 180 +++++++++++++++++ 10 files changed, 519 insertions(+), 66 deletions(-) diff --git a/voidcrew/machinery/suit_storage_unit.dm b/voidcrew/machinery/suit_storage_unit.dm index ebf63ae4f0b..1849b5f09c7 100644 --- a/voidcrew/machinery/suit_storage_unit.dm +++ b/voidcrew/machinery/suit_storage_unit.dm @@ -1,3 +1,79 @@ +/// Uniform base-tier suit stock shared by machines and the loose ruin spawner. +GLOBAL_LIST_INIT(base_tier_modsuits, list( + /obj/item/mod/control/pre_equipped/standard, + /obj/item/mod/control/pre_equipped/civilian, + /obj/item/mod/control/pre_equipped/engineering, + /obj/item/mod/control/pre_equipped/atmospheric, + /obj/item/mod/control/pre_equipped/mining, + /obj/item/mod/control/pre_equipped/medical, +)) + +/obj/machinery/suit_storage_unit/base_tier + +/obj/machinery/suit_storage_unit/base_tier/Initialize(mapload) + mod_type = pick(GLOB.base_tier_modsuits) + return ..() + +/obj/effect/spawner/random/modsuit/base_tier + name = "base MODsuit spawner" + icon_state = "circuit" + +/obj/effect/spawner/random/modsuit/base_tier/Initialize(mapload) + loot = GLOB.base_tier_modsuits.Copy() + return ..() + +/obj/machinery/suit_storage_unit/ruin_zone + /// Pinned before parent initialization; moving the machine never changes its tier. + var/turf/stock_spawn_turf + /// A resolved or checkpoint-scrubbed unit can never create stock again. + var/stock_consumed = FALSE + /// Keep retrieval blocked throughout suit initialization, even if it yields. + var/stock_resolving = FALSE + +/obj/machinery/suit_storage_unit/ruin_zone/Initialize(mapload) + stock_spawn_turf = get_turf(src) + mod_type = null + suit_type = null + helmet_type = null + . = ..() + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/suit_storage_unit/ruin_zone/LateInitialize() + . = ..() + if(!stock_consumed) + new /datum/zone_resolver(stock_spawn_turf, CALLBACK(src, PROC_REF(stock_for_zone))) + +/obj/machinery/suit_storage_unit/ruin_zone/Destroy() + stock_spawn_turf = null + return ..() + +/obj/machinery/suit_storage_unit/ruin_zone/proc/stock_for_zone(zone_type) + if(QDELETED(src) || stock_consumed || stock_resolving) + return + stock_resolving = TRUE + stock_spawn_turf = null + switch(zone_type) + if(ZONE_RED) + mod_type = /obj/item/mod/control/pre_equipped/nuclear/unrestricted + if(ZONE_YELLOW) + mod_type = /obj/item/mod/control/pre_equipped/security + else + mod_type = pick(GLOB.base_tier_modsuits) + var/obj/item/mod/control/reward = new mod_type(src) + stock_resolving = FALSE + // A checkpoint scrub or deletion may have happened during initialization. + if(QDELETED(src) || stock_consumed) + qdel(reward) + return + stock_consumed = TRUE + mod = reward + update_appearance() + +/obj/machinery/suit_storage_unit/ruin_zone/check_interactable(mob/user) + if(!stock_consumed || stock_resolving) + return FALSE + return ..() + /obj/machinery/suit_storage_unit/ert mask_type = /obj/item/clothing/mask/gas/atmos/centcom storage_type = /obj/item/tank/jetpack/oxygen/captain @@ -23,4 +99,3 @@ /obj/machinery/suit_storage_unit/ert/chaplain mod_type = /obj/item/mod/control/pre_equipped/responsory/chaplain - diff --git a/voidcrew/modules/loot/abandoned_crate.dm b/voidcrew/modules/loot/abandoned_crate.dm index 8638ac4c9eb..409836a3707 100644 --- a/voidcrew/modules/loot/abandoned_crate.dm +++ b/voidcrew/modules/loot/abandoned_crate.dm @@ -97,9 +97,7 @@ GLOBAL_LIST_INIT(abandoned_crate_uncommon, list( /// The top of freight, and deliberately the top of nothing else. Gear a crew /// reorganizes an afternoon around, never gear it reorganizes the round -/// around: no uniques, no chrome, no five-figure cash. The blueprint is the -/// one long-odds reach into the weapons-bench pipeline, at the tier the themed -/// caches already put a mid blueprint on. +/// around: no uniques, no chrome, no five-figure cash. GLOBAL_LIST_INIT(abandoned_crate_prime, list( /obj/item/stack/sheet/plasteel/fifty = 7, /obj/item/ship_parts/combat = 7, @@ -117,7 +115,6 @@ GLOBAL_LIST_INIT(abandoned_crate_prime, list( /obj/item/storage/medkit/surgery = 4, /obj/item/stack/sheet/mineral/diamond/five = 4, /obj/item/clothing/glasses/night = 4, - /obj/item/blueprint/gun/wt550 = 3, // a loaded bluespace RPED: ten each of tier-3 parts, enough to re-fit // every machine on a hull in one pass. Tier 4 exists a line above this one // in part_replacer.dm if this plays too weak diff --git a/voidcrew/modules/loot/themes/plunder.dm b/voidcrew/modules/loot/themes/plunder.dm index 7dee57694e0..87f82453b19 100644 --- a/voidcrew/modules/loot/themes/plunder.dm +++ b/voidcrew/modules/loot/themes/plunder.dm @@ -16,8 +16,6 @@ guard_themes = list(/obj/effect/zone_mobs/pirate, /obj/effect/zone_mobs/pirate/boss) theme_skus = list( /datum/shop_sku/black_market/rotating/mateba, - /datum/shop_sku/black_market/bulldog_blueprint, - /datum/shop_sku/outfitter/carbine_blueprint, /datum/shop_sku/ripperdoc/gecko, /datum/shop_sku/ripperdoc/mantis, /datum/shop_sku/ripperdoc/ronin, @@ -47,7 +45,6 @@ /obj/item/clothing/head/costume/pirate/armored = 4, /obj/item/clothing/suit/costume/pirate/armored = 4, /obj/item/reagent_containers/cup/glass/bottle/rum/aged = 4, - /obj/item/blueprint/gun/laser_carbine = 3, /obj/item/ship_parts/combat = 7, // boarder's palms: your hands clamp shut on your gun when you go // down, and tables stop being furniture @@ -66,7 +63,6 @@ /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium = 4, /obj/item/clothing/suit/costume/pirate/captain/armored = 3, /obj/item/clothing/head/costume/pirate/captain = 3, - /obj/item/blueprint/gun/bulldog = 3, /obj/item/stack/spacecash/c10000 = 2, // the captain's cut, all of it voucher-grade chrome: the cased blade // pair, the arm gun nobody can disarm you of, and the rocket pod. diff --git a/voidcrew/modules/loot/themes/research.dm b/voidcrew/modules/loot/themes/research.dm index 0cc73c690c6..400a5f0f83d 100644 --- a/voidcrew/modules/loot/themes/research.dm +++ b/voidcrew/modules/loot/themes/research.dm @@ -14,7 +14,6 @@ name = "research" guard_themes = list(/obj/effect/zone_mobs/bug, /obj/effect/zone_mobs/bug/boss) theme_skus = list( - /datum/shop_sku/outfitter/carbine_blueprint, /datum/shop_sku/ripperdoc/doppler, /datum/shop_sku/ripperdoc/rigger, ) @@ -43,7 +42,6 @@ /obj/item/gun/energy/laser/retro = 6, /obj/item/gun/energy/recharge/ebow = 4, /obj/item/reagent_containers/cup/beaker/noreact = 4, - /obj/item/blueprint/gun/laser_carbine = 3, /obj/item/ship_parts/science = 7, // lab hardware worn instead of carried: a sonar transceiver socketed // into the bone behind the ear, reading movement through walls diff --git a/voidcrew/modules/loot/themes/syndicate.dm b/voidcrew/modules/loot/themes/syndicate.dm index e63595fc913..0d3b3d1b69f 100644 --- a/voidcrew/modules/loot/themes/syndicate.dm +++ b/voidcrew/modules/loot/themes/syndicate.dm @@ -6,11 +6,6 @@ // TODO: review/balance-pass all four tiers: first-draft weights and // contents, never playtested. Tune weights against the black-market voucher // prices in shop_catalog_black_market.dm. -// Weapon blueprints are seeded across both channels: the outfitter sells the -// c20r/wt550/carbine schematics (uncommon-tier), the black market sells the -// l6_saw/sniper/bulldog three (prime-tier), the same blueprints ride these -// cache tables at matching tiers. Craft them from the recipe anywhere, once -// you have the part and a firing pin (modules/weapons_bench/blueprint.dm). // Cyberware rides the same two channels: the parlor's smuggling cavity and // door spike sit at uncommon, and the three voucher-only pieces an operative // would carry (cloak weave, wire, reflex shunt) sit at the bottom of prime. @@ -22,16 +17,10 @@ theme_skus = list( /datum/shop_sku/black_market/emag, /datum/shop_sku/black_market/tactical_medkit, - /datum/shop_sku/black_market/saw_blueprint, - /datum/shop_sku/black_market/sniper_blueprint, - /datum/shop_sku/black_market/bulldog_blueprint, /datum/shop_sku/black_market/mystery_cache, /datum/shop_sku/black_market/mystery_cache_rare, /datum/shop_sku/black_market/rare/energy_sword, /datum/shop_sku/general/rotating/freight_crate, - /datum/shop_sku/outfitter/smg_blueprint, - /datum/shop_sku/outfitter/wt550_blueprint, - /datum/shop_sku/outfitter/carbine_blueprint, /datum/shop_sku/ripperdoc/cargo_cavity, /datum/shop_sku/ripperdoc/icepick, /datum/shop_sku/ripperdoc/slipwire, @@ -58,9 +47,6 @@ /obj/item/card/id/advanced/chameleon = 4, /obj/item/clothing/shoes/chameleon/noslip = 4, /obj/item/clothing/glasses/thermal/syndi = 3, - /obj/item/blueprint/gun/c20r = 4, - /obj/item/blueprint/gun/wt550 = 3, - /obj/item/blueprint/gun/laser_carbine = 3, /obj/item/ship_parts/combat = 8, // courier chrome: a shielded rib compartment scanners read past, and // a wrist spike for door motors and turret IFF @@ -76,9 +62,6 @@ /obj/item/pen/sleepy = 4, /obj/item/grenade/syndieminibomb = 3, /obj/item/card/emag = 2, - /obj/item/blueprint/gun/l6_saw = 3, - /obj/item/blueprint/gun/sniper_rifle = 3, - /obj/item/blueprint/gun/bulldog = 3, // the deepest slice of the theme, previously reachable only through // a sealed cache: now the long tail of prime, open to any band /obj/item/gun/ballistic/automatic/l6_saw/unrestricted = 3, diff --git a/voidcrew/modules/player_outposts/outpost_checkpoint_rebuild.dm b/voidcrew/modules/player_outposts/outpost_checkpoint_rebuild.dm index 8fc65d60759..8785d888197 100644 --- a/voidcrew/modules/player_outposts/outpost_checkpoint_rebuild.dm +++ b/voidcrew/modules/player_outposts/outpost_checkpoint_rebuild.dm @@ -94,6 +94,24 @@ GLOBAL_LIST_INIT(outpost_checkpoint_restocked, typecacheof(list( for(var/datum/gas_mixture/mix as anything in stored) mix?.gases.Cut() // Stock kept outside contents or in counters rather than as items. + if(istype(object, /obj/structure/closet)) + var/obj/structure/closet/closet = object + closet.contents_initialized = TRUE + if(istype(object, /obj/structure/closet/crate/secure/loot)) + var/obj/structure/closet/crate/secure/loot/freight = object + freight.spawned_loot = TRUE + if(istype(object, /obj/machinery/suit_storage_unit)) + var/obj/machinery/suit_storage_unit/unit = object + unit.suit = null + unit.helmet = null + unit.mask = null + unit.mod = null + unit.storage = null + if(istype(unit, /obj/machinery/suit_storage_unit/ruin_zone)) + var/obj/machinery/suit_storage_unit/ruin_zone/ruin_unit = unit + ruin_unit.stock_consumed = TRUE + ruin_unit.stock_spawn_turf = null + unit.update_appearance() if(istype(object, /obj/structure/closet/crate/critter)) var/obj/structure/closet/crate/critter/crate = object QDEL_NULL(crate.tank) @@ -122,3 +140,9 @@ GLOBAL_LIST_INIT(outpost_checkpoint_restocked, typecacheof(list( if(istype(object, /obj/machinery/atmospherics/components/unary/shuttle/heater)) var/obj/machinery/atmospherics/components/unary/shuttle/heater/heater = object heater.fuel_tank = null + +/// Mapped suit rewards are fittings only when rebuilt, even if unbolted at save time. +/obj/machinery/suit_storage_unit/checkpoint_type() + if(!..()) + return null + return /obj/machinery/suit_storage_unit diff --git a/voidcrew/modules/trade/rumor_charts.dm b/voidcrew/modules/trade/rumor_charts.dm index c1423495962..6063b6d6a62 100644 --- a/voidcrew/modules/trade/rumor_charts.dm +++ b/voidcrew/modules/trade/rumor_charts.dm @@ -7,12 +7,87 @@ * button then spawns the ruin at an uncharted square in the chart's zone band, * marks it on the helm readout and paints the overmap signal gold. * - * Each purchased chart reveals one fresh encounter, with normal ruin cleanup. + * Each template has one site per round, with normal ruin cleanup. Later charts + * lead to that same site; once it retires, no chart can create another vault. * The generic coordinate-tip rumor (/datum/shop_sku/rumor) is a separate, much * cheaper thing and every outpost sells it. Both live in shop_catalog_charts.dm; * this file is the reveal machinery. */ +#define COMSIG_RUIN_CHART_SITE_RETIRED "ruin_chart_site_retired" + +/// Round-wide template registry. Entries survive ships and site cleanup as tombstones. +GLOBAL_LIST_EMPTY(ruin_chart_sites) + +/proc/get_ruin_chart_site(template_path) + var/datum/ruin_chart_site/entry = GLOB.ruin_chart_sites[template_path] + if(!entry) + entry = new(template_path) + GLOB.ruin_chart_sites[template_path] = entry + return entry + +/datum/ruin_chart_site + var/template_path + var/datum/weakref/site_ref + var/claimed = FALSE + var/retired = FALSE + +/datum/ruin_chart_site/New(template_path) + src.template_path = template_path + +/datum/ruin_chart_site/Destroy() + var/obj/structure/overmap/space_ruin/site = site_ref?.resolve() + if(site) + UnregisterSignal(site, COMSIG_QDELETING) + site_ref = null + if(GLOB.ruin_chart_sites[template_path] == src) + GLOB.ruin_chart_sites -= template_path + return ..() + +/// Claim before creation can yield. A competing reveal stays sealed and can retry. +/datum/ruin_chart_site/proc/get_or_create(spawn_zone) + if(retired || claimed) + return null + var/obj/structure/overmap/space_ruin/site = site_ref?.resolve() + if(site) + return site + claimed = TRUE + site = create_site(spawn_zone) + claimed = FALSE + if(QDELETED(site)) + return null + site_ref = WEAKREF(site) + RegisterSignal(site, COMSIG_QDELETING, PROC_REF(on_site_retired)) + return site + +/datum/ruin_chart_site/proc/create_site(spawn_zone) + // SSmapping's instance is the canonical, size-preloaded template. + var/datum/map_template/ruin/space/template + for(var/template_name in SSmapping.space_ruins_templates) + var/datum/map_template/ruin/space/candidate = SSmapping.space_ruins_templates[template_name] + if(candidate.type == template_path) + template = candidate + break + if(!template) + stack_trace("Rumor chart points at unregistered ruin template [template_path]") + return null + var/turf/spawn_turf = SSovermap.get_unused_overmap_square_in_zone_band(spawn_zone) + if(!spawn_turf) + return null + var/obj/structure/overmap/space_ruin/site = new(spawn_turf) + if(QDELETED(site)) + return null + site.set_ruin_template(template) + site.mark_rare() + return site + +/datum/ruin_chart_site/proc/on_site_retired(datum/source) + SIGNAL_HANDLER + UnregisterSignal(source, COMSIG_QDELETING) + site_ref = null + retired = TRUE + SEND_SIGNAL(src, COMSIG_RUIN_CHART_SITE_RETIRED) + /** * # Sealed rumor * @@ -36,39 +111,80 @@ /// Charts with work left after the reveal (anomaly charts wait for the crew to /// arrive) manage their own lifetime instead of being deleted on reveal. var/keep_after_reveal = FALSE + /// Exact payment and original recipients, used only while a named chart is sealed. + var/paid_credits = 0 + var/paid_vouchers = 0 + var/datum/weakref/payment_account_ref + var/datum/weakref/purchaser_ref + var/datum/weakref/purchaser_mind_ref + var/datum/weakref/pending_ship_ref + var/datum/ruin_chart_site/registered_site + +/datum/rumor_chart/Destroy() + if(registered_site) + UnregisterSignal(registered_site, COMSIG_RUIN_CHART_SITE_RETIRED) + registered_site = null + var/obj/structure/overmap/ship/ship = pending_ship_ref?.resolve() + ship?.pending_rumors.Remove(src) + payment_account_ref = null + purchaser_ref = null + purchaser_mind_ref = null + pending_ship_ref = null + return ..() + +/// Subscribe before the first reveal, so outstanding paid copies are refunded. +/datum/rumor_chart/proc/watch_registered_site(obj/structure/overmap/ship/ship) + pending_ship_ref = WEAKREF(ship) + if(!ruin_template_path || registered_site) + return + registered_site = get_ruin_chart_site(ruin_template_path) + RegisterSignal(registered_site, COMSIG_RUIN_CHART_SITE_RETIRED, PROC_REF(refund_retired_site)) + if(registered_site.retired) + refund_retired_site() + +/datum/rumor_chart/proc/refund_retired_site(datum/source) + SIGNAL_HANDLER + if(revealed || QDELETED(src)) + return + // Consume the refund before creating physical currency or notifying anyone. + var/credits = paid_credits + var/vouchers = paid_vouchers + paid_credits = 0 + paid_vouchers = 0 + var/datum/bank_account/account = payment_account_ref?.resolve() + if(credits && account) + account.adjust_money(credits, "Retired rumor: [name]") + var/datum/mind/purchaser_mind = purchaser_mind_ref?.resolve() + var/mob/living/purchaser = purchaser_mind?.current || purchaser_ref?.resolve() + var/obj/structure/overmap/ship/ship = pending_ship_ref?.resolve() + var/atom/refund_location = purchaser ? purchaser.drop_location() : get_turf(ship?.shuttle) + if(vouchers && refund_location) + var/obj/item/stack/trade_voucher/refund = new(refund_location, vouchers) + purchaser?.put_in_hands(refund) + if(purchaser) + to_chat(purchaser, span_notice("The signal has gone dark. Your payment was returned.")) + qdel(src) /** - * Spawns the chart's ruin at an unused square in the chart's zone band and - * charts it on the ship's helm. Returns the new overmap ruin, or null if no - * clear square could be found (the rumor stays sealed so it can be retried). + * Charts the template's round-wide site, creating it only on the first reveal. + * Failed placement or a competing claim leaves the chart sealed for a retry. */ /datum/rumor_chart/proc/reveal(obj/structure/overmap/ship/ship) if(QDELETED(ship) || !ruin_template_path || revealed) return null - // SSmapping's instance is the canonical, size-preloaded template - var/datum/map_template/ruin/space/template - for(var/template_name in SSmapping.space_ruins_templates) - var/datum/map_template/ruin/space/candidate = SSmapping.space_ruins_templates[template_name] - if(candidate.type == ruin_template_path) - template = candidate - break - if(!template) - stack_trace("Rumor chart [name] points at unregistered ruin template [ruin_template_path]") + var/datum/ruin_chart_site/entry = get_ruin_chart_site(ruin_template_path) + if(entry.retired) + refund_retired_site() return null - - var/turf/spawn_turf = SSovermap.get_unused_overmap_square_in_zone_band(spawn_zone) - if(!spawn_turf) + var/obj/structure/overmap/space_ruin/ruin = entry.get_or_create(spawn_zone) + if(QDELETED(ruin) || QDELETED(src) || QDELETED(ship)) return null - - var/obj/structure/overmap/space_ruin/ruin = new(spawn_turf) - ruin.set_ruin_template(template) - ruin.mark_rare() revealed = TRUE var/list/coords = ruin.get_relative_overmap_coords() ship.add_waypoint("rumor_[REF(ruin)]", name, coords[1], coords[2], "Rumors", ruin) - log_mapping("Rumor chart revealed: spawned rare ruin '[template.name]' at ([coords[1]], [coords[2]]) for [ship]") + log_mapping("Rumor chart revealed: charted rare ruin '[ruin.ruin_template.name]' at ([coords[1]], [coords[2]]) for [ship]") return ruin /obj/structure/overmap/ship @@ -80,7 +196,9 @@ */ /obj/structure/overmap/ship/proc/add_pending_rumor(datum/rumor_chart/chart) pending_rumors += chart - ship_notify("Encrypted rumor data received: \"[chart.name]\". Reveal it from the helm console when ready.", "HELM", SHIP_NOTIFY_NOTICE, 'voidcrew/sound/notify.ogg', 50) + chart.watch_registered_site(src) + if(!QDELETED(chart)) + ship_notify("Encrypted rumor data received: \"[chart.name]\".", "HELM", SHIP_NOTIFY_NOTICE, 'voidcrew/sound/notify.ogg', 50) /** * Reveals a pending rumor: spawns or picks its site, charts the waypoint and @@ -127,8 +245,8 @@ * # Rumor chart SKU * * The storefront line for one specific rare ruin. No goods change hands: on - * purchase the sealed rumor lands straight on the buyer's ship. Each purchase - * reveals a fresh instance, even if this crew or another already visited one. + * purchase the sealed rumor lands straight on the buyer's ship. All purchases + * of a template chart the same site, until that site retires for the round. */ /datum/shop_sku/ruin_chart category = "Intel & Charts" @@ -150,13 +268,19 @@ . = ..() if(.) return + var/datum/ruin_chart_site/entry = GLOB.ruin_chart_sites[ruin_template_path] + if(entry?.retired) + return "That signal has gone dark." var/obj/structure/overmap/ship/ship = get_crew_ship(user) if(!ship) - return "No crew registration, you need a ship to upload the rumor to." + return "No crew registration." /datum/shop_sku/ruin_chart/try_purchase(mob/living/user, mob/living/basic/outpost_trader/vendor) if(stock <= 0) return FALSE + var/datum/ruin_chart_site/entry = GLOB.ruin_chart_sites[ruin_template_path] + if(entry?.retired) + return FALSE var/obj/structure/overmap/ship/ship = get_crew_ship(user) if(!ship) return FALSE @@ -182,8 +306,15 @@ chart.desc = rumor_desc || desc chart.ruin_template_path = ruin_template_path chart.spawn_zone = spawn_zone + chart.paid_credits = credit_price + chart.paid_vouchers = price_vouchers + chart.payment_account_ref = WEAKREF(account) + chart.purchaser_ref = WEAKREF(user) + chart.purchaser_mind_ref = WEAKREF(user.mind) ship.add_pending_rumor(chart) - to_chat(user, span_notice("The rumor data is encrypted and beamed to [ship]'s helm console. Reveal it when your crew is ready to move.")) + to_chat(user, span_notice("Encrypted rumor data received by [ship].")) metric_shop_purchase(src, user, credit_price, price_vouchers) return TRUE + +#undef COMSIG_RUIN_CHART_SITE_RETIRED diff --git a/voidcrew/modules/unit_tests/voidcrew_checkpoints.dm b/voidcrew/modules/unit_tests/voidcrew_checkpoints.dm index 28af34ce87c..e9345ea6265 100644 --- a/voidcrew/modules/unit_tests/voidcrew_checkpoints.dm +++ b/voidcrew/modules/unit_tests/voidcrew_checkpoints.dm @@ -35,6 +35,65 @@ var/obj/machinery/computer/ship_checkpoint/terminal var/turf/terminal_turf +/// Only clear_stock is under test; no bay, checkpoint or reconstruction job is needed. +/datum/checkpoint_construction/stock_test/New() + state = "complete" // CHECKPOINT_BUILD_COMPLETE, defined after the test includes. + +/obj/docking_port/mobile/voidcrew/stock_test/return_turfs() + return list(get_turf(src)) + +/datum/unit_test/voidcrew_checkpoint_lazy_stock + var/obj/docking_port/mobile/voidcrew/stock_test/source_port + +/datum/unit_test/voidcrew_checkpoint_lazy_stock/Destroy() + if(source_port) + qdel(source_port, force = TRUE) + source_port = null + return ..() + +/datum/unit_test/voidcrew_checkpoint_lazy_stock/Run() + source_port = new(run_loc_floor_bottom_left) + source_port.shuttle_areas = list() + source_port.shuttle_areas[get_area(run_loc_floor_bottom_left)] = TRUE + var/datum/checkpoint_construction/stock_test/job = allocate(/datum/checkpoint_construction/stock_test) + var/obj/structure/closet/crate/zone_loot/research/cache = allocate(/obj/structure/closet/crate/zone_loot/research) + var/obj/structure/closet/crate/secure/loot/freight = allocate(/obj/structure/closet/crate/secure/loot) + var/obj/machinery/suit_storage_unit/ruin_zone/unit = allocate(/obj/machinery/suit_storage_unit/ruin_zone) + TEST_ASSERT(!unit.stock_consumed && !unit.mod, "Test unit did not start with a deferred resolver") + var/obj/machinery/suit_storage_unit/base_tier/base = allocate(/obj/machinery/suit_storage_unit/base_tier) + TEST_ASSERT_NOTNULL(base.mod, "Base fixture has no initial stock to scrub") + for(var/obj/machinery/suit_storage_unit/machine as anything in list(base, unit)) + machine.anchored = FALSE + TEST_ASSERT_EQUAL(machine.checkpoint_type(), /obj/machinery/suit_storage_unit, "Unbolted suit reward retained its stocked rebuild type") + var/rebuilt_type = machine.checkpoint_type() + var/obj/machinery/suit_storage_unit/rebuilt = allocate(rebuilt_type, run_loc_floor_top_right) + TEST_ASSERT_NULL(rebuilt.mod, "Rebuilt suit unit stocked a reward") + job.clear_stock(source_port) + TEST_ASSERT(cache.contents_initialized && freight.contents_initialized && freight.spawned_loot, "Scrubbed containers retain a lazy stock path") + TEST_ASSERT(unit.stock_consumed && isnull(unit.stock_spawn_turf), "Scrubbed unit retained its deferred stock claim") + // Reopening takes the real closet path; a solved freight lock also checks spawned_loot. + for(var/obj/structure/closet/container as anything in list(cache, freight)) + container.open(force = TRUE, special_effects = FALSE) + container.dump_contents() + TEST_ASSERT_NULL(locate(/obj/item/mod/control) in base.contents, "Scrubbing retained the base suit") + TEST_ASSERT_NULL(base.mod, "Scrubbing retained a reference to the deleted suit") + var/turf/red = SSovermap.get_unused_overmap_square_in_zone_band(3) // ZONE_RED + TEST_ASSERT_NOTNULL(red, "No red square for the deferred stock test") + unit.forceMove(red) + // ZONE_RESOLVE_ATTEMPTS * ZONE_RESOLVE_RETRY_DELAY, plus a tick of margin. + sleep(61 SECONDS) + TEST_ASSERT_NULL(unit.mod, "Deferred resolver replenished the rebuilt machine") + unit.stock_for_zone(3) + TEST_ASSERT_NULL(unit.mod, "A repeated resolver callback replenished the rebuilt machine") + for(var/obj/structure/closet/container as anything in list(cache, freight)) + container.dump_contents() + for(var/obj/item/item in run_loc_floor_bottom_left.get_all_contents()) + if(ismachinery(item.loc)) + var/obj/machinery/machine = item.loc + if((item in machine.component_parts) || item == machine.circuit) + continue + TEST_FAIL("Reopened checkpoint fixture returned stock: [item.type]") + /// Recovery must also work after the hull and the captain's original body are gone. /datum/unit_test/voidcrew_checkpoints/lost destroy_original = TRUE diff --git a/voidcrew/modules/unit_tests/voidcrew_launch_access.dm b/voidcrew/modules/unit_tests/voidcrew_launch_access.dm index 5529f68467c..549eeef43a1 100644 --- a/voidcrew/modules/unit_tests/voidcrew_launch_access.dm +++ b/voidcrew/modules/unit_tests/voidcrew_launch_access.dm @@ -220,9 +220,10 @@ SSdynamic_events.enabled = FALSE TEST_ASSERT_NULL(SSdynamic_events.get_due_colosseum(1), "Deadline bypassed the subsystem's disabled switch") -/// Exercise actual reveal and map-slot teardown without loading a ruin template interior. +/// Exercise shared named-site reveals and teardown without loading a ruin interior. /datum/unit_test/voidcrew_launch_fresh_charts var/list/spawned_sites = list() + var/list/saved_registry /datum/unit_test/voidcrew_launch_fresh_charts/Destroy() for(var/obj/structure/overmap/space_ruin/site as anything in spawned_sites) @@ -231,9 +232,15 @@ // Space-ruin Destroy releases any footprint still owned by the signal. site.remove_docks() qdel(site) + if(saved_registry) + for(var/template_path in GLOB.ruin_chart_sites.Copy()) + qdel(GLOB.ruin_chart_sites[template_path]) + GLOB.ruin_chart_sites = saved_registry return ..() /datum/unit_test/voidcrew_launch_fresh_charts/Run() + saved_registry = GLOB.ruin_chart_sites + GLOB.ruin_chart_sites = list() var/chart_type = /datum/map_template/ruin/space/rare/hospice var/obj/structure/overmap/ship/first_ship = allocate(/obj/structure/overmap/ship) var/obj/structure/overmap/ship/second_ship = allocate(/obj/structure/overmap/ship) @@ -259,14 +266,11 @@ second_chart.spawn_zone = 1 var/obj/structure/overmap/space_ruin/second = second_chart.reveal(second_ship) TEST_ASSERT_NOTNULL(second, "Another chart could not reveal the same template again") - spawned_sites += second second.mission_exclusive = TRUE - TEST_ASSERT(first != second, "Second buyer received the first crew's encounter") - TEST_ASSERT(get_turf(first) != get_turf(second), "Fresh encounter overlapped the first ruin's occupied coordinates") - TEST_ASSERT(!second.loaded && !second.visited, "Second chart reused a visited interior") - TEST_ASSERT_EQUAL(length(GLOB.space_ruin_signals), signals_before + 2, "Second chart did not create its own signal") + TEST_ASSERT_EQUAL(first, second, "Second buyer received another vault for the same template") + TEST_ASSERT_EQUAL(length(GLOB.space_ruin_signals), signals_before + 1, "Second chart created another signal") var/datum/ship_waypoint/second_waypoint = second_ship.get_waypoint("rumor_[REF(second)]") - TEST_ASSERT_EQUAL(second_waypoint?.tracked_target?.resolve(), second, "Second crew was sent to the old encounter") + TEST_ASSERT_EQUAL(second_waypoint?.tracked_target?.resolve(), second, "Second crew did not chart the shared encounter") // Give the actual first signal a real empty interior allocation and docks. // No .dmm is loaded, but release_interior and slot/dock deletion run unchanged. @@ -296,20 +300,26 @@ TEST_ASSERT(QDELETED(footprint), "Chart cleanup did not release its map footprint") TEST_ASSERT_EQUAL(zone.used_slot_count(), slots_before - 1, "Chart cleanup kept its map slot allocated") TEST_ASSERT(QDELETED(primary_dock) && QDELETED(secondary_dock), "Chart cleanup left its docking ports behind") - TEST_ASSERT(!QDELETED(second), "Cleaning the first encounter deleted another buyer's fresh ruin") - TEST_ASSERT_EQUAL(length(GLOB.space_ruin_signals), signals_before + 1, "Chart cleanup automatically spawned an unpaid replacement") + TEST_ASSERT_EQUAL(length(GLOB.space_ruin_signals), signals_before, "Chart cleanup automatically spawned an unpaid replacement") + var/datum/ruin_chart_site/retired = GLOB.ruin_chart_sites[chart_type] + TEST_ASSERT(retired.retired, "Cleanup discarded the template's consumed tombstone") + var/datum/rumor_chart/retired_chart = allocate(/datum/rumor_chart) + retired_chart.ruin_template_path = chart_type + TEST_ASSERT_NULL(retired_chart.reveal(second_ship), "Retired template spawned another vault") - // A failed placement keeps the paid chart sealed; a retry creates another fresh site. + // A different, unconsumed template stays retryable after failed placement. var/datum/rumor_chart/retry_chart = allocate(/datum/rumor_chart) - retry_chart.ruin_template_path = chart_type + retry_chart.ruin_template_path = /datum/map_template/ruin/space/rare/liner retry_chart.spawn_zone = 99 // No real zone can match this value. TEST_ASSERT_NULL(first_ship.reveal_pending_rumor(retry_chart), "A foreign chart was accepted as this ship's pending purchase") first_ship.add_pending_rumor(retry_chart) TEST_ASSERT_NULL(first_ship.reveal_pending_rumor(retry_chart), "Impossible placement unexpectedly succeeded") TEST_ASSERT(!retry_chart.revealed && (retry_chart in first_ship.pending_rumors), "Failed reveal consumed its paid chart") + var/datum/ruin_chart_site/retry_entry = GLOB.ruin_chart_sites[retry_chart.ruin_template_path] + TEST_ASSERT(!retry_entry.claimed && !retry_entry.retired && isnull(retry_entry.site_ref), "Failed placement retained its claim or consumed the template") retry_chart.spawn_zone = 1 var/obj/structure/overmap/space_ruin/retried = first_ship.reveal_pending_rumor(retry_chart) TEST_ASSERT_NOTNULL(retried, "A valid retry could not generate a fresh encounter after cleanup") spawned_sites += retried - TEST_ASSERT(retried != second && !retried.visited && !retried.loaded, "Retry reused another crew's ruin state") + TEST_ASSERT(!retried.visited && !retried.loaded, "Retry inherited an explored interior") TEST_ASSERT(QDELETED(retry_chart) && !(retry_chart in first_ship.pending_rumors), "Successful reveal did not consume the sealed chart") diff --git a/voidcrew/modules/unit_tests/voidcrew_loot.dm b/voidcrew/modules/unit_tests/voidcrew_loot.dm index d1d055355b6..20ce575b8f8 100644 --- a/voidcrew/modules/unit_tests/voidcrew_loot.dm +++ b/voidcrew/modules/unit_tests/voidcrew_loot.dm @@ -44,6 +44,7 @@ TEST_FAIL("[theme_path] has an empty [table_name] table") continue for(var/entry in table) + TEST_ASSERT(!ispath(entry, /obj/item/blueprint/gun), "[theme_path].[table_name] still drops a gun schematic: [entry]") if(!ispath(entry, /atom/movable)) TEST_FAIL("[theme_path].[table_name] entry [entry] is not an /atom/movable path") var/weight = table[entry] @@ -60,6 +61,21 @@ for(var/sku in theme.theme_skus) if(!ispath(sku, /datum/shop_sku)) TEST_FAIL("[theme_path].theme_skus entry [sku] is not a shop SKU") + else + var/datum/shop_sku/sku_path = sku + TEST_ASSERT(!ispath(initial(sku_path.item_path), /obj/item/blueprint/gun), "[theme_path] still references a gun schematic SKU: [sku]") + + for(var/list/table as anything in list(GLOB.abandoned_crate_common, GLOB.abandoned_crate_uncommon, GLOB.abandoned_crate_prime)) + for(var/entry in table) + TEST_ASSERT(!ispath(entry, /obj/item/blueprint/gun), "Freight still drops a gun schematic: [entry]") + var/datum/loot_theme/syndicate/syndicate = GLOB.loot_themes[/datum/loot_theme/syndicate] + var/datum/loot_theme/plunder/plunder = GLOB.loot_themes[/datum/loot_theme/plunder] + var/datum/loot_theme/research/research = GLOB.loot_themes[/datum/loot_theme/research] + TEST_ASSERT(syndicate.loot_prime[/obj/item/gun/ballistic/automatic/c20r/unrestricted], "Schematic removal also removed the finished C-20r") + TEST_ASSERT(syndicate.loot_prime[/obj/item/gun/ballistic/automatic/l6_saw/unrestricted], "Schematic removal also removed the finished L6") + TEST_ASSERT(syndicate.loot_prime[/obj/item/gun/ballistic/rifle/sniper_rifle], "Schematic removal also removed the finished sniper rifle") + TEST_ASSERT(plunder.loot_prime[/obj/item/gun/ballistic/shotgun/bulldog/unrestricted], "Schematic removal also removed the finished Bulldog") + TEST_ASSERT(research.loot_prime[/obj/item/gun/energy/laser/carbine], "Schematic removal also removed the finished laser carbine") // every crate subtype must point at a registered theme for(var/obj/structure/closet/crate/zone_loot/crate_path as anything in subtypesof(/obj/structure/closet/crate/zone_loot)) @@ -242,3 +258,167 @@ for(var/area/area_path as anything in warded) if(!initial(area_path.repels_megafauna)) TEST_FAIL("[area_path] does not set repels_megafauna. A megafauna that reaches it can stay there for the rest of the round") + +/// Control when the real resolver starts, including after moving the machine. +/obj/machinery/suit_storage_unit/ruin_zone/stock_test/LateInitialize() + return + +/datum/unit_test/voidcrew_ruin_suit_stock/Run() + var/list/expected = list( + /obj/item/mod/control/pre_equipped/standard, + /obj/item/mod/control/pre_equipped/civilian, + /obj/item/mod/control/pre_equipped/engineering, + /obj/item/mod/control/pre_equipped/atmospheric, + /obj/item/mod/control/pre_equipped/mining, + /obj/item/mod/control/pre_equipped/medical, + ) + TEST_ASSERT_EQUAL(length(GLOB.base_tier_modsuits), 6, "Base-tier allowlist changed") + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human/consistent) + for(var/suit_path in expected) + TEST_ASSERT(suit_path in GLOB.base_tier_modsuits, "Base-tier allowlist lost [suit_path]") + TEST_ASSERT_NULL(GLOB.base_tier_modsuits[suit_path], "Base-tier selection must be uniform") + var/obj/item/mod/control/suit = allocate(suit_path) + TEST_ASSERT(suit.allowed(user), "Base reward [suit_path] is access-locked") + var/obj/machinery/suit_storage_unit/base_tier/base = allocate(/obj/machinery/suit_storage_unit/base_tier) + TEST_ASSERT(base.mod?.type in expected, "Base unit did not select its suit before parent initialization") + TEST_ASSERT_EQUAL(base.mod.loc, base, "Base unit did not stock its selected suit") + + var/before_loose = 0 + for(var/obj/item/mod/control/suit in run_loc_floor_top_right) + before_loose++ + new /obj/effect/spawner/random/modsuit/base_tier(run_loc_floor_top_right) + var/after_loose = 0 + for(var/obj/item/mod/control/suit in run_loc_floor_top_right) + after_loose++ + TEST_ASSERT(suit.type in expected, "Loose spawner selected a suit outside the allowlist") + TEST_ASSERT_EQUAL(after_loose, before_loose + 1, "Loose spawner did not pay exactly one suit") + TEST_ASSERT_EQUAL(length(GLOB.base_tier_modsuits), 6, "Loose spawner mutated the shared allowlist") + for(var/suit_path in expected) + TEST_ASSERT_NULL(GLOB.base_tier_modsuits[suit_path], "Loose spawner changed shared weights") + + // Literals 1/2/3 are ZONE_GREEN/YELLOW/RED, defined after unit-test includes. + for(var/zone in list(1, 2, 3)) + var/turf/spawn_turf = SSovermap.get_unused_overmap_square_in_zone_band(zone) + TEST_ASSERT_NOTNULL(spawn_turf, "No test square in zone [zone]") + var/obj/machinery/suit_storage_unit/ruin_zone/stock_test/unit = allocate(/obj/machinery/suit_storage_unit/ruin_zone/stock_test, spawn_turf) + TEST_ASSERT_NULL(unit.mod, "Ruin unit stocked before resolution") + unit.state_open = TRUE + TEST_ASSERT(!unit.check_interactable(user), "Unresolved unit permits retrieval") + TEST_ASSERT_EQUAL(unit.stock_spawn_turf, spawn_turf, "Unit did not pin its spawn turf") + unit.forceMove(run_loc_floor_bottom_left) + new /datum/zone_resolver(unit.stock_spawn_turf, CALLBACK(unit, TYPE_PROC_REF(/obj/machinery/suit_storage_unit/ruin_zone, stock_for_zone))) + TEST_ASSERT(unit.stock_consumed, "Resolver did not complete stock resolution") + if(zone == 1) + TEST_ASSERT(unit.mod?.type in expected, "Moved green unit did not retain base-tier stock") + else + var/expected_type = zone == 2 ? /obj/item/mod/control/pre_equipped/security : /obj/item/mod/control/pre_equipped/nuclear/unrestricted + TEST_ASSERT_EQUAL(unit.mod?.type, expected_type, "Moved unit changed suit tier") + TEST_ASSERT(unit.check_interactable(user) && unit.access_check(user), "Resolved unit blocks retrieval") + TEST_ASSERT(unit.mod.allowed(user), "Zone [zone] suit is access-locked") + var/obj/item/mod/control/reward = unit.mod + unit.stock_for_zone(3) + TEST_ASSERT_EQUAL(unit.mod, reward, "Repeated callback created another suit") + unit.dump_inventory_contents() + unit.stock_for_zone(3) + TEST_ASSERT_NULL(unit.mod, "Retrieving the suit allowed replenishment") + + var/obj/machinery/suit_storage_unit/ruin_zone/stock_test/fallback = allocate(/obj/machinery/suit_storage_unit/ruin_zone/stock_test) + fallback.stock_for_zone(null) + TEST_ASSERT(fallback.mod?.type in expected, "Unresolved zone did not fall back to base-tier stock") + +/// A real yielding creation window exercises the registry's claim. +/datum/ruin_chart_site/concurrency_test + var/creations = 0 + +/datum/ruin_chart_site/concurrency_test/create_site(spawn_zone) + creations++ + sleep(2) + return ..() + +/datum/unit_test/voidcrew_named_chart_registry + var/list/saved_registry + var/obj/structure/overmap/space_ruin/created_site + +/datum/unit_test/voidcrew_named_chart_registry/Destroy() + if(!QDELETED(created_site)) + qdel(created_site) + if(saved_registry) + for(var/template_path in GLOB.ruin_chart_sites.Copy()) + qdel(GLOB.ruin_chart_sites[template_path]) + GLOB.ruin_chart_sites = saved_registry + return ..() + +/datum/unit_test/voidcrew_named_chart_registry/Run() + saved_registry = GLOB.ruin_chart_sites + GLOB.ruin_chart_sites = list() + var/template_path = /datum/map_template/ruin/space/rare/hospice + var/datum/ruin_chart_site/concurrency_test/entry = new(template_path) + GLOB.ruin_chart_sites[template_path] = entry + var/obj/structure/overmap/ship/first_ship = allocate(/obj/structure/overmap/ship) + var/obj/structure/overmap/ship/second_ship = allocate(/obj/structure/overmap/ship) + var/datum/rumor_chart/first = allocate(/datum/rumor_chart) + var/datum/rumor_chart/second = allocate(/datum/rumor_chart) + first.ruin_template_path = template_path + second.ruin_template_path = template_path + first.spawn_zone = 1 // ZONE_GREEN + second.spawn_zone = 1 + first_ship.add_pending_rumor(first) + second_ship.add_pending_rumor(second) + INVOKE_ASYNC(first_ship, TYPE_PROC_REF(/obj/structure/overmap/ship, reveal_pending_rumor), first) + TEST_ASSERT(entry.claimed, "Creation yielded without claiming its template") + TEST_ASSERT_NULL(second_ship.reveal_pending_rumor(second), "Competing reveal created a second site") + TEST_ASSERT(!second.revealed && (second in second_ship.pending_rumors), "Competing reveal consumed its chart") + sleep(3) + created_site = entry.site_ref?.resolve() + TEST_ASSERT_NOTNULL(created_site, "Claimed reveal did not finish") + created_site.visited = TRUE + TEST_ASSERT_EQUAL(second_ship.reveal_pending_rumor(second), created_site, "Retry failed to chart the registered site") + TEST_ASSERT_EQUAL(entry.creations, 1, "Concurrent charts created more than one site") + qdel(first_ship) + TEST_ASSERT_EQUAL(get_ruin_chart_site(template_path), entry, "Ship deletion lost the round-wide registry") + + var/mob/living/carbon/human/buyer = allocate(/mob/living/carbon/human/consistent) + buyer.mind_initialize() + allocated += buyer.mind + var/datum/team/voidcrew/team = allocate(/datum/team/voidcrew) + team.ship = second_ship + buyer.mind.ship_teams = list(team) + var/datum/bank_account/account = allocate(/datum/bank_account, "Chart refund test", null, 1, FALSE) + account.account_balance = 20000 + var/obj/item/card/id/advanced/id = allocate(/obj/item/card/id/advanced) + qdel(id.registered_account) + id.registered_account = account + TEST_ASSERT(buyer.put_in_hands(id), "Buyer cannot hold their ID") + var/obj/item/stack/trade_voucher/vouchers = allocate(/obj/item/stack/trade_voucher, buyer, 10) + var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) + shop.add_sku(/datum/shop_sku/ruin_chart/biolab, "rotating") + var/datum/shop_sku/ruin_chart/sku = shop.skus[1] + sku.ruin_template_path = template_path + sku.stock = 2 + var/price = sku.get_credit_price(buyer) + var/voucher_price = sku.price_vouchers + TEST_ASSERT(sku.try_purchase(buyer, null), "Live registered site refused a purchase") + var/datum/rumor_chart/revealed_copy = second_ship.pending_rumors[1] + TEST_ASSERT_EQUAL(second_ship.reveal_pending_rumor(revealed_copy), created_site, "Paid chart did not reuse the visited site") + TEST_ASSERT(sku.try_purchase(buyer, null), "Pending refund purchase failed") + var/datum/rumor_chart/pending = second_ship.pending_rumors[1] + TEST_ASSERT_EQUAL(account.account_balance, 20000 - 2 * price, "Purchase charged the wrong credits") + TEST_ASSERT_EQUAL(vouchers.amount, 10 - 2 * voucher_price, "Purchase charged the wrong vouchers") + // Refund the actual bill, even after shelf prices change. + sku.price_credits *= 2 + sku.price_vouchers *= 2 + qdel(created_site) + TEST_ASSERT(entry.retired && isnull(entry.site_ref), "Deleted site did not leave a tombstone") + TEST_ASSERT(QDELETED(pending) && !length(second_ship.pending_rumors), "Retired site retained a paid pending chart") + TEST_ASSERT_EQUAL(account.account_balance, 20000 - price, "Retirement did not refund exactly the pending credit bill") + TEST_ASSERT_EQUAL(count_trade_vouchers(buyer), 10 - voucher_price, "Retirement did not refund exactly the pending voucher bill") + sku.stock = 1 + TEST_ASSERT(sku.get_denial_reason(buyer), "Retired site has no purchase denial") + TEST_ASSERT(!sku.try_purchase(buyer, null), "Retired site allowed another purchase") + TEST_ASSERT_EQUAL(sku.stock, 1, "Refused purchase consumed stock") + TEST_ASSERT_EQUAL(account.account_balance, 20000 - price, "Refused purchase charged credits") + TEST_ASSERT_EQUAL(count_trade_vouchers(buyer), 10 - voucher_price, "Refused purchase charged vouchers") + TEST_ASSERT_NULL(entry.get_or_create(1), "Retired template created another vault") + TEST_ASSERT_EQUAL(entry.creations, 1, "Tombstone allowed another creation") + buyer.mind.ship_teams = null + team.ship = null From cf556c292be2976e1b09037701a48542ac2fccc5 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:14:13 -0700 Subject: [PATCH 005/105] Remove gun manufacturing and cargo shortcuts --- tgstation.dme | 1 - voidcrew/_DEFINES/techweb_nodes.dm | 10 +- voidcrew/modules/admin/feature_testing.dm | 25 +-- .../modules/cargo/shipping/cargo_console.dm | 21 ++- voidcrew/modules/cargo/shipping/purchasing.dm | 2 + .../modules/research/designs/ammo_designs.dm | 5 +- .../modules/research/edits/_techweb_node.dm | 5 + .../trade/shop_catalog_black_market.dm | 31 ---- .../modules/trade/shop_catalog_outfitter.dm | 55 +------ .../modules/trade/shop_catalog_suit_vendor.dm | 10 -- .../unit_tests/voidcrew_blueprint_guns.dm | 150 +++++++++++------- .../modules/unit_tests/voidcrew_cargo_cart.dm | 105 ++++++++++++ .../unit_tests/voidcrew_launch_cargo.dm | 4 +- voidcrew/modules/unit_tests/voidcrew_loot.dm | 6 +- .../unit_tests/voidcrew_shop_catalog.dm | 9 ++ voidcrew/modules/weapons_bench/blueprint.dm | 98 +----------- .../modules/weapons_bench/guns/bulldog.dm | 59 +------ voidcrew/modules/weapons_bench/guns/c20r.dm | 54 +------ voidcrew/modules/weapons_bench/guns/l6_saw.dm | 69 +------- .../weapons_bench/guns/laser_carbine.dm | 51 ------ voidcrew/modules/weapons_bench/guns/sniper.dm | 55 +------ voidcrew/modules/weapons_bench/guns/wt550.dm | 56 +------ 22 files changed, 263 insertions(+), 618 deletions(-) delete mode 100644 voidcrew/modules/weapons_bench/guns/laser_carbine.dm diff --git a/tgstation.dme b/tgstation.dme index 0c9037cfd75..db2310e4d1e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7693,7 +7693,6 @@ #include "voidcrew\modules\weapons_bench\guns\bulldog.dm" #include "voidcrew\modules\weapons_bench\guns\c20r.dm" #include "voidcrew\modules\weapons_bench\guns\l6_saw.dm" -#include "voidcrew\modules\weapons_bench\guns\laser_carbine.dm" #include "voidcrew\modules\weapons_bench\guns\sniper.dm" #include "voidcrew\modules\weapons_bench\guns\wt550.dm" #include "voidcrew\modules\worldgen_logging\worldgen.dm" diff --git a/voidcrew/_DEFINES/techweb_nodes.dm b/voidcrew/_DEFINES/techweb_nodes.dm index f9bcf266077..ec7961253bc 100644 --- a/voidcrew/_DEFINES/techweb_nodes.dm +++ b/voidcrew/_DEFINES/techweb_nodes.dm @@ -20,18 +20,12 @@ #define TECHWEB_NODE_NANITE_SMART "nanite_smart" #define TECHWEB_NODE_NANITE_MESH "nanite_mesh" -// Weapon blueprint pipeline (per-gun part/ammo nodes) -#define TECHWEB_NODE_WEAPON_PART_L6_SAW "weapon_part_l6_saw" +// Per-gun ammunition nodes #define TECHWEB_NODE_WEAPON_AMMO_L6_SAW "weapon_ammo_l6_saw" -#define TECHWEB_NODE_WEAPON_PART_C20R "weapon_part_c20r" #define TECHWEB_NODE_WEAPON_AMMO_C20R "weapon_ammo_c20r" -#define TECHWEB_NODE_WEAPON_PART_SNIPER "weapon_part_sniper" #define TECHWEB_NODE_WEAPON_AMMO_SNIPER "weapon_ammo_sniper" -#define TECHWEB_NODE_WEAPON_PART_BULLDOG "weapon_part_bulldog" #define TECHWEB_NODE_WEAPON_AMMO_BULLDOG "weapon_ammo_bulldog" -#define TECHWEB_NODE_WEAPON_PART_WT550 "weapon_part_wt550" #define TECHWEB_NODE_WEAPON_AMMO_WT550 "weapon_ammo_wt550" -#define TECHWEB_NODE_WEAPON_PART_CARBINE "weapon_part_carbine" // Ship Combat #define TECHWEB_NODE_SHIP_COMBAT "ship_combat" @@ -54,7 +48,7 @@ #define TECHWEB_NODE_TRANSPORTER_TARGETING "transporter_targeting" #define TECHWEB_NODE_TRANSPORTER_BIOFILTER "transporter_biofilter" -// Generic ammunition (the per-gun blueprint ammo nodes live in _DEFINES above) +// Generic ammunition (per-gun ammunition nodes are defined above) #define TECHWEB_NODE_BALLISTIC_AMMO "ballistic_ammo" #define TECHWEB_NODE_AUTOMATIC_AMMO "automatic_ammo" #define TECHWEB_NODE_SPECIALIST_AMMO "specialist_ammo" diff --git a/voidcrew/modules/admin/feature_testing.dm b/voidcrew/modules/admin/feature_testing.dm index 240093a93b8..0091f9d5304 100644 --- a/voidcrew/modules/admin/feature_testing.dm +++ b/voidcrew/modules/admin/feature_testing.dm @@ -10,7 +10,7 @@ * spawn every rare-loot unique at once. * - Dynamic events: fire a chosen event at a chosen ship. * - Missions: hand a chosen mission type to a ship, force-resolve any active one. - * - Trade: grant vouchers, reveal rare rumor-chart ruins, spawn gun blueprints. + * - Trade: grant vouchers, reveal rare rumor-chart ruins. * - Overmap: spawn gas nebulas (ram scoop testing), surface a contested cache. * * Complements the per-module verbs that already exist: colosseum match control @@ -701,29 +701,6 @@ ADMIN_VERB(reveal_rare_ruin, R_ADMIN|R_DEBUG, "Trade: Reveal Rare Ruin", "Spawn log_admin("[key_name(user)] revealed rare ruin '[template.name]'.") BLACKBOX_LOG_ADMIN_VERB("Reveal Rare Ruin") -ADMIN_VERB(spawn_gun_blueprint, R_ADMIN|R_DEBUG, "Trade: Spawn Blueprint", "Spawn a specific weapons-bench gun blueprint at your feet.", ADMIN_CATEGORY_DEBUG) - var/turf/drop_turf = get_turf(user.mob) - if(!drop_turf) - to_chat(user, span_warning("You need a physical location to spawn a blueprint at.")) - return - var/list/choices = list() - for(var/obj/item/blueprint/blueprint_type as anything in subtypesof(/obj/item/blueprint)) - if(blueprint_type == /obj/item/blueprint/gun) - continue - choices[initial(blueprint_type.name)] = blueprint_type - var/choice = tgui_input_list(user, "Which blueprint?", "Spawn Blueprint", sort_list(choices)) - if(!choice) - return - var/blueprint_type = choices[choice] - var/obj/item/blueprint/blueprint = new blueprint_type(drop_turf) - var/mob/living/admin_mob = user.mob - if(isliving(admin_mob)) - admin_mob.put_in_hands(blueprint) - to_chat(user, span_notice("[blueprint] spawned.")) - message_admins("[key_name_admin(user)] spawned blueprint '[blueprint]'.") - log_admin("[key_name(user)] spawned blueprint '[blueprint]'.") - BLACKBOX_LOG_ADMIN_VERB("Spawn Gun Blueprint") - // ===== OVERMAP / GAS ECONOMY ===== ADMIN_VERB(spawn_gas_nebula, R_ADMIN|R_DEBUG, "Overmap: Spawn Nebula", "Spawn a gas nebula on the overmap, under a ship for instant ram scoop testing, or on an empty square.", ADMIN_CATEGORY_DEBUG) diff --git a/voidcrew/modules/cargo/shipping/cargo_console.dm b/voidcrew/modules/cargo/shipping/cargo_console.dm index a0ad90a3db6..7d82a005887 100644 --- a/voidcrew/modules/cargo/shipping/cargo_console.dm +++ b/voidcrew/modules/cargo/shipping/cargo_console.dm @@ -209,7 +209,7 @@ data["supplies"] = list() for(var/pack_id in SSshuttle.supply_packs) var/datum/supply_pack/pack = SSshuttle.supply_packs[pack_id] - if(!data["supplies"][pack.group]) + if(can_order_pack(pack) && !data["supplies"][pack.group]) data["supplies"][pack.group] = list( "name" = pack.group, "packs" = get_packs_data(pack.group), @@ -223,6 +223,19 @@ /obj/machinery/computer/voidcrew_cargo/proc/can_order_pack(datum/supply_pack/pack) if(!pack) return FALSE + var/static/list/forbidden_packs = typecacheof(list( + /datum/supply_pack/security, + /datum/supply_pack/goody/mars_single, + /datum/supply_pack/goody/ballistic_single, + /datum/supply_pack/goody/disabler_single, + /datum/supply_pack/goody/energy_single, + /datum/supply_pack/goody/laser_single, + /datum/supply_pack/goody/thermal_single, + /datum/supply_pack/goody/double_barrel, + /datum/supply_pack/goody/hell_single, + )) + if(is_type_in_typecache(pack, forbidden_packs)) + return FALSE if((pack.hidden && !(obj_flags & EMAGGED)) || (pack.special && !pack.special_enabled) || pack.drop_pod_only) return FALSE return !pack.contraband || contraband @@ -511,6 +524,12 @@ say("Error: No orders in cart.") return TRUE + // Outpost freight reserves payment during dispatch, before buy(). + for(var/datum/supply_order/order as anything in checkout_list) + if(!can_order_pack(order.pack)) + say("Order unavailable.") + return TRUE + // Check if we have enough credits for the order var/total_cost = get_cart_total() // A siphon on the account freezes ordering: shipping the balance out diff --git a/voidcrew/modules/cargo/shipping/purchasing.dm b/voidcrew/modules/cargo/shipping/purchasing.dm index 71696dc0e6f..2c2ed7c1ac3 100644 --- a/voidcrew/modules/cargo/shipping/purchasing.dm +++ b/voidcrew/modules/cargo/shipping/purchasing.dm @@ -31,6 +31,8 @@ // Iterate a copy: paid orders leave checkout_list inside the loop. for(var/datum/supply_order/spawning_order as anything in checkout_list.Copy()) + if(!can_order_pack(spawning_order.pack)) + continue // The cart quote is also the debit. Material stock is checked in full before // payment and consumed only after payment, never partially at a pooled price. if(!spawning_order.settle_ship_order(bank_account_holder.synced_bank_account)) diff --git a/voidcrew/modules/research/designs/ammo_designs.dm b/voidcrew/modules/research/designs/ammo_designs.dm index a837ee1e348..a1ffec1d99f 100644 --- a/voidcrew/modules/research/designs/ammo_designs.dm +++ b/voidcrew/modules/research/designs/ammo_designs.dm @@ -1,7 +1,7 @@ /** * Generic ballistic ammunition designs. * - * voidcrew/modules/weapons_bench/ already gives every blueprint gun (C-20r, Bulldog, + * voidcrew/modules/weapons_bench/ already gives each of these guns (C-20r, Bulldog, * WT-550, L6 SAW, anti-materiel rifle) its own ammo node and design. ammo_catalogue.dm * adds the remaining firearm calibers and specialty loads. What had no * manufacturing path at all was the plain stuff every crew is actually carrying: @@ -21,6 +21,9 @@ * 1 sheet, and the specialist shell adds the same plasma the .38 hotshot design uses. */ +/datum/design/pin_testing + build_type = NONE + // // Ballistic Ammunition - what a boarding party burns through. // diff --git a/voidcrew/modules/research/edits/_techweb_node.dm b/voidcrew/modules/research/edits/_techweb_node.dm index a4aa68ad6f5..c65d5532330 100644 --- a/voidcrew/modules/research/edits/_techweb_node.dm +++ b/voidcrew/modules/research/edits/_techweb_node.dm @@ -8,3 +8,8 @@ // stars = 0, // ) var/list/required_surveyed_objects + +/datum/techweb_node/riot_supression/New() + . = ..() + design_ids = design_ids.Copy() + design_ids -= "pin_testing" diff --git a/voidcrew/modules/trade/shop_catalog_black_market.dm b/voidcrew/modules/trade/shop_catalog_black_market.dm index 542719d825d..88c5b9e8cae 100644 --- a/voidcrew/modules/trade/shop_catalog_black_market.dm +++ b/voidcrew/modules/trade/shop_catalog_black_market.dm @@ -52,7 +52,6 @@ "Infiltration", "Combat Medical", "Intel & Charts", - "Blueprints", "Mystery Cargo", "Sundries", "Back Room", @@ -112,10 +111,6 @@ // Intel & Charts: named ruin tips are dealt onto the rotating shelf // from chart_pool below; the generic tip is the cheap standing rung. /datum/shop_sku/rumor, - // Blueprints - /datum/shop_sku/black_market/saw_blueprint, - /datum/shop_sku/black_market/sniper_blueprint, - /datum/shop_sku/black_market/bulldog_blueprint, // Mystery Cargo /datum/shop_sku/black_market/mystery_cache, /datum/shop_sku/black_market/mystery_cache_rare, @@ -230,7 +225,6 @@ "Stock's limited. The galaxy is not a reliable supplier.", "Raw telecrystal. The burning worlds are full of it, and the fools who mine it. Bring me both. Just kidding. Just the crystal.", "The mystery caches? Sealed when they got here. I make a point of not knowing.", - "Somebody asked what the imprinter does with the schematics. Confetti. Expensive confetti.", "Legion cores keep better than legionnaires. Cooler's under the counter.", "Quartermain will sell you a mining suit. I sell the ones with the Cybersun stamp still on the plating.", "The bare chassis are cheaper for a reason. You're buying a frame and a cell, not a loadout.", @@ -661,31 +655,6 @@ // Every chart SKU now lives in shop_catalog_charts.dm and reaches this shelf // through chart_pool above. The generic rumor rides the core shelf. -// ===== BLUEPRINTS ===== -// The only trader route to these guns; build them via their schematics. -// Reusable, so priced at the top of the ladder. - -/datum/shop_sku/black_market/saw_blueprint - category = "Blueprints" - item_path = /obj/item/blueprint/gun/l6_saw - price_vouchers = 5 - stock_min = 1 - stock_max = 1 - -/datum/shop_sku/black_market/sniper_blueprint - category = "Blueprints" - item_path = /obj/item/blueprint/gun/sniper_rifle - price_vouchers = 5 - stock_min = 1 - stock_max = 1 - -/datum/shop_sku/black_market/bulldog_blueprint - category = "Blueprints" - item_path = /obj/item/blueprint/gun/bulldog - price_vouchers = 5 - stock_min = 1 - stock_max = 1 - // ===== MYSTERY CARGO ===== // The gamble channel, sold over the counter: sealed caches rolling the zone // loot tables. The crate pins its band to the spawn turf, bought at the diff --git a/voidcrew/modules/trade/shop_catalog_outfitter.dm b/voidcrew/modules/trade/shop_catalog_outfitter.dm index 63bbe27e028..32d1e316a6b 100644 --- a/voidcrew/modules/trade/shop_catalog_outfitter.dm +++ b/voidcrew/modules/trade/shop_catalog_outfitter.dm @@ -46,7 +46,6 @@ "Fuel & Gas", "Colonial Registry", "Intel & Charts", - "Blueprints", "Barter Deals", "Back Room", ) @@ -82,7 +81,6 @@ // Security Gear /datum/shop_sku/outfitter/seclite, /datum/shop_sku/outfitter/flash, - /datum/shop_sku/outfitter/bola, /datum/shop_sku/outfitter/security_belt, /datum/shop_sku/outfitter/pepper_spray, /datum/shop_sku/outfitter/riot_shield, @@ -92,7 +90,6 @@ /datum/shop_sku/outfitter/advanced_medkit, /datum/shop_sku/outfitter/stimpack, /datum/shop_sku/outfitter/suture, - /datum/shop_sku/outfitter/health_hud, // Mess Tin /datum/shop_sku/outfitter/rations, /datum/shop_sku/outfitter/energy_bar, @@ -114,10 +111,6 @@ /datum/shop_sku/outpost_deed, // Intel & Charts: the dealt chart shelf adds to this from chart_pool /datum/shop_sku/rumor, - // Blueprints - /datum/shop_sku/outfitter/smg_blueprint, - /datum/shop_sku/outfitter/wt550_blueprint, - /datum/shop_sku/outfitter/carbine_blueprint, // Barter /datum/shop_sku/barter/plasteel_for_shield, ) @@ -224,7 +217,6 @@ "Firing pins. Everyone forgets the firing pins. Don't be everyone.", "Thruster boards are on the back wall. If your ship's limping, that's the fix, and it beats buying a new ship.", "Most crews can't build a turret. Most crews also can't afford mine. Work on the second problem.", - "The schematics I stock are legal. The fun ones are two zones that way.", ), TRADER_LINE_RESTOCK = list( "Convoy made it through. Shelves are full, for now.", @@ -322,12 +314,10 @@ stock_min = 10 stock_max = 20 -// Magazines for the two ballistics whose blueprints are on the shelf below. -// Print the gun once, buy the ammo forever. /datum/shop_sku/outfitter/smg_mag category = "Firearms & Ammo" name = "c-20r magazine" - desc = "A loaded .45 magazine for a C-20r. Sarge stocks these because the schematic's on her own shelf." + desc = "A loaded .45 magazine for a C-20r." item_path = /obj/item/ammo_box/magazine/smgm45 price_credits = 250 stock_min = 10 @@ -342,7 +332,6 @@ stock_min = 10 stock_max = 20 -// The quiet backbone of the blueprint economy: no pin, no gun /datum/shop_sku/outfitter/firing_pin category = "Firearms & Ammo" item_path = /obj/item/firing_pin @@ -451,11 +440,6 @@ item_path = /obj/item/assembly/flash/handheld price_credits = 750 -/datum/shop_sku/outfitter/bola - category = "Security Gear" - item_path = /obj/item/restraints/legcuffs/bola - price_credits = 600 - /datum/shop_sku/outfitter/security_belt category = "Security Gear" item_path = /obj/item/storage/belt/security/full @@ -513,17 +497,6 @@ stock_min = 10 stock_max = 20 -// Triage glasses. Reads live health off everyone in view, which is worth more -// in a boarding action than knowing who a station flagged as wanted. -/datum/shop_sku/outfitter/health_hud - category = "Combat Medical" - name = "medical HUD sunglasses" - desc = "Tinted health-scanner glasses. Everyone in view gets a status icon, so you can tell who's down from who's dead without walking over." - item_path = /obj/item/clothing/glasses/hud/health/sunglasses - price_credits = 1500 - stock_min = 1 - stock_max = 3 - // ===== MESS TIN ===== // Field chow. Nothing here is cooking. It's calories that survive a webbing // pouch, a decompression and the customer. Every outpost feeds its lane; @@ -650,32 +623,6 @@ stock_min = 10 stock_max = 20 -// ===== BLUEPRINTS ===== -// Yellow-tier guns, carried or imprinted, crafted anywhere. The charts and -// rumor tips that used to share this shelf now come off chart_pool. - -/datum/shop_sku/outfitter/smg_blueprint - category = "Blueprints" - item_path = /obj/item/blueprint/gun/c20r - price_vouchers = 3 - stock_min = 1 - stock_max = 1 - -/datum/shop_sku/outfitter/wt550_blueprint - category = "Blueprints" - item_path = /obj/item/blueprint/gun/wt550 - price_vouchers = 3 - stock_min = 1 - stock_max = 1 - -/datum/shop_sku/outfitter/carbine_blueprint - category = "Blueprints" - item_path = /obj/item/blueprint/gun/laser_carbine - price_vouchers = 2 - price_credits = 3000 - stock_min = 1 - stock_max = 1 - // ===== ROTATING SHELF ===== /datum/shop_sku/outfitter/rotating/riot_suit diff --git a/voidcrew/modules/trade/shop_catalog_suit_vendor.dm b/voidcrew/modules/trade/shop_catalog_suit_vendor.dm index 9787ef08644..eb8bd08a0db 100644 --- a/voidcrew/modules/trade/shop_catalog_suit_vendor.dm +++ b/voidcrew/modules/trade/shop_catalog_suit_vendor.dm @@ -79,7 +79,6 @@ /datum/shop_sku/fitter/frame_boots, /datum/shop_sku/fitter/plating_civilian, // Cores & Power - /datum/shop_sku/fitter/core_standard, /datum/shop_sku/fitter/core_plasma, /datum/shop_sku/fitter/cell, // Mobility @@ -328,15 +327,6 @@ // Boffin owns the cell ladder. Wick stocks exactly one basic cell so a bare // core is usable the moment you buy it, and points at the Skunkworks for more. -/datum/shop_sku/fitter/core_standard - category = "Cores & Power" - name = "MOD standard core" - desc = "The baseline power core. It ships empty, so drop a cell in it or the suit won't run. Boffin stocks the higher grades." - item_path = /obj/item/mod/core/standard - price_credits = 300 - stock_min = 2 - stock_max = 3 - /datum/shop_sku/fitter/core_plasma category = "Cores & Power" name = "MOD plasma core" diff --git a/voidcrew/modules/unit_tests/voidcrew_blueprint_guns.dm b/voidcrew/modules/unit_tests/voidcrew_blueprint_guns.dm index 6531a1669e4..abf0a81c950 100644 --- a/voidcrew/modules/unit_tests/voidcrew_blueprint_guns.dm +++ b/voidcrew/modules/unit_tests/voidcrew_blueprint_guns.dm @@ -1,65 +1,99 @@ -/// Exercise the actual crafting pipeline: schematics must not supply free ammunition. +/// Finished guns have no schematic, receiver, crafting result or fabrication design. /datum/unit_test/voidcrew_blueprint_guns/Run() - var/mob/living/carbon/human/crafter = allocate(__IMPLIED_TYPE__) - var/datum/component/personal_crafting/unit_test/crafting = crafter.AddComponent(__IMPLIED_TYPE__) - allocate(/obj/item/screwdriver, crafter.loc) - allocate(/obj/item/wrench, crafter.loc) - var/recipes_checked = 0 - for(var/datum/crafting_recipe/blueprint/gun/recipe in GLOB.crafting_recipes) - if(!ispath(recipe.result, /obj/item/gun)) - continue - recipes_checked++ - check_recipe(crafter, crafting, recipe) - TEST_ASSERT(recipes_checked > 0, "No blueprint gun recipes were tested.") + var/list/guns = list( + /obj/item/gun/ballistic/automatic/c20r, + /obj/item/gun/ballistic/automatic/wt550, + /obj/item/gun/energy/laser/carbine, + /obj/item/gun/ballistic/automatic/l6_saw, + /obj/item/gun/ballistic/rifle/sniper_rifle, + /obj/item/gun/ballistic/shotgun/bulldog, + ) + for(var/datum/crafting_recipe/recipe as anything in GLOB.crafting_recipes) + var/list/results = islist(recipe.result) ? recipe.result : list(recipe.result) + for(var/result in results) + for(var/gun_type in guns) + TEST_ASSERT(!ispath(result, gun_type), "[recipe.type] still crafts [result].") + for(var/design_id in SSresearch.techweb_designs) + var/datum/design/design = SSresearch.techweb_designs[design_id] + for(var/gun_type in guns) + TEST_ASSERT(!ispath(design.build_path, gun_type), "[design.type] still fabricates [design.build_path].") -/datum/unit_test/voidcrew_blueprint_guns/proc/check_recipe(mob/living/carbon/human/crafter, datum/component/personal_crafting/unit_test/crafting, datum/crafting_recipe/recipe) - for(var/requirement in recipe.reqs) - if(ispath(requirement, /obj/item/stack)) - allocate(requirement, crafter.loc, recipe.reqs[requirement], FALSE) - else - for(var/index in 1 to recipe.reqs[requirement]) - allocate(requirement, crafter.loc) - var/obj/item/gun/gun = crafting.construct_item(crafter, recipe) - TEST_ASSERT(istype(gun), "[recipe.type] failed to craft: [gun]") - allocated += gun - TEST_ASSERT(gun.pin?.type == /obj/item/firing_pin, "[recipe.type] did not install a usable standard firing pin.") - if(istype(gun, /obj/item/gun/energy)) - var/obj/item/gun/energy/energy_gun = gun - TEST_ASSERT(energy_gun.cell?.charge > 0, "[recipe.type] lost its rechargeable power supply.") - qdel(gun) - return - var/obj/item/gun/ballistic/ballistic = gun - TEST_ASSERT_EQUAL(ballistic.get_ammo(), 0, "[recipe.type] provided free ammunition.") - TEST_ASSERT_NULL(ballistic.chambered, "[recipe.type] left a chambered round.") - TEST_ASSERT_NULL(ballistic.magazine, "[recipe.type] provided a free detachable magazine.") - // Deleting the default magazine must not eject it onto the ground instead. - for(var/obj/item/ammo_box/magazine/leaked in crafter.loc) - TEST_FAIL("[recipe.type] left a free magazine on the ground: [leaked.type].") - for(var/obj/item/ammo_casing/leaked in crafter.loc) - TEST_FAIL("[recipe.type] left a free round on the ground: [leaked.type].") + // Text paths avoid recreating the removed parents or requiring deleted defines. + for(var/removed_parent in list("/obj/item/blueprint/gun", "/datum/crafting_recipe/blueprint/gun", "/obj/item/gun_part")) + TEST_ASSERT_NULL(text2path(removed_parent), "[removed_parent] still exists.") + var/list/node_suffixes = list("c20r", "wt550", "carbine", "l6_saw", "sniper", "bulldog") + for(var/removed_node in node_suffixes) + TEST_ASSERT_NULL(SSresearch.techweb_nodes["weapon_part_[removed_node]"], "Receiver node [removed_node] still exists.") + for(var/removed_family in list("c20r", "wt550", "laser_carbine", "l6_saw", "sniper_rifle", "bulldog")) + TEST_ASSERT_NULL(text2path("/obj/item/blueprint/gun/[removed_family]"), "[removed_family] still has a gun schematic.") + TEST_ASSERT_NULL(text2path("/obj/item/gun_part/[removed_family]"), "[removed_family] still has a receiver item.") + TEST_ASSERT_NULL(text2path("/datum/design/gun_part_[removed_family]"), "[removed_family] still has a receiver design type.") + TEST_ASSERT_NULL(text2path("/datum/techweb_node/weapon_part_[removed_family]"), "[removed_family] still has a receiver node type.") + TEST_ASSERT_NULL(SSresearch.techweb_designs["vc_gun_part_[removed_family]"], "[removed_family] still has a receiver design.") + for(var/node_id in SSresearch.techweb_nodes) + var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] + for(var/removed_node in node_suffixes) + TEST_ASSERT(!("weapon_part_[removed_node]" in node.prereq_ids), "[node_id] still requires a removed receiver node.") - // A separately supplied magazine must restore a working weapon, including open bolts. - var/obj/item/ammo_box/magazine/reload = allocate(ballistic.spawn_magazine_type) - TEST_ASSERT(crafter.put_in_hands(reload), "Could not hold the reload for [recipe.type].") - TEST_ASSERT(ballistic.insert_magazine(crafter, reload, FALSE), "[recipe.type] rejected its normal magazine.") - ballistic.drop_bolt() - TEST_ASSERT(ballistic.chambered?.loaded_projectile, "[recipe.type] could not chamber separately supplied ammunition.") - qdel(gun) +/// Ammunition remains connected to the research tree, including specialist loads. +/datum/unit_test/voidcrew_gun_ammo_research/Run() + var/list/reachable = list() + var/previous_count = -1 + while(length(reachable) != previous_count) + previous_count = length(reachable) + for(var/node_id in SSresearch.techweb_nodes) + var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] + if(!(node_id in reachable) && !length(node.prereq_ids - reachable)) + reachable += node_id + var/list/ammo_prereqs = list( + "weapon_ammo_c20r" = list(TECHWEB_NODE_RIOT_SUPRESSION), + "weapon_ammo_wt550" = list(TECHWEB_NODE_RIOT_SUPRESSION), + "weapon_ammo_sniper" = list(TECHWEB_NODE_EXOTIC_AMMO), + "weapon_ammo_bulldog" = list(TECHWEB_NODE_EXOTIC_AMMO), + "weapon_ammo_l6_saw" = list(TECHWEB_NODE_EXOTIC_AMMO, "automatic_ammo"), + ) + var/list/ammo_designs = list( + "weapon_ammo_c20r" = list("vc_ammo_smgm45"), + "weapon_ammo_wt550" = list("vc_ammo_wt550"), + "weapon_ammo_sniper" = list("vc_ammo_sniper_rounds"), + "weapon_ammo_bulldog" = list("vc_ammo_m12g", "vc_ammo_m12g_slug"), + "weapon_ammo_l6_saw" = list("vc_ammo_m7mm"), + ) + for(var/node_id in ammo_prereqs) + TEST_ASSERT(node_id in reachable, "Ammunition node [node_id] is unreachable.") + var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] + TEST_ASSERT_NOTNULL(node, "Missing ammunition node [node_id].") + var/list/expected_prereqs = ammo_prereqs[node_id] + TEST_ASSERT_EQUAL(length(node.prereq_ids), length(expected_prereqs), "[node_id] has unexpected prerequisites.") + TEST_ASSERT_EQUAL(length(expected_prereqs - node.prereq_ids), 0, "[node_id] lost an intended prerequisite.") + for(var/design_id in ammo_designs[node_id]) + TEST_ASSERT(design_id in node.design_ids, "[node_id] lost ammunition design [design_id].") + var/datum/design/design = SSresearch.techweb_designs[design_id] + TEST_ASSERT_NOTNULL(design, "Missing ammunition design [design_id].") + TEST_ASSERT_EQUAL(design.build_type, PROTOLATHE | AWAY_LATHE, "[design_id] lost its lathe channels.") + for(var/node_id in list("bulldog_special_ammo", "l6_special_ammo", "sniper_special_ammo")) + TEST_ASSERT(node_id in reachable, "Specialist ammunition node [node_id] is unreachable.") -/// Preserve internal tubes and cylinder slots when a future schematic uses them. -/datum/unit_test/voidcrew_blueprint_internal_magazines/Run() - var/datum/crafting_recipe/blueprint/gun/recipe = allocate(__IMPLIED_TYPE__) - for(var/gun_type in list(/obj/item/gun/ballistic/shotgun, /obj/item/gun/ballistic/revolver)) - var/obj/item/gun/ballistic/gun = allocate(gun_type) - var/obj/item/ammo_box/magazine/original_magazine = gun.magazine - gun.on_craft_completion(list(), recipe, null) - TEST_ASSERT_EQUAL(gun.magazine, original_magazine, "[gun_type] lost its internal magazine.") - TEST_ASSERT_EQUAL(gun.get_ammo(), 0, "[gun_type] retained free ammunition.") - TEST_ASSERT_NULL(gun.chambered, "[gun_type] retained a chambered round.") - var/obj/item/ammo_casing/reload = allocate(gun.magazine.ammo_type) - TEST_ASSERT(gun.magazine.give_round(reload), "[gun_type] could not reload its emptied internal magazine.") - TEST_ASSERT_EQUAL(gun.get_ammo(), 1, "[gun_type] did not retain its separately supplied round.") - qdel(gun) + var/datum/design/pin_testing/pin = SSresearch.techweb_designs["pin_testing"] + TEST_ASSERT_NOTNULL(pin, "The upstream test-range pin design must remain defined.") + TEST_ASSERT_EQUAL(pin.build_type, NONE, "Test-range pins still have a fabrication channel.") + var/datum/techweb_node/riot_supression/riot = SSresearch.techweb_nodes[TECHWEB_NODE_RIOT_SUPRESSION] + TEST_ASSERT_NOTNULL(riot, "Riot Suppression must remain available.") + TEST_ASSERT(!("pin_testing" in riot.design_ids), "Riot Suppression still unlocks test-range pins.") + TEST_ASSERT("clown_firing_pin" in riot.design_ids, "Removing test-range pins lost another firing pin design.") + +/// The unrelated heavy-cartridge schematic retains the carried-schematic gate. +/datum/unit_test/voidcrew_cartridge_schematic/Run() + var/mob/living/carbon/human/consistent/crafter = allocate(__IMPLIED_TYPE__) + var/obj/item/blueprint/no_quarter_cartridge/schematic = allocate(__IMPLIED_TYPE__) + var/datum/crafting_recipe/blueprint/recipe = schematic.get_recipe() + TEST_ASSERT_NOTNULL(recipe, "The No Quarter cartridge recipe disappeared.") + TEST_ASSERT_EQUAL(recipe.result, /obj/item/ammo_casing/shotgun/no_quarter, "The heavy-cartridge schematic has the wrong recipe.") + TEST_ASSERT(!is_blueprint_recipe_available(recipe, crafter), "A nearby schematic must not unlock a recipe.") + TEST_ASSERT(crafter.put_in_hands(schematic), "Could not carry the cartridge schematic.") + TEST_ASSERT(is_blueprint_recipe_available(recipe, crafter), "Carrying the cartridge schematic must unlock its recipe.") + qdel(schematic) + TEST_ASSERT(!is_blueprint_recipe_available(recipe, crafter), "The recipe remained available after losing the schematic.") /// Map/loot guns and unrelated crafting recipes retain their ordinary loaded state. /datum/unit_test/voidcrew_blueprint_ammo_scope/Run() diff --git a/voidcrew/modules/unit_tests/voidcrew_cargo_cart.dm b/voidcrew/modules/unit_tests/voidcrew_cargo_cart.dm index bcc5cf23df7..ce165b7e739 100644 --- a/voidcrew/modules/unit_tests/voidcrew_cargo_cart.dm +++ b/voidcrew/modules/unit_tests/voidcrew_cargo_cart.dm @@ -51,3 +51,108 @@ world.push_usr(user, CALLBACK(console, TYPE_PROC_REF(/datum, ui_act), "remove", list("order_name" = individual_pack.name), ui)) TEST_ASSERT(!(individual in home.cargo_cart), "Per-item Remove must accept the numeric order ID supplied by ui_act.") TEST_ASSERT(protected in home.cargo_cart, "Removing another item must retain the protected order.") + +// Observe dispatch without loading a shuttle; cart actions and buy() remain real. +/obj/machinery/computer/voidcrew_cargo/launch_cargo_test/restricted_dispatch_test/get_shuttle_error_message() + return null + +/datum/voidcrew_cargo_shuttle/launch_cargo_test/restricted_dispatch_test + var/dispatch_attempted = FALSE + +/datum/voidcrew_cargo_shuttle/launch_cargo_test/restricted_dispatch_test/call_shuttle(obj/structure/overmap/ship/ship) + dispatch_attempted = TRUE + return "Dispatch fixture" + +/// Exercise forged actions, dispatch validation and real settlement. +/datum/unit_test/voidcrew_launch_cargo_fixture/denied_packs/Run() + save_economy() + SSshuttle.supply_packs = list() + var/turf/bay = get_step(run_loc_floor_bottom_left, EAST) + var/list/original_contents = bay.contents.Copy() + var/obj/machinery/computer/voidcrew_cargo/launch_cargo_test/restricted_dispatch_test/console = allocate(__IMPLIED_TYPE__) + var/datum/voidcrew_cargo_shuttle/launch_cargo_test/restricted_dispatch_test/ferry = allocate(__IMPLIED_TYPE__) + ferry.test_turfs = list(bay) + console.test_ferry = ferry + var/obj/machinery/computer/bank_machine/bank = allocate(__IMPLIED_TYPE__) + var/datum/bank_account/account = allocate(/datum/bank_account, "Cargo restriction test", null, 1, FALSE) + bank.synced_bank_account = account + console.link_ship_bank(bank) + account.account_balance = 1000000 + var/mob/living/carbon/human/consistent/user = allocate(__IMPLIED_TYPE__) + var/datum/tgui/ui = allocate(/datum/tgui, user, console, "Cargo") + var/list/banned_types = typesof(/datum/supply_pack/security) + list( + /datum/supply_pack/goody/mars_single, + /datum/supply_pack/goody/ballistic_single, + /datum/supply_pack/goody/disabler_single, + /datum/supply_pack/goody/energy_single, + /datum/supply_pack/goody/laser_single, + /datum/supply_pack/goody/thermal_single, + /datum/supply_pack/goody/double_barrel, + /datum/supply_pack/goody/hell_single, + ) + var/list/banned_packs = list() + for(var/pack_type in banned_types) + var/datum/supply_pack/pack = allocate(pack_type) + pack.special_enabled = TRUE + pack.drop_pod_only = FALSE + SSshuttle.supply_packs[pack_type] = pack + banned_packs += pack + for(var/unlocked in list(FALSE, TRUE)) + if(unlocked) + console.obj_flags |= EMAGGED + else + console.obj_flags &= ~EMAGGED + console.contraband = unlocked + pack.hidden = unlocked + pack.contraband = unlocked + TEST_ASSERT(!console.can_order_pack(pack), "[pack_type] is orderable with emag/contraband [unlocked].") + TEST_ASSERT(!console.add_item(list("id" = "[pack_type]"), user), "A forged [pack_type] ID entered the cart.") + world.push_usr(user, CALLBACK(console, TYPE_PROC_REF(/datum, ui_act), "add", list("id" = "[pack_type]"), ui)) + world.push_usr(user, CALLBACK(console, TYPE_PROC_REF(/datum, ui_act), "add_by_name", list("order_name" = pack.name), ui)) + world.push_usr(user, CALLBACK(console, TYPE_PROC_REF(/datum, ui_act), "modify", list("order_name" = pack.name, "amount" = 1), ui)) + TEST_ASSERT_EQUAL(length(console.checkout_list), 0, "A forged cart action added [pack_type].") + TEST_ASSERT_EQUAL(length(console.get_packs_data(pack.group)), 0, "Forbidden pack group [pack.group] has catalog entries.") + var/list/catalog = console.ui_static_data(user) + TEST_ASSERT_EQUAL(length(catalog["supplies"]), 0, "Empty cargo groups remain visible.") + + // A cart loaded before the restriction must be rechecked before payment or spawning. + for(var/datum/supply_pack/pack as anything in banned_packs) + var/datum/supply_order/order = allocate(/datum/supply_order, pack) + order.applied_coupon = allocate(/obj/item/coupon) + console.checkout_list += order + world.push_usr(user, CALLBACK(console, TYPE_PROC_REF(/datum, ui_act), "send", list(), ui)) + TEST_ASSERT(!ferry.dispatch_attempted, "A forbidden cart reached dispatch, where outpost freight would reserve payment.") + TEST_ASSERT(console.buy(), "The stale-cart fixture did not reach the shipment loop.") + TEST_ASSERT_EQUAL(account.account_balance, 1000000, "A forbidden stale order was charged.") + TEST_ASSERT_EQUAL(length(console.checkout_list), length(banned_packs), "Rejected stale orders must remain cancellable in the cart.") + TEST_ASSERT_EQUAL(length(bay.contents - original_contents), 0, "A forbidden stale order generated cargo.") + for(var/datum/supply_order/order as anything in console.checkout_list) + TEST_ASSERT_NULL(order.ship_paid_cost, "[order.pack.type] was settled despite the restriction.") + TEST_ASSERT_NOTNULL(order.applied_coupon, "Rejecting [order.pack.type] consumed its coupon.") + + // Unrelated cargo must still settle in a cart that also holds forbidden orders. + var/datum/supply_pack/ordinary_pack = allocate(/datum/supply_pack) + ordinary_pack.group = "Cargo control" + ordinary_pack.contains = list(/obj/item/screwdriver) + SSshuttle.supply_packs[ordinary_pack.type] = ordinary_pack + catalog = console.ui_static_data(user) + TEST_ASSERT_EQUAL(length(catalog["supplies"]), 1, "The catalog must show only its nonempty group.") + TEST_ASSERT_NOTNULL(catalog["supplies"][ordinary_pack.group], "An ordinary cargo group disappeared.") + var/datum/supply_order/ordinary_order = allocate(/datum/supply_order, ordinary_pack) + ordinary_order.manifest_can_fail = FALSE + console.checkout_list += ordinary_order + var/ordinary_cost = ordinary_order.get_final_cost() + TEST_ASSERT(console.can_order_pack(ordinary_pack), "The restriction blocked an ordinary pack.") + console.buy() + TEST_ASSERT_EQUAL(account.account_balance, 1000000 - ordinary_cost, "A mixed cart must bill only its ordinary cargo.") + TEST_ASSERT(!(ordinary_order in console.checkout_list), "Ordinary cargo did not leave the cart after settlement.") + TEST_ASSERT_EQUAL(length(console.checkout_list), length(banned_packs), "Settling ordinary cargo changed forbidden orders.") + var/obj/structure/closet/crate/delivery = locate() in bay + TEST_ASSERT_NOTNULL(delivery, "Ordinary cargo did not arrive.") + TEST_ASSERT(locate(/obj/item/screwdriver) in delivery, "Ordinary cargo lost its contents.") + qdel(delivery) + + console.checkout_list.Cut() + console.checkout_list += allocate(/datum/supply_order, ordinary_pack) + world.push_usr(user, CALLBACK(console, TYPE_PROC_REF(/datum, ui_act), "send", list(), ui)) + TEST_ASSERT(ferry.dispatch_attempted, "An ordinary cart must still reach dispatch.") diff --git a/voidcrew/modules/unit_tests/voidcrew_launch_cargo.dm b/voidcrew/modules/unit_tests/voidcrew_launch_cargo.dm index a0bce9de9b6..0eb065ad21f 100644 --- a/voidcrew/modules/unit_tests/voidcrew_launch_cargo.dm +++ b/voidcrew/modules/unit_tests/voidcrew_launch_cargo.dm @@ -158,7 +158,9 @@ qdel(delivery) // An ordinary discounted shipment must record the final paid bill as well. - var/datum/supply_pack/plating_pack = allocate(/datum/supply_pack/security/modsuit_plating) + var/datum/supply_pack/plating_pack = allocate(/datum/supply_pack) + plating_pack.cost = CARGO_CRATE_VALUE + plating_pack.contains = list(/obj/item/mod/construction/plating/civilian) var/datum/supply_order/plating_order = allocate(/datum/supply_order, plating_pack) plating_order.manifest_can_fail = FALSE plating_order.applied_coupon = allocate(/obj/item/coupon) diff --git a/voidcrew/modules/unit_tests/voidcrew_loot.dm b/voidcrew/modules/unit_tests/voidcrew_loot.dm index 20ce575b8f8..b5b96f7e982 100644 --- a/voidcrew/modules/unit_tests/voidcrew_loot.dm +++ b/voidcrew/modules/unit_tests/voidcrew_loot.dm @@ -44,7 +44,7 @@ TEST_FAIL("[theme_path] has an empty [table_name] table") continue for(var/entry in table) - TEST_ASSERT(!ispath(entry, /obj/item/blueprint/gun), "[theme_path].[table_name] still drops a gun schematic: [entry]") + TEST_ASSERT(findtext("[entry]/", "/obj/item/blueprint/gun/") != 1, "[theme_path].[table_name] still drops a gun schematic: [entry]") if(!ispath(entry, /atom/movable)) TEST_FAIL("[theme_path].[table_name] entry [entry] is not an /atom/movable path") var/weight = table[entry] @@ -63,11 +63,11 @@ TEST_FAIL("[theme_path].theme_skus entry [sku] is not a shop SKU") else var/datum/shop_sku/sku_path = sku - TEST_ASSERT(!ispath(initial(sku_path.item_path), /obj/item/blueprint/gun), "[theme_path] still references a gun schematic SKU: [sku]") + TEST_ASSERT(findtext("[initial(sku_path.item_path)]/", "/obj/item/blueprint/gun/") != 1, "[theme_path] still references a gun schematic SKU: [sku]") for(var/list/table as anything in list(GLOB.abandoned_crate_common, GLOB.abandoned_crate_uncommon, GLOB.abandoned_crate_prime)) for(var/entry in table) - TEST_ASSERT(!ispath(entry, /obj/item/blueprint/gun), "Freight still drops a gun schematic: [entry]") + TEST_ASSERT(findtext("[entry]/", "/obj/item/blueprint/gun/") != 1, "Freight still drops a gun schematic: [entry]") var/datum/loot_theme/syndicate/syndicate = GLOB.loot_themes[/datum/loot_theme/syndicate] var/datum/loot_theme/plunder/plunder = GLOB.loot_themes[/datum/loot_theme/plunder] var/datum/loot_theme/research/research = GLOB.loot_themes[/datum/loot_theme/research] diff --git a/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm b/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm index 9f0881b9cd1..5166ac448d7 100644 --- a/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm +++ b/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm @@ -71,3 +71,12 @@ TEST_ASSERT(shops_checked >= 5, "only [shops_checked] shops with a category list were checked") TEST_ASSERT(skus_checked >= 100, "only [skus_checked] SKUs were checked. The catalog walk is not seeing the shelves") + + var/list/banned_gear = list( + /obj/item/restraints/legcuffs/bola, + /obj/item/clothing/glasses/hud/health/sunglasses, + /obj/item/mod/core/standard, + ) + for(var/datum/shop_sku/sku_type as anything in subtypesof(/datum/shop_sku)) + TEST_ASSERT(!(initial(sku_type.item_path) in banned_gear), "[sku_type] still sells removed craftable gear.") + TEST_ASSERT(findtext("[initial(sku_type.item_path)]/", "/obj/item/blueprint/gun/") != 1, "[sku_type] still sells a gun schematic.") diff --git a/voidcrew/modules/weapons_bench/blueprint.dm b/voidcrew/modules/weapons_bench/blueprint.dm index 717f5a20be2..fedf1f4b7ec 100644 --- a/voidcrew/modules/weapons_bench/blueprint.dm +++ b/voidcrew/modules/weapons_bench/blueprint.dm @@ -1,27 +1,6 @@ /** - * Weapon schematics: blueprint-gated crafting-menu recipes - * - * A blueprint is a physical schematic scroll. Its recipe appears in the - * ordinary tg crafting menu when EITHER: - * 1. the crafter is carrying the physical blueprint anywhere on them, or - * 2. the crafter's ckey holds a neural imprint of it for the round - * (bought at an outpost's neural schematic imprinter, destroying the - * physical copy, see voidcrew/modules/trade/blueprint_imprinter.dm). - * - * The availability gate lives in a //VOID EDIT inside - * /datum/component/personal_crafting/is_recipe_available(). - * - * The tension is deliberate: keep the physical copy and it's shareable, - * resellable and stealable; imprint it and it's theft-proof but gone. - * - * Machined gun parts stay the R&D clock: each gun's part design prints at - * the protolathe behind its techweb part node (see the per-gun files), and the - * crafting recipes consume that part. Gun recipes also want a firing pin. - * Crafted guns get a clean standard pin installed in place of any - * faction-locked default (see on_craft_completion below). No bench or other - * machinery is required; the recipe and its reqs are the whole gate, so - * crafting can happen anywhere. Ballistic guns arrive unloaded; ammunition - * must be manufactured or acquired separately. + * Schematics unlock crafting recipes when carried or neurally imprinted. + * The availability gate lives in personal_crafting/is_recipe_available(). */ /// ckey -> list of /datum/crafting_recipe/blueprint types imprinted this round @@ -49,7 +28,7 @@ GLOBAL_LIST_EMPTY(blueprint_imprints) */ /obj/item/blueprint name = "schematic" - desc = "A rolled-up fabrication schematic. Carry it and its recipe shows up in your crafting menu." + desc = "A rolled-up fabrication schematic." icon = 'icons/obj/scrolls.dmi' icon_state = "blueprints" inhand_icon_state = "blueprints" @@ -91,24 +70,6 @@ GLOBAL_LIST_EMPTY(blueprint_imprints) /obj/item/blueprint/examine(mob/user) . = ..() . += span_notice("Schematic: [schematic_name].") - var/datum/crafting_recipe/recipe = get_recipe() - if(recipe) - var/list/req_names = list() - for(var/req_path in recipe.reqs) - var/atom/req_cast = req_path - var/req_amount = recipe.reqs[req_path] - req_names += "[req_amount > 1 ? "[req_amount]x " : ""][initial(req_cast.name)]" - if(length(req_names)) - . += span_notice("Requires: [req_names.Join(", ")].") - if(ispath(recipe.result, /obj/item/gun/ballistic)) - . += span_notice("Builds an unloaded weapon. Ammunition and detachable magazines must be acquired separately.") - if(length(recipe.machinery)) - var/list/machine_names = list() - for(var/machine_path in recipe.machinery) - var/atom/machine_cast = machine_path - machine_names += initial(machine_cast.name) - . += span_notice("Needs a [machine_names.Join(" or ")] nearby.") - . += span_notice("While you're carrying this, the recipe is in your crafting menu. An outpost neural imprinter can burn it into your memory for the rest of the round, but the scroll is destroyed doing it.") /** * # Blueprint recipes @@ -119,56 +80,3 @@ GLOBAL_LIST_EMPTY(blueprint_imprints) /datum/crafting_recipe/blueprint time = 10 SECONDS category = CAT_WEAPON_RANGED - -/// Gun schematics: consume the techweb-gated machined part plus a firing pin. -/// No machinery requirement: craftable anywhere the schematic is available. -/datum/crafting_recipe/blueprint/gun - tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WRENCH) - -/** - * Blueprint-crafted guns swap any faction-locked default pin (syndicate - * implant pins on the C-20r, SAW, Bulldog...) for a clean standard pin, the - * recipe consumed one as a requirement. Without this the crafted gun would - * refuse its own crew. - */ -/obj/item/gun/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) - . = ..() - if(!istype(current_recipe, /datum/crafting_recipe/blueprint)) - return - if(pin && pin.type != /obj/item/firing_pin) - QDEL_NULL(pin) - if(!pin) - pin = new /obj/item/firing_pin(src) - -/// Schematics manufacture the gun, not its default magazine or ammunition. -/obj/item/gun/ballistic/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter) - . = ..() - if(!istype(current_recipe, /datum/crafting_recipe/blueprint/gun)) - return - QDEL_NULL(chambered) - if(internal_magazine && magazine) - // Keep integral feed mechanisms, including the empty slots in revolver - // cylinders. ammo_list() also resolves ammunition that is still lazy-loaded. - for(var/obj/item/ammo_casing/casing in magazine.ammo_list()) - qdel(casing) - magazine.update_appearance() - else - QDEL_NULL(magazine) - if(bolt_type == BOLT_TYPE_OPEN || bolt_type == BOLT_TYPE_LOCKING) - bolt_locked = TRUE - update_appearance() - -/** - * # Machined gun part - * - * The R&D clock made physical: prints at the protolathe once its techweb - * part node is researched, then feeds the gun's crafting recipe. - */ -/obj/item/gun_part - name = "weapon component" - desc = "A machined firearm component. You'll need the matching schematic to build it into a working gun." - icon = 'voidcrew/modules/weapons_bench/icons/gun_parts.dmi' - icon_state = "gun_part" - lefthand_file = 'voidcrew/modules/weapons_bench/icons/gun_parts_lefthand.dmi' - righthand_file = 'voidcrew/modules/weapons_bench/icons/gun_parts_righthand.dmi' - w_class = WEIGHT_CLASS_NORMAL diff --git a/voidcrew/modules/weapons_bench/guns/bulldog.dm b/voidcrew/modules/weapons_bench/guns/bulldog.dm index 5e0314658c7..a46b2b6292d 100644 --- a/voidcrew/modules/weapons_bench/guns/bulldog.dm +++ b/voidcrew/modules/weapons_bench/guns/bulldog.dm @@ -1,49 +1,6 @@ -/** - * Bulldog shotgun -- red-tier blueprint gun. - * - * Boarding-party drum shotgun. Part node sits deep (prereq Exotic Ammunition, - * tier 4); see guns/l6_saw.dm for the annotated pipeline walkthrough. - */ - -/obj/item/blueprint/gun/bulldog - name = "weapon schematic (Bulldog shotgun)" - schematic_name = "Bulldog shotgun" - recipe_type = /datum/crafting_recipe/blueprint/gun/bulldog - tier = BLUEPRINT_TIER_RED - -/datum/crafting_recipe/blueprint/gun/bulldog - name = "Bulldog Shotgun" - result = /obj/item/gun/ballistic/shotgun/bulldog - reqs = list( - /obj/item/gun_part/bulldog = 1, - /obj/item/firing_pin = 1, - /obj/item/stack/sheet/iron = 6, - ) - -/obj/item/gun_part/bulldog - name = "Bulldog receiver" - desc = "The machined receiver and drum-feed assembly for a Bulldog shotgun. You'll need the matching schematic to build it into a working gun." - icon_state = "bulldog" - -/datum/design/gun_part_bulldog - name = "Bulldog Receiver" - desc = "A machined receiver and drum-feed assembly for a Bulldog shotgun. Not a working gun on its own." - id = "vc_gun_part_bulldog" - build_type = PROTOLATHE | AWAY_LATHE - materials = list( - /datum/material/iron = SHEET_MATERIAL_AMOUNT * 12, - /datum/material/plastic = SHEET_MATERIAL_AMOUNT * 4, - /datum/material/silver = SHEET_MATERIAL_AMOUNT * 1, - ) - build_path = /obj/item/gun_part/bulldog - category = list( - RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_PARTS, - ) - departmental_flags = DEPARTMENT_BITFLAG_SECURITY - /datum/design/ammo_m12g name = "Shotgun Drum Magazine (12g buckshot)" - desc = "An 8-round buckshot drum for a Bulldog shotgun." + desc = "A buckshot drum for a Bulldog shotgun." id = "vc_ammo_m12g" build_type = PROTOLATHE | AWAY_LATHE materials = list( @@ -58,7 +15,7 @@ /datum/design/ammo_m12g_slug name = "Shotgun Drum Magazine (12g slug)" - desc = "An 8-round slug drum for a Bulldog shotgun." + desc = "A slug drum for a Bulldog shotgun." id = "vc_ammo_m12g_slug" build_type = PROTOLATHE | AWAY_LATHE materials = list( @@ -71,18 +28,10 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SECURITY -/datum/techweb_node/weapon_part_bulldog - id = TECHWEB_NODE_WEAPON_PART_BULLDOG - display_name = "Bulldog Schematics" - description = "Reverse-engineered receiver schematics for the Bulldog shotgun. Unlocks protolathe production of its receiver assembly." - prereq_ids = list(TECHWEB_NODE_EXOTIC_AMMO) - design_ids = list("vc_gun_part_bulldog") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) - /datum/techweb_node/weapon_ammo_bulldog id = TECHWEB_NODE_WEAPON_AMMO_BULLDOG display_name = "12g Drum Production" - description = "Bulk 12-gauge drum production for the Bulldog. Prints buckshot and slug drums at the lathe." - prereq_ids = list(TECHWEB_NODE_WEAPON_PART_BULLDOG) + description = "Bulk buckshot and slug drums for the Bulldog." + prereq_ids = list(TECHWEB_NODE_EXOTIC_AMMO) design_ids = list("vc_ammo_m12g", "vc_ammo_m12g_slug") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) diff --git a/voidcrew/modules/weapons_bench/guns/c20r.dm b/voidcrew/modules/weapons_bench/guns/c20r.dm index d4142e78abc..e5b78f52ab8 100644 --- a/voidcrew/modules/weapons_bench/guns/c20r.dm +++ b/voidcrew/modules/weapons_bench/guns/c20r.dm @@ -1,45 +1,3 @@ -/** - * C-20r SMG -- yellow/mid-tier blueprint gun. - * - * Part node sits mid-depth (prereq Riot Suppression, tier 3). Same pipeline as - * the L6 SAW; see guns/l6_saw.dm for the annotated walkthrough. - */ - -/obj/item/blueprint/gun/c20r - name = "weapon schematic (C-20r SMG)" - schematic_name = "C-20r SMG" - recipe_type = /datum/crafting_recipe/blueprint/gun/c20r - tier = BLUEPRINT_TIER_YELLOW - -/datum/crafting_recipe/blueprint/gun/c20r - name = "C-20r SMG" - result = /obj/item/gun/ballistic/automatic/c20r - reqs = list( - /obj/item/gun_part/c20r = 1, - /obj/item/firing_pin = 1, - /obj/item/stack/sheet/iron = 5, - ) - -/obj/item/gun_part/c20r - name = "C-20r receiver" - desc = "The machined receiver assembly for a C-20r submachine gun. You'll need the matching schematic to build it into a working gun." - icon_state = "c20r" - -/datum/design/gun_part_c20r - name = "C-20r Receiver" - desc = "A machined receiver assembly for a C-20r SMG. Not a working gun on its own." - id = "vc_gun_part_c20r" - build_type = PROTOLATHE | AWAY_LATHE - materials = list( - /datum/material/iron = SHEET_MATERIAL_AMOUNT * 10, - /datum/material/plastic = SHEET_MATERIAL_AMOUNT * 4, - ) - build_path = /obj/item/gun_part/c20r - category = list( - RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_PARTS, - ) - departmental_flags = DEPARTMENT_BITFLAG_SECURITY - /datum/design/ammo_smgm45 name = "SMG Magazine (.45)" desc = "A .45 box magazine for a C-20r SMG." @@ -55,18 +13,10 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SECURITY -/datum/techweb_node/weapon_part_c20r - id = TECHWEB_NODE_WEAPON_PART_C20R - display_name = "C-20r Schematics" - description = "Reverse-engineered receiver schematics for the C-20r SMG. Unlocks protolathe production of its receiver assembly." - prereq_ids = list(TECHWEB_NODE_RIOT_SUPRESSION) - design_ids = list("vc_gun_part_c20r") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) - /datum/techweb_node/weapon_ammo_c20r id = TECHWEB_NODE_WEAPON_AMMO_C20R display_name = ".45 SMG Ammunition" - description = "Bulk .45 production for the C-20r. Prints magazines at the lathe." - prereq_ids = list(TECHWEB_NODE_WEAPON_PART_C20R) + description = "Bulk .45 production for the C-20r." + prereq_ids = list(TECHWEB_NODE_RIOT_SUPRESSION) design_ids = list("vc_ammo_smgm45") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) diff --git a/voidcrew/modules/weapons_bench/guns/l6_saw.dm b/voidcrew/modules/weapons_bench/guns/l6_saw.dm index 838026f9037..64df35913dc 100644 --- a/voidcrew/modules/weapons_bench/guns/l6_saw.dm +++ b/voidcrew/modules/weapons_bench/guns/l6_saw.dm @@ -1,63 +1,6 @@ -/** - * L6 SAW -- red-tier blueprint gun (the design doc's running example). - * - * Pipeline, all in one place: - * 1. Schematic (below) -- ruin loot / black-market SKU; carrying it (or a neural imprint) puts the recipe in your crafting menu - * 2. Part node -> part design -- tier 4 after Exotic Ammunition; part prints at the protolathe - * 3. Ammo node -> ammo design -- tier 2 after Exotic and Automatic Ammunition, independent of the receiver - * 4. Crafting menu, anywhere -- part + firing pin + plasteel => the unloaded gun - */ - -// --- Schematic + recipe + part ----------------------------------------------- - -/obj/item/blueprint/gun/l6_saw - name = "weapon schematic (L6 SAW)" - schematic_name = "L6 SAW" - recipe_type = /datum/crafting_recipe/blueprint/gun/l6_saw - tier = BLUEPRINT_TIER_RED - -/datum/crafting_recipe/blueprint/gun/l6_saw - name = "L6 SAW" - result = /obj/item/gun/ballistic/automatic/l6_saw - time = 45 SECONDS - reqs = list( - /obj/item/gun_part/l6_saw = 1, - /obj/item/firing_pin = 1, - /obj/item/stack/sheet/plasteel = 20, - ) - -/obj/item/gun_part/l6_saw - name = "L6 SAW receiver" - desc = "The machined receiver assembly for an L6 SAW light machine gun. You'll need the matching schematic to build it into a working gun." - icon_state = "l6" - -// --- Protolathe part design -------------------------------------------------- - -/datum/design/gun_part_l6_saw - name = "L6 SAW Receiver" - desc = "A machined receiver assembly for an L6 SAW. Not a working gun on its own." - id = "vc_gun_part_l6_saw" - build_type = PROTOLATHE | AWAY_LATHE - // A crew investment comparable to combat mech body parts, even with the - // protolathe's 60% maximum discount. Assembly's plasteel is paid separately. - materials = list( - /datum/material/iron = SHEET_MATERIAL_AMOUNT * 100, - /datum/material/titanium = SHEET_MATERIAL_AMOUNT * 30, - /datum/material/plastic = SHEET_MATERIAL_AMOUNT * 20, - /datum/material/silver = SHEET_MATERIAL_AMOUNT * 10, - /datum/material/diamond = SHEET_MATERIAL_AMOUNT * 10, - ) - build_path = /obj/item/gun_part/l6_saw - category = list( - RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_PARTS, - ) - departmental_flags = DEPARTMENT_BITFLAG_SECURITY - -// --- Lathe ammo design ------------------------------------------------------- - /datum/design/ammo_m7mm name = "Machine Gun Magazine (7mm)" - desc = "A 50-round box magazine of 7mm ammunition for an L6 SAW." + desc = "A box magazine of 7mm ammunition for an L6 SAW." id = "vc_ammo_m7mm" build_type = PROTOLATHE | AWAY_LATHE // Sustained SAW fire consumes mining resources on every reload. At full @@ -76,18 +19,10 @@ // --- Techweb nodes ----------------------------------------------------------- -/datum/techweb_node/weapon_part_l6_saw - id = TECHWEB_NODE_WEAPON_PART_L6_SAW - display_name = "L6 SAW Schematics" - description = "Reverse-engineered receiver schematics for the L6 SAW. Unlocks protolathe production of its receiver assembly, the hard half of the gun." - prereq_ids = list(TECHWEB_NODE_EXOTIC_AMMO) - design_ids = list("vc_gun_part_l6_saw") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) - /datum/techweb_node/weapon_ammo_l6_saw id = TECHWEB_NODE_WEAPON_AMMO_L6_SAW display_name = "7mm Machine Gun Ammunition" - description = "Belt-fed 7mm production for the L6 SAW. Prints magazines at the lathe, including for salvaged weapons without receiver research." + description = "Belt-fed 7mm production for the L6 SAW." prereq_ids = list(TECHWEB_NODE_EXOTIC_AMMO, TECHWEB_NODE_AUTOMATIC_AMMO) design_ids = list("vc_ammo_m7mm") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) diff --git a/voidcrew/modules/weapons_bench/guns/laser_carbine.dm b/voidcrew/modules/weapons_bench/guns/laser_carbine.dm deleted file mode 100644 index 7b3f47f0ef2..00000000000 --- a/voidcrew/modules/weapons_bench/guns/laser_carbine.dm +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Laser carbine -- yellow/mid-tier blueprint gun, the first energy schematic. - * - * Energy weapons skip the ammo node entirely: the cell recharges at any - * recharger, which is the point of the carbine. Sustained cheap fire, low - * per-shot punch. Part node sits mid-depth (prereq Riot Suppression, tier 3). - */ - -/obj/item/blueprint/gun/laser_carbine - name = "weapon schematic (laser carbine)" - schematic_name = "laser carbine" - recipe_type = /datum/crafting_recipe/blueprint/gun/laser_carbine - tier = BLUEPRINT_TIER_YELLOW - -/datum/crafting_recipe/blueprint/gun/laser_carbine - name = "Laser Carbine" - result = /obj/item/gun/energy/laser/carbine - reqs = list( - /obj/item/gun_part/laser_carbine = 1, - /obj/item/firing_pin = 1, - /obj/item/stack/sheet/glass = 5, - ) - -/obj/item/gun_part/laser_carbine - name = "laser carbine emitter assembly" - desc = "The machined emitter and focusing assembly for a laser carbine. You'll need the matching schematic to build it into a working gun." - icon_state = "laser_carbine" - -/datum/design/gun_part_laser_carbine - name = "Laser Carbine Emitter Assembly" - desc = "A machined emitter and focusing assembly for a laser carbine. Not a working gun on its own." - id = "vc_gun_part_laser_carbine" - build_type = PROTOLATHE | AWAY_LATHE - materials = list( - /datum/material/iron = SHEET_MATERIAL_AMOUNT * 8, - /datum/material/glass = SHEET_MATERIAL_AMOUNT * 4, - /datum/material/gold = SHEET_MATERIAL_AMOUNT * 1, - ) - build_path = /obj/item/gun_part/laser_carbine - category = list( - RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_PARTS, - ) - departmental_flags = DEPARTMENT_BITFLAG_SECURITY - -/datum/techweb_node/weapon_part_laser_carbine - id = TECHWEB_NODE_WEAPON_PART_CARBINE - display_name = "Laser Carbine Schematics" - description = "Emitter schematics for a rapid-cycling laser carbine. Unlocks protolathe production of its emitter assembly. There's no ammunition to research; the cell tops up at any recharger." - prereq_ids = list(TECHWEB_NODE_RIOT_SUPRESSION) - design_ids = list("vc_gun_part_laser_carbine") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) diff --git a/voidcrew/modules/weapons_bench/guns/sniper.dm b/voidcrew/modules/weapons_bench/guns/sniper.dm index f36f88ff055..56eaf3a7d64 100644 --- a/voidcrew/modules/weapons_bench/guns/sniper.dm +++ b/voidcrew/modules/weapons_bench/guns/sniper.dm @@ -1,46 +1,3 @@ -/** - * Anti-materiel sniper rifle -- red/deep-tier blueprint gun. - * - * Part node sits deep (prereq Exotic Ammunition, tier 4). Same pipeline as the - * L6 SAW; see guns/l6_saw.dm for the annotated walkthrough. - */ - -/obj/item/blueprint/gun/sniper_rifle - name = "weapon schematic (anti-materiel rifle)" - schematic_name = "anti-materiel sniper rifle" - recipe_type = /datum/crafting_recipe/blueprint/gun/sniper_rifle - tier = BLUEPRINT_TIER_RED - -/datum/crafting_recipe/blueprint/gun/sniper_rifle - name = "Anti-Materiel Sniper Rifle" - result = /obj/item/gun/ballistic/rifle/sniper_rifle - reqs = list( - /obj/item/gun_part/sniper_rifle = 1, - /obj/item/firing_pin = 1, - /obj/item/stack/sheet/iron = 8, - ) - -/obj/item/gun_part/sniper_rifle - name = "anti-materiel rifle receiver" - desc = "The machined receiver and bolt assembly for an anti-materiel sniper rifle. You'll need the matching schematic to build it into a working gun." - icon_state = "sniper" - -/datum/design/gun_part_sniper_rifle - name = "Anti-Materiel Rifle Receiver" - desc = "A machined receiver and bolt assembly for an anti-materiel sniper rifle. Not a working gun on its own." - id = "vc_gun_part_sniper_rifle" - build_type = PROTOLATHE | AWAY_LATHE - materials = list( - /datum/material/iron = SHEET_MATERIAL_AMOUNT * 18, - /datum/material/plastic = SHEET_MATERIAL_AMOUNT * 4, - /datum/material/silver = SHEET_MATERIAL_AMOUNT * 3, - ) - build_path = /obj/item/gun_part/sniper_rifle - category = list( - RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_PARTS, - ) - departmental_flags = DEPARTMENT_BITFLAG_SECURITY - /datum/design/ammo_sniper_rounds name = "Sniper Magazine (.50 BMG)" desc = "A magazine of .50 BMG cartridges for an anti-materiel rifle." @@ -56,18 +13,10 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SECURITY -/datum/techweb_node/weapon_part_sniper_rifle - id = TECHWEB_NODE_WEAPON_PART_SNIPER - display_name = "Anti-Materiel Rifle Schematics" - description = "Reverse-engineered receiver schematics for an anti-materiel sniper rifle. Unlocks protolathe production of its receiver assembly." - prereq_ids = list(TECHWEB_NODE_EXOTIC_AMMO) - design_ids = list("vc_gun_part_sniper_rifle") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) - /datum/techweb_node/weapon_ammo_sniper_rifle id = TECHWEB_NODE_WEAPON_AMMO_SNIPER display_name = ".50 BMG Ammunition" - description = "Bulk .50 BMG production for the anti-materiel rifle. Prints magazines at the lathe." - prereq_ids = list(TECHWEB_NODE_WEAPON_PART_SNIPER) + description = "Bulk .50 BMG production for the anti-materiel rifle." + prereq_ids = list(TECHWEB_NODE_EXOTIC_AMMO) design_ids = list("vc_ammo_sniper_rounds") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) diff --git a/voidcrew/modules/weapons_bench/guns/wt550.dm b/voidcrew/modules/weapons_bench/guns/wt550.dm index b57884a8ff0..a990120d27e 100644 --- a/voidcrew/modules/weapons_bench/guns/wt550.dm +++ b/voidcrew/modules/weapons_bench/guns/wt550.dm @@ -1,48 +1,6 @@ -/** - * WT-550 autorifle -- yellow/mid-tier blueprint gun. - * - * The lawful counterpart to the C-20r. Part node sits mid-depth (prereq Riot - * Suppression, tier 3); see guns/l6_saw.dm for the annotated walkthrough. - */ - -/obj/item/blueprint/gun/wt550 - name = "weapon schematic (WT-550 autorifle)" - schematic_name = "WT-550 autorifle" - recipe_type = /datum/crafting_recipe/blueprint/gun/wt550 - tier = BLUEPRINT_TIER_YELLOW - -/datum/crafting_recipe/blueprint/gun/wt550 - name = "WT-550 Autorifle" - result = /obj/item/gun/ballistic/automatic/wt550 - reqs = list( - /obj/item/gun_part/wt550 = 1, - /obj/item/firing_pin = 1, - /obj/item/stack/sheet/iron = 5, - ) - -/obj/item/gun_part/wt550 - name = "WT-550 receiver" - desc = "The machined receiver assembly for a WT-550 autorifle. You'll need the matching schematic to build it into a working gun." - icon_state = "wt550" - -/datum/design/gun_part_wt550 - name = "WT-550 Receiver" - desc = "A machined receiver assembly for a WT-550 autorifle. Not a working gun on its own." - id = "vc_gun_part_wt550" - build_type = PROTOLATHE | AWAY_LATHE - materials = list( - /datum/material/iron = SHEET_MATERIAL_AMOUNT * 10, - /datum/material/plastic = SHEET_MATERIAL_AMOUNT * 4, - ) - build_path = /obj/item/gun_part/wt550 - category = list( - RND_CATEGORY_WEAPONS + RND_SUBCATEGORY_WEAPONS_PARTS, - ) - departmental_flags = DEPARTMENT_BITFLAG_SECURITY - /datum/design/ammo_wt550 name = "Autorifle Magazine (4.6x30mm)" - desc = "A 20-round 4.6x30mm magazine for a WT-550 autorifle." + desc = "A 4.6x30mm magazine for a WT-550 autorifle." id = "vc_ammo_wt550" build_type = PROTOLATHE | AWAY_LATHE materials = list( @@ -55,18 +13,10 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SECURITY -/datum/techweb_node/weapon_part_wt550 - id = TECHWEB_NODE_WEAPON_PART_WT550 - display_name = "WT-550 Schematics" - description = "Licensed receiver schematics for the WT-550 autorifle. Unlocks protolathe production of its receiver assembly." - prereq_ids = list(TECHWEB_NODE_RIOT_SUPRESSION) - design_ids = list("vc_gun_part_wt550") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) - /datum/techweb_node/weapon_ammo_wt550 id = TECHWEB_NODE_WEAPON_AMMO_WT550 display_name = "4.6x30mm Ammunition" - description = "Bulk 4.6x30mm production for the WT-550. Prints magazines at the lathe." - prereq_ids = list(TECHWEB_NODE_WEAPON_PART_WT550) + description = "Bulk 4.6x30mm production for the WT-550." + prereq_ids = list(TECHWEB_NODE_RIOT_SUPRESSION) design_ids = list("vc_ammo_wt550") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) From f5dd8c26eb38bdc77ccd6459385994c5496505f8 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:20:22 -0700 Subject: [PATCH 006/105] Remove guaranteed melee and reduce reward bundles --- voidcrew/edits/mobs/ruin_icons.dm | 7 +++ .../npc_ships/code/bounty/bounty_loot.dm | 9 --- .../faction_pirates/faction_pirate_bosses.dm | 4 +- .../faction_pirates/faction_pirate_mobs.dm | 3 - .../outpost_checkpoint_snapshot.dm | 2 + .../modules/unit_tests/voidcrew_missions.dm | 55 ++++++++++++++++ .../unit_tests/voidcrew_planetary_factions.dm | 63 +++++++++++++++++++ voidcrew/modules/vending/security.dm | 1 - 8 files changed, 129 insertions(+), 15 deletions(-) diff --git a/voidcrew/edits/mobs/ruin_icons.dm b/voidcrew/edits/mobs/ruin_icons.dm index 4b2cf006325..e37426febfb 100644 --- a/voidcrew/edits/mobs/ruin_icons.dm +++ b/voidcrew/edits/mobs/ruin_icons.dm @@ -1,6 +1,13 @@ // Static/editor fallbacks for dynamically assembled basic mobs used by legacy // Voidcrew ruins. These states are sourced from Voidcrew-LRP's simple_human.dmi. +/mob/living/basic/skeleton/templar + loot = list( + /obj/effect/decal/remains/human, + /obj/item/clothing/suit/chaplainsuit/armor/templar, + /obj/item/clothing/head/helmet/chaplain, + ) + /mob/living/basic/skeleton/plasmaminer icon = 'voidcrew/icons/mob/legacy_ruin_mobs.dmi' diff --git a/voidcrew/modules/npc_ships/code/bounty/bounty_loot.dm b/voidcrew/modules/npc_ships/code/bounty/bounty_loot.dm index 6f507984780..ed8068d55e0 100644 --- a/voidcrew/modules/npc_ships/code/bounty/bounty_loot.dm +++ b/voidcrew/modules/npc_ships/code/bounty/bounty_loot.dm @@ -22,8 +22,6 @@ /obj/structure/closet/crate/secure/weapon/pirate_loot/lasers/populate_contents_immediate() . = ..() new /obj/item/gun/energy/laser(src) - new /obj/item/gun/energy/laser(src) - new /obj/item/gun/energy/laser(src) /obj/structure/closet/crate/secure/weapon/pirate_loot/disablers name = "pirate disabler cache" @@ -33,8 +31,6 @@ /obj/structure/closet/crate/secure/weapon/pirate_loot/disablers/populate_contents_immediate() . = ..() new /obj/item/gun/energy/disabler(src) - new /obj/item/gun/energy/disabler(src) - new /obj/item/gun/energy/disabler(src) /obj/structure/closet/crate/secure/weapon/pirate_loot/armor name = "pirate armor cache" @@ -85,7 +81,6 @@ /obj/structure/closet/crate/secure/weapon/pirate_loot/heavy/energy_guns/populate_contents_immediate() . = ..() new /obj/item/gun/energy/e_gun(src) - new /obj/item/gun/energy/e_gun(src) /obj/structure/closet/crate/secure/weapon/pirate_loot/heavy/combat_shotguns name = "pirate combat shotgun cache" @@ -94,8 +89,6 @@ /obj/structure/closet/crate/secure/weapon/pirate_loot/heavy/combat_shotguns/PopulateContents() . = ..() new /obj/item/gun/ballistic/shotgun/automatic/combat(src) - new /obj/item/gun/ballistic/shotgun/automatic/combat(src) - new /obj/item/gun/ballistic/shotgun/automatic/combat(src) new /obj/item/storage/belt/bandolier(src) new /obj/item/storage/belt/bandolier(src) new /obj/item/storage/belt/bandolier(src) @@ -107,8 +100,6 @@ /obj/structure/closet/crate/secure/weapon/pirate_loot/heavy/laser_carbines/PopulateContents() . = ..() new /obj/item/gun/energy/laser/carbine(src) - new /obj/item/gun/energy/laser/carbine(src) - new /obj/item/gun/energy/laser/carbine(src) /obj/structure/closet/crate/secure/weapon/pirate_loot/heavy/swat name = "pirate tactical gear cache" diff --git a/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_bosses.dm b/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_bosses.dm index d408032eba2..89c7a8fcab0 100644 --- a/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_bosses.dm +++ b/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_bosses.dm @@ -58,7 +58,7 @@ mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/faction/silverscale/highlord corpse = /obj/effect/mob_spawn/corpse/human/pirate/faction/silverscale/highlord r_hand = /obj/item/melee/energy/sword/pirate - loot_pool = list(/obj/item/claymore/cutlass, /obj/item/clothing/suit/hooded/cloak/drake, /obj/item/clothing/head/hooded/cloakhood/drake) + loot_pool = list(/obj/item/clothing/suit/hooded/cloak/drake, /obj/item/clothing/head/hooded/cloakhood/drake) plunder_credits = 3000 /mob/living/basic/trooper/pirate/faction/boss/silverscale/Initialize(mapload) @@ -87,7 +87,7 @@ mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/faction/skeleton/davyjones corpse = /obj/effect/mob_spawn/corpse/human/pirate/faction/skeleton/davyjones r_hand = /obj/item/claymore/cutlass - loot_pool = list(/obj/item/claymore/cutlass, /obj/item/gun/ballistic/shotgun/hook) + loot_pool = list(/obj/item/gun/ballistic/shotgun/hook) plunder_credits = 3000 /mob/living/basic/trooper/pirate/faction/boss/skeleton/Initialize(mapload) diff --git a/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm b/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm index 9f158b5d8d5..1fa32a02618 100644 --- a/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm +++ b/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm @@ -126,7 +126,6 @@ mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/faction/silverscale/captain corpse = /obj/effect/mob_spawn/corpse/human/pirate/faction/silverscale/captain r_hand = /obj/item/gun/energy/e_gun/lethal - loot_pool = list(/obj/item/claymore/cutlass) random_loot = null plunder_credits = 1000 @@ -325,7 +324,6 @@ mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/faction/lustrous/captain corpse = /obj/effect/mob_spawn/corpse/human/pirate/faction/lustrous/captain r_hand = /obj/item/melee/energy/sword/pirate - loot_pool = list(/obj/item/claymore/cutlass) random_loot = null plunder_credits = 1000 @@ -389,7 +387,6 @@ mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/faction/interdyne/captain corpse = /obj/effect/mob_spawn/corpse/human/pirate/faction/interdyne/captain r_hand = /obj/item/melee/energy/sword/pirate - loot_pool = list(/obj/item/claymore/cutlass) random_loot = null plunder_credits = 1000 diff --git a/voidcrew/modules/player_outposts/outpost_checkpoint_snapshot.dm b/voidcrew/modules/player_outposts/outpost_checkpoint_snapshot.dm index aad06503529..28877394003 100644 --- a/voidcrew/modules/player_outposts/outpost_checkpoint_snapshot.dm +++ b/voidcrew/modules/player_outposts/outpost_checkpoint_snapshot.dm @@ -27,6 +27,8 @@ GLOBAL_LIST_INIT(outpost_checkpoint_infrastructure, typecacheof(list( GLOBAL_LIST_INIT(outpost_checkpoint_excluded, typecacheof(list( /obj/machinery/portable_atmospherics, /obj/machinery/computer/ship_checkpoint, + // Internal vending stock is not scrubbed by clear_stock(). + /obj/machinery/vending/security/marine/solgov, // Made by its turret. /obj/machinery/porta_turret_cover, // Never rebuilt: user decision, 2026-09-24. diff --git a/voidcrew/modules/unit_tests/voidcrew_missions.dm b/voidcrew/modules/unit_tests/voidcrew_missions.dm index 59b49bc4b11..c6c96379b1d 100644 --- a/voidcrew/modules/unit_tests/voidcrew_missions.dm +++ b/voidcrew/modules/unit_tests/voidcrew_missions.dm @@ -58,6 +58,61 @@ /datum/unit_test/voidcrew_mission_wiring +/// Steal-objective guns exist at spawn; opening any gun cache yields one gun total. +/datum/unit_test/voidcrew_pirate_reward_guns/Run() + var/list/cache_guns = list( + /obj/structure/closet/crate/secure/weapon/pirate_loot/lasers = /obj/item/gun/energy/laser, + /obj/structure/closet/crate/secure/weapon/pirate_loot/disablers = /obj/item/gun/energy/disabler, + /obj/structure/closet/crate/secure/weapon/pirate_loot/heavy/energy_guns = /obj/item/gun/energy/e_gun, + /obj/structure/closet/crate/secure/weapon/pirate_loot/heavy/combat_shotguns = /obj/item/gun/ballistic/shotgun/automatic/combat, + /obj/structure/closet/crate/secure/weapon/pirate_loot/heavy/laser_carbines = /obj/item/gun/energy/laser/carbine, + ) + var/list/immediate_caches = list( + /obj/structure/closet/crate/secure/weapon/pirate_loot/lasers, + /obj/structure/closet/crate/secure/weapon/pirate_loot/disablers, + /obj/structure/closet/crate/secure/weapon/pirate_loot/heavy/energy_guns, + ) + var/turf/cache_turf = run_loc_floor_bottom_left + for(var/cache_type in cache_guns) + var/obj/structure/closet/crate/secure/weapon/pirate_loot/cache = allocate(cache_type, cache_turf) + var/expected_before = (cache_type in immediate_caches) ? 1 : 0 + TEST_ASSERT_EQUAL(length(cache.get_all_contents_type(/obj/item/gun)), expected_before, "[cache_type] has the wrong gun count before opening") + TEST_ASSERT_EQUAL(length(cache.get_all_contents_type(cache_guns[cache_type])), expected_before, "[cache_type] has the wrong gun type before opening") + TEST_ASSERT(!cache.contents_initialized, "[cache_type] must retain lazy population of other contents") + TEST_ASSERT(cache.open(null, TRUE, FALSE), "[cache_type] could not open") + TEST_ASSERT_EQUAL(length(cache_turf.get_all_contents_type(/obj/item/gun)), 1, "[cache_type] must contain exactly one gun after opening") + TEST_ASSERT_EQUAL(length(cache_turf.get_all_contents_type(cache_guns[cache_type])), 1, "[cache_type] must retain its gun type") + if(cache_type == /obj/structure/closet/crate/secure/weapon/pirate_loot/heavy/combat_shotguns) + TEST_ASSERT_EQUAL(length(cache_turf.get_all_contents_type(/obj/item/storage/belt/bandolier)), 3, "The shotgun cache must retain all three bandoliers") + TEST_ASSERT(cache.close(), "[cache_type] could not close") + TEST_ASSERT(cache.open(null, TRUE, FALSE), "[cache_type] could not reopen") + TEST_ASSERT_EQUAL(length(cache_turf.get_all_contents_type(/obj/item/gun)), 1, "Reopening [cache_type] duplicated its gun") + for(var/atom/movable/drop in cache_turf.contents - cache) + if(!istype(drop, /obj/effect/landmark)) + qdel(drop) + qdel(cache) + +/// Initial, rebuilt and refilled SolGov inventories cannot recreate the removed sword. +/datum/unit_test/voidcrew_solgov_vendor_stock/Run() + var/obj/machinery/vending/security/marine/solgov/vendor = allocate(/obj/machinery/vending/security/marine/solgov) + assert_no_sword(vendor) + TEST_ASSERT(!outpost_checkpoint_saves(vendor), "Ship checkpoints must exclude SolGov vendors") + vendor.update_canister() + vendor.RefreshParts() + assert_no_sword(vendor) + var/obj/item/vending_refill/security/refill = allocate(/obj/item/vending_refill/security) + // Old stock in a canister must not add a product absent from the new inventory. + refill.products = list(/obj/item/melee/energy/sword/saber/blue = 1, /obj/item/restraints/handcuffs = 10) + for(var/datum/data/vending_product/product in vendor.product_records) + product.amount = 0 + TEST_ASSERT(vendor.restock(refill) > 0, "The refill must still replenish supported products") + assert_no_sword(vendor) + +/datum/unit_test/voidcrew_solgov_vendor_stock/proc/assert_no_sword(obj/machinery/vending/security/marine/solgov/vendor) + TEST_ASSERT(!(/obj/item/melee/energy/sword/saber/blue in vendor.products), "SolGov's products still include the blue sword") + for(var/datum/data/vending_product/product in vendor.product_records + vendor.hidden_records + vendor.coin_records) + TEST_ASSERT(!ispath(product.product_path, /obj/item/melee/energy/sword/saber/blue), "SolGov's live inventory still includes the blue sword") + /datum/unit_test/voidcrew_mission_wiring/Run() var/checked = 0 for(var/datum/mission/mission_type as anything in subtypesof(/datum/mission)) diff --git a/voidcrew/modules/unit_tests/voidcrew_planetary_factions.dm b/voidcrew/modules/unit_tests/voidcrew_planetary_factions.dm index 5f657798308..3abfc6b9543 100644 --- a/voidcrew/modules/unit_tests/voidcrew_planetary_factions.dm +++ b/voidcrew/modules/unit_tests/voidcrew_planetary_factions.dm @@ -8,6 +8,69 @@ */ /datum/unit_test/voidcrew_planetary_factions +/// Check real death drops, including corpse equipment, rather than visual weapons. +/datum/unit_test/voidcrew_melee_death_drops/Run() + var/list/mob_loot = list( + /mob/living/basic/trooper/pirate/faction/silverscale/captain = list(), + /mob/living/basic/trooper/pirate/faction/lustrous/captain = list(), + /mob/living/basic/trooper/pirate/faction/interdyne/captain = list(), + /mob/living/basic/trooper/pirate/faction/boss/silverscale = list( + /obj/item/clothing/suit/hooded/cloak/drake, + /obj/item/clothing/head/hooded/cloakhood/drake, + ), + /mob/living/basic/trooper/pirate/faction/boss/skeleton = list(/obj/item/gun/ballistic/shotgun/hook), + /mob/living/basic/skeleton/templar = list( + /obj/effect/decal/remains/human, + /obj/item/clothing/suit/chaplainsuit/armor/templar, + /obj/item/clothing/head/helmet/chaplain, + ), + ) + var/turf/death_turf = run_loc_floor_bottom_left + for(var/mob_type in mob_loot) + var/mob/living/basic/victim = allocate(mob_type, death_turf) + // Keep the original body to exercise the repeated-death guard safely. + victim.basic_mob_flags &= ~DEL_ON_DEATH + var/list/before_death = death_turf.get_all_contents() + var/list/expected_loot = mob_loot[mob_type].Copy() + if(istype(victim, /mob/living/basic/trooper/pirate/faction)) + expected_loot += list(/mob/living/carbon/human, /obj/item/holochip) + victim.death() + TEST_ASSERT_EQUAL(victim.stat, DEAD, "[mob_type] must actually die") + var/list/drops = death_turf.contents - before_death + for(var/drop_type in expected_loot) + var/count = 0 + for(var/atom/movable/drop in drops) + if(istype(drop, drop_type)) + count++ + TEST_ASSERT_EQUAL(count, 1, "[mob_type] must drop [drop_type] exactly once") + + var/expected_count = length(expected_loot) + if(istype(victim, /mob/living/basic/trooper/pirate/faction)) + var/mob/living/basic/trooper/pirate/faction/pirate = victim + var/is_boss = istype(pirate, /mob/living/basic/trooper/pirate/faction/boss) + var/obj/item/holochip/payment = locate() in drops + TEST_ASSERT_NOTNULL(payment, "[mob_type] must retain its credit drop") + TEST_ASSERT_EQUAL(payment.credits, is_boss ? 3000 : 1000, "[mob_type] must retain its payout") + if(!is_boss) + var/auxiliary_count = 0 + for(var/obj/item/drop in drops) + if(drop.type in pirate.random_loot_2) + auxiliary_count++ + TEST_ASSERT_EQUAL(auxiliary_count, 1, "[mob_type] must retain one auxiliary drop") + expected_count++ + TEST_ASSERT_EQUAL(length(drops), expected_count, "[mob_type] emitted extra or missing death drops") + var/list/all_drops = death_turf.get_all_contents() - before_death + for(var/obj/item/drop in all_drops) + TEST_ASSERT(!istype(drop, /obj/item/claymore/cutlass), "[mob_type] still drops a cutlass") + TEST_ASSERT(!istype(drop, /obj/item/claymore/weak), "[mob_type] still drops a holy sword") + + var/list/after_death = death_turf.get_all_contents() + victim.death() + TEST_ASSERT_EQUAL(length(death_turf.get_all_contents() - after_death), 0, "A repeated death call duplicated [mob_type]'s loot") + for(var/atom/movable/drop in drops) + qdel(drop) + qdel(victim) + /datum/unit_test/voidcrew_planetary_factions/Run() var/datum/space_level/test_level = SSmapping.z_list[run_loc_floor_bottom_left.z] if(!test_level) diff --git a/voidcrew/modules/vending/security.dm b/voidcrew/modules/vending/security.dm index 122df04adbc..bbbe38c08dd 100644 --- a/voidcrew/modules/vending/security.dm +++ b/voidcrew/modules/vending/security.dm @@ -50,7 +50,6 @@ /obj/item/grenade/frag = 5, /obj/item/grenade/flashbang = 5, /obj/item/grenade/barrier = 10, - /obj/item/melee/energy/sword/saber/blue = 1, ) voucher_items = list( "Tactical Energy Gun" = /obj/item/gun/energy/e_gun/stun, From c3de8d4461f91d50bf6563f4d754bfc59a8b150e Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:14:22 -0700 Subject: [PATCH 007/105] Scanner-controlled trader-outpost entrances --- .../outposts/trader_outpost_black_market.dmm | 94 ++++- .../outposts/trader_outpost_general.dmm | 70 +++- .../outposts/trader_outpost_outfitter.dmm | 113 +++++- voidcrew/modules/trade/outpost.dm | 11 + voidcrew/modules/trade/outpost_security.dm | 121 ++++++ .../unit_tests/voidcrew_outpost_safe_hubs.dm | 361 ++++++++++++++++++ 6 files changed, 735 insertions(+), 35 deletions(-) diff --git a/voidcrew/_maps/map_files/outposts/trader_outpost_black_market.dmm b/voidcrew/_maps/map_files/outposts/trader_outpost_black_market.dmm index 2840d9d2f44..81318a9005a 100644 --- a/voidcrew/_maps/map_files/outposts/trader_outpost_black_market.dmm +++ b/voidcrew/_maps/map_files/outposts/trader_outpost_black_market.dmm @@ -215,6 +215,13 @@ /obj/machinery/light/floor, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) +"ay" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "undertow_elevator"; + dir = 4 + }, +/turf/open/indestructible/dark/smooth_large, +/area/voidcrew/trader_outpost) "az" = ( /obj/effect/turf_decal/tile/dark_red/half/contrasted{ dir = 1 @@ -472,6 +479,13 @@ /obj/machinery/newscaster/directional/east, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) +"aX" = ( +/obj/machinery/door/airlock/outpost/checkpoint{ + checkpoint_id = "undertow_elevator"; + dir = 4 + }, +/turf/open/indestructible/dark/smooth_large, +/area/voidcrew/trader_outpost) "aY" = ( /obj/machinery/sleeper/outpost{ dir = 4 @@ -597,6 +611,38 @@ }, /turf/open/indestructible/dark/textured, /area/voidcrew/trader_outpost) +"bl" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "undertow_elevator"; + dir = 4 + }, +/obj/effect/landmark/outpost_elevator_alcove, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/turf/open/indestructible/dark/textured, +/area/voidcrew/trader_outpost) +"bm" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "undertow_bar"; + dir = 4 + }, +/obj/effect/turf_decal/trimline/dark_red/filled/warning{ + dir = 4 + }, +/obj/effect/turf_decal/tile/dark_red{ + dir = 1 + }, +/obj/effect/turf_decal/stripes{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wideplating_new/dark/corner{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wideplating_new/dark, +/obj/machinery/light/red/directional/south, +/turf/open/indestructible/dark, +/area/voidcrew/trader_outpost) "bn" = ( /obj/effect/turf_decal/siding/wideplating_new/dark{ dir = 8 @@ -607,6 +653,38 @@ /obj/structure/extinguisher_cabinet/directional/west, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) +"bo" = ( +/obj/machinery/door/airlock/outpost/checkpoint{ + checkpoint_id = "undertow_bar"; + dir = 4; + name = "Bar Gate" + }, +/obj/effect/turf_decal/bot, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wideplating_new/dark/corner{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wideplating_new/dark/corner{ + dir = 8 + }, +/obj/effect/turf_decal/stripes{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/plating, +/area/voidcrew/trader_outpost) +"bp" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "undertow_bar"; + dir = 4 + }, +/obj/structure/sign/warning/vacuum/external/directional/north, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/light/floor, +/turf/open/indestructible/plating, +/area/voidcrew/trader_outpost) "bz" = ( /obj/effect/turf_decal/siding/thinplating_new/dark, /obj/machinery/porta_turret/outpost, @@ -4668,7 +4746,7 @@ we aa aa aq -ar +ay Eu aV vn @@ -4701,9 +4779,9 @@ rw Si aa aa -ut -ar -au +aa +aX +aa aa vn aC @@ -4736,7 +4814,7 @@ al BJ aa bd -bc +bl bb aa vn @@ -4827,7 +4905,7 @@ tz an aH aD -DU +bm aa aa aa @@ -4861,7 +4939,7 @@ dW BL aa aa -ip +bo aa vn vn @@ -4895,7 +4973,7 @@ aa aa aa aa -vK +bp aa vn vn diff --git a/voidcrew/_maps/map_files/outposts/trader_outpost_general.dmm b/voidcrew/_maps/map_files/outposts/trader_outpost_general.dmm index 1ce457704a9..4d3818bc19e 100644 --- a/voidcrew/_maps/map_files/outposts/trader_outpost_general.dmm +++ b/voidcrew/_maps/map_files/outposts/trader_outpost_general.dmm @@ -329,6 +329,20 @@ /obj/machinery/light/floor, /turf/open/indestructible/large, /area/voidcrew/trader_outpost) +"aM" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "halcyon_elevator"; + dir = 2 + }, +/obj/effect/turf_decal/siding/wideplating_new/corner{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wideplating_new/corner{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "aN" = ( /obj/effect/turf_decal/siding/wideplating_new/dark{ dir = 9 @@ -349,6 +363,15 @@ /obj/structure/sign/departments/medbay/alt/directional/east, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) +"aP" = ( +/obj/machinery/door/airlock/outpost/checkpoint{ + checkpoint_id = "halcyon_elevator"; + dir = 2 + }, +/obj/effect/turf_decal/siding/thinplating_new, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "aQ" = ( /obj/structure/railing/unbreakable{ dir = 5 @@ -359,6 +382,17 @@ /obj/effect/turf_decal/tile/neutral/full, /turf/open/indestructible/large, /area/voidcrew/trader_outpost) +"aR" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "halcyon_elevator"; + dir = 2 + }, +/obj/effect/landmark/outpost_elevator_alcove, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/indestructible/dark/smooth_large, +/area/voidcrew/trader_outpost) "aS" = ( /obj/structure/chair/stool/directional/north, /obj/effect/turf_decal/trimline/neutral/filled/line{ @@ -7786,11 +7820,11 @@ aZ aY aY lf -aC -ad -ad -ad -aJ +ak +ak +ak +ak +ak dp WP aY @@ -7852,11 +7886,11 @@ ac aY aY GQ -Vv +ak al ah aa -zB +ak eK ac aY @@ -7917,12 +7951,12 @@ lU kE Or kE -Aa -Vv -at +aM +aP +aR aq an -Uo +ak dk kE Or @@ -7984,11 +8018,11 @@ WP aY aY GQ -Vv +ak aA ax av -zB +ak eK WP aY @@ -8050,11 +8084,11 @@ aZ aY aY aQ -aI -ib -ib -ib -aL +ak +ak +ak +ak +ak Md ac aY diff --git a/voidcrew/_maps/map_files/outposts/trader_outpost_outfitter.dmm b/voidcrew/_maps/map_files/outposts/trader_outpost_outfitter.dmm index 8e61e566b67..f8e4c5436b0 100644 --- a/voidcrew/_maps/map_files/outposts/trader_outpost_outfitter.dmm +++ b/voidcrew/_maps/map_files/outposts/trader_outpost_outfitter.dmm @@ -62,6 +62,15 @@ }, /turf/open/indestructible, /area/voidcrew/trader_outpost) +"aj" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "quartermain_west_yard"; + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/light/floor, +/turf/open/indestructible/plating, +/area/voidcrew/trader_outpost) "ak" = ( /obj/effect/landmark/outpost_elevator_alcove, /obj/effect/turf_decal/stripes/line{ @@ -251,6 +260,19 @@ /obj/structure/closet/crate, /turf/open/indestructible/dark/smooth_large, /area/voidcrew/trader_outpost) +"aI" = ( +/obj/machinery/door/airlock/outpost/checkpoint{ + checkpoint_id = "quartermain_west_yard"; + dir = 4; + name = "West Yard Gate" + }, +/obj/effect/turf_decal/bot, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/plating, +/area/voidcrew/trader_outpost) "aJ" = ( /obj/effect/turf_decal/tile/yellow/half/contrasted{ dir = 1 @@ -285,6 +307,18 @@ }, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) +"aM" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "quartermain_west_yard"; + dir = 4 + }, +/obj/effect/turf_decal/siding/thinplating_new, +/obj/effect/turf_decal/stripes{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/voidcrew/trader_outpost) "aN" = ( /obj/effect/turf_decal/stripes, /obj/effect/turf_decal/trimline/yellow/warning{ @@ -340,6 +374,14 @@ /obj/effect/decal/cleanable/dirt/dust, /turf/open/indestructible/plating, /area/voidcrew/trader_outpost) +"aS" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "quartermain_elevator"; + dir = 2 + }, +/obj/effect/turf_decal/stripes, +/turf/open/indestructible/dark, +/area/voidcrew/trader_outpost) "aT" = ( /obj/effect/turf_decal/trimline/red/filled/line{ dir = 8 @@ -403,6 +445,59 @@ /obj/effect/decal/cleanable/dirt, /turf/open/indestructible/white, /area/voidcrew/trader_outpost) +"ba" = ( +/obj/effect/turf_decal/bot, +/obj/machinery/door/airlock/outpost/checkpoint{ + checkpoint_id = "quartermain_elevator"; + dir = 2; + name = "Hangar Elevator" + }, +/turf/open/indestructible/dark/textured, +/area/voidcrew/trader_outpost) +"bb" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "quartermain_elevator"; + dir = 2 + }, +/obj/effect/landmark/outpost_elevator_alcove, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/indestructible/dark/textured, +/area/voidcrew/trader_outpost) +"bc" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "quartermain_east_yard"; + dir = 4 + }, +/obj/effect/turf_decal/stripes{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/dark, +/area/voidcrew/trader_outpost) +"bd" = ( +/obj/effect/turf_decal/bot, +/obj/machinery/door/airlock/outpost/checkpoint{ + checkpoint_id = "quartermain_east_yard"; + dir = 4; + name = "East Yard Gate" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/plating, +/area/voidcrew/trader_outpost) +"be" = ( +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ + checkpoint_id = "quartermain_east_yard"; + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/light/floor, +/turf/open/indestructible/plating, +/area/voidcrew/trader_outpost) "bf" = ( /obj/structure/closet/wardrobe/mixed, /obj/effect/turf_decal/siding/wideplating_new/dark{ @@ -4289,7 +4384,7 @@ aV aV aV dU -ZV +aj dU aV aV @@ -4331,7 +4426,7 @@ dU dU dU dU -aR +aI dU lE lE @@ -4373,7 +4468,7 @@ lw NJ lE dP -aP +aM HH HF HF @@ -4434,9 +4529,9 @@ aq KA ly ly -iT -LQ -aw +aS +ba +bb at as dU @@ -5277,7 +5372,7 @@ pA zN Cm Yo -xZ +bc WU dU aV @@ -5319,7 +5414,7 @@ dU dU dU dU -bO +bd dU dU aV @@ -5361,7 +5456,7 @@ aV aV aV dU -ZV +be dU aV aV diff --git a/voidcrew/modules/trade/outpost.dm b/voidcrew/modules/trade/outpost.dm index 34c152a40b2..8b5c0b460d5 100644 --- a/voidcrew/modules/trade/outpost.dm +++ b/voidcrew/modules/trade/outpost.dm @@ -209,6 +209,8 @@ GLOBAL_LIST_EMPTY(trader_outposts) ) if(!top_right) return + var/list/obj/machinery/door/airlock/outpost/checkpoint/checkpoint_doors = list() + var/list/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/checkpoint_scanners = list() for(var/turf/interior_turf as anything in block(template_bottom_left, top_right)) // block() iterates y-major then x, same order the hangar-side alcove // collects in, so the elevator can map alcove turf i to alcove turf i. @@ -230,6 +232,10 @@ GLOBAL_LIST_EMPTY(trader_outposts) else if(istype(machine, /obj/machinery/door/airlock/outpost)) var/obj/machinery/door/airlock/outpost/door = machine door.outpost = src + if(istype(door, /obj/machinery/door/airlock/outpost/checkpoint)) + checkpoint_doors += door + else if(istype(machine, /obj/machinery/scanner_gate/preset_guns/outpost_checkpoint)) + checkpoint_scanners += machine else if(istype(machine, /obj/machinery/outpost_elevator)) var/obj/machinery/outpost_elevator/panel = machine panel.outpost = src @@ -244,6 +250,11 @@ GLOBAL_LIST_EMPTY(trader_outposts) for(var/obj/fixture in interior_turf) if(ismachinery(fixture) || isstructure(fixture)) fixture.AddElement(/datum/element/outpost_property) + // Only machines collected from this concourse reservation can form a circuit. + for(var/obj/machinery/door/airlock/outpost/checkpoint/door as anything in checkpoint_doors) + for(var/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/scanner as anything in checkpoint_scanners) + if(door.checkpoint_id && door.checkpoint_id == scanner.checkpoint_id) + door.link_scanner(scanner) // The traders' names/appearances depend on their shops, so setup runs // post-link. In the roundstart pre-load path the mobs haven't initialized // yet, dressing the appearance dummy that early is unsafe, so those diff --git a/voidcrew/modules/trade/outpost_security.dm b/voidcrew/modules/trade/outpost_security.dm index fb00e560829..766141d126c 100644 --- a/voidcrew/modules/trade/outpost_security.dm +++ b/voidcrew/modules/trade/outpost_security.dm @@ -305,6 +305,127 @@ GLOBAL_DATUM_INIT(outpost_pvp_enforcement, /datum/outpost_pvp_enforcement, new) outpost.register_aggression(hitting_projectile.firer) return ..() +/// Trader entrance scanners retain Guns-mode storage shielding, but never exempt an ID or mindshield. +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint + name = "outpost scanner" + desc = "A sealed weapons scanner." + base_false_beep = 0 + move_resist = INFINITY + var/checkpoint_id + var/datum/weakref/checkpoint_door + +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/Initialize(mapload) + . = ..() + AddElement(/datum/element/outpost_property) + +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/Destroy() + var/obj/machinery/door/airlock/outpost/checkpoint/door = checkpoint_door?.resolve() + door?.unlink_scanner(src) + checkpoint_door = null + return ..() + +// ID swipes and emags must not unlock configuration. Tools still follow the property protection signals. +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers) + if(attacking_item.GetID()) + return TRUE + return ..() + +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/emag_act(mob/user, obj/item/card/emag/emag_card) + return FALSE + +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + return FALSE + +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/examine(mob/user) + // The base scanner appends configuration instructions that do not apply to this sealed model. + return list("[icon2html(src, user)] [name]", desc) + +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/proc/checkpoint_operational() + return !QDELETED(src) && anchored && !panel_open && !(machine_stat & (BROKEN | NOPOWER)) + +/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/perform_scan(atom/movable/thing) + if(!thing || !checkpoint_operational()) + return + // This is tg's recursive Guns search with only the personnel exemptions removed. + var/armed = isgun(thing) + if(!armed) + for(var/obj/item/content in thing.get_all_contents_skipping_traits(TRAIT_CONTRABAND_BLOCKER)) + if(isgun(content)) + armed = TRUE + break + playsound(src, SFX_INDUSTRIAL_SCAN, 20, TRUE, -2, TRUE, FALSE) + if(armed) + alarm_beep("Weapons") + SEND_SIGNAL(src, COMSIG_SCANGATE_PASS_TRIGGER, thing) + else + SEND_SIGNAL(src, COMSIG_SCANGATE_PASS_NO_TRIGGER, thing) + set_scanline("scanning", 1 SECONDS) + use_energy(active_power_usage) + +/// Permission is an argument to one immediate opening call; there is no stored clean result to rebuild or reuse. +/obj/machinery/door/airlock/outpost/checkpoint + name = "outpost checkpoint" + desc = "An armored checkpoint door." + move_resist = INFINITY + var/checkpoint_id + var/list/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/checkpoint_scanners = list() + +/obj/machinery/door/airlock/outpost/checkpoint/Initialize(mapload) + . = ..() + AddElement(/datum/element/outpost_property) + +/obj/machinery/door/airlock/outpost/checkpoint/Destroy() + for(var/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/scanner as anything in checkpoint_scanners.Copy()) + unlink_scanner(scanner) + return ..() + +/obj/machinery/door/airlock/outpost/checkpoint/proc/link_scanner(obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/scanner) + var/obj/structure/overmap/trader_outpost/host = outpost + if(!istype(host) || !host.reservation?.contains_turf(get_turf(src)) || !host.reservation.contains_turf(get_turf(scanner))) + return FALSE + if(!checkpoint_id || scanner.checkpoint_id != checkpoint_id || get_dist(src, scanner) != 1 || !(get_dir(src, scanner) in GLOB.cardinals)) + return FALSE + var/obj/machinery/door/airlock/outpost/checkpoint/old_door = scanner.checkpoint_door?.resolve() + old_door?.unlink_scanner(scanner) + checkpoint_scanners |= scanner + scanner.checkpoint_door = WEAKREF(src) + RegisterSignal(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, PROC_REF(on_clean_scan)) + return TRUE + +/obj/machinery/door/airlock/outpost/checkpoint/proc/unlink_scanner(obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/scanner) + UnregisterSignal(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER) + // A weakref already stops resolving once this door enters Destroy(). + if((scanner in checkpoint_scanners) || scanner.checkpoint_door?.resolve() == src) + scanner.checkpoint_door = null + checkpoint_scanners -= scanner + +/obj/machinery/door/airlock/outpost/checkpoint/proc/on_clean_scan(obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/scanner, atom/movable/thing) + SIGNAL_HANDLER + if(isliving(thing)) + INVOKE_ASYNC(src, PROC_REF(open), DEFAULT_DOOR_CHECKS, scanner, thing) + +/obj/machinery/door/airlock/outpost/checkpoint/open(forced = DEFAULT_DOOR_CHECKS, obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/scanner, mob/living/actor, safety_reopen = FALSE) + if(safety_reopen) + if(!safe || !(locate(/mob/living) in get_turf(src))) + return FALSE + else + var/obj/structure/overmap/trader_outpost/host = outpost + if(!istype(host) || !isliving(actor) || QDELETED(actor) || QDELETED(scanner) || !(scanner in checkpoint_scanners)) + return FALSE + if(scanner.checkpoint_door?.resolve() != src || !scanner.checkpoint_operational() || scanner.checkpoint_id != checkpoint_id) + return FALSE + if(!host.reservation?.contains_turf(get_turf(src)) || !host.reservation.contains_turf(get_turf(scanner))) + return FALSE + if(actor.loc != scanner.loc || get_dist(src, scanner) != 1 || !(get_dir(src, scanner) in GLOB.cardinals) || !allowed(actor)) + return FALSE + return ..(forced) + +/obj/machinery/door/airlock/outpost/checkpoint/CheckForMobs() + // A living obstruction arriving during the close animation must still be released. + if(safe && (locate(/mob/living) in get_turf(src))) + SLEEP_NOT_DEL(0.1 SECONDS) + open(safety_reopen = TRUE) + /** * # Outpost Wall * diff --git a/voidcrew/modules/unit_tests/voidcrew_outpost_safe_hubs.dm b/voidcrew/modules/unit_tests/voidcrew_outpost_safe_hubs.dm index 6c1d1cbd5ca..6d74b72c017 100644 --- a/voidcrew/modules/unit_tests/voidcrew_outpost_safe_hubs.dm +++ b/voidcrew/modules/unit_tests/voidcrew_outpost_safe_hubs.dm @@ -45,3 +45,364 @@ if(findtext(text, banned)) TEST_FAIL("[map_path] ([template_path]) places [banned], which spawns hostiles inside a trader outpost") TEST_ASSERT(checked, "No trader outpost map was checked") + +/// A small reserved concourse exercises the real linking pass without loading a whole market. +/datum/unit_test/voidcrew_trader_checkpoint + abstract_type = /datum/unit_test/voidcrew_trader_checkpoint + var/obj/structure/overmap/trader_outpost/host + var/obj/machinery/door/airlock/outpost/checkpoint/door + var/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/scanner + var/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/other_scanner + var/mob/living/carbon/human/actor + var/clean_signals = 0 + var/alarm_signals = 0 + +/datum/unit_test/voidcrew_trader_checkpoint/proc/fixture() + host = allocate(/obj/structure/overmap/trader_outpost/general) + host.outpost_template = new /datum/map_template/trader_outpost + host.outpost_template.width = 7 + host.outpost_template.height = 5 + host.reservation = SSmapping.request_turf_block_reservation(7, 5, 1) + TEST_ASSERT_NOTNULL(host.reservation, "Could not reserve the checkpoint fixture") + host.template_bottom_left = host.reservation.bottom_left_turfs[1] + var/turf/origin = host.template_bottom_left + for(var/turf/tile as anything in host.reservation.reserved_turfs) + tile.ChangeTurf(/turf/open/indestructible) + door = allocate(/obj/machinery/door/airlock/outpost/checkpoint, locate(origin.x + 3, origin.y + 2, origin.z)) + door.checkpoint_id = "test_checkpoint" + door.set_machine_stat(NONE) + scanner = allocate(/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint, get_step(door, WEST)) + scanner.checkpoint_id = door.checkpoint_id + scanner.set_machine_stat(NONE) + other_scanner = allocate(/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint, get_step(door, EAST)) + other_scanner.checkpoint_id = door.checkpoint_id + other_scanner.set_machine_stat(NONE) + host.link_interior_machinery() + scanner.set_machine_stat(NOPOWER) + actor = allocate(/mob/living/carbon/human, get_turf(scanner)) + scanner.set_machine_stat(NONE) + RegisterSignal(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, PROC_REF(clean_signal)) + RegisterSignal(scanner, COMSIG_SCANGATE_PASS_TRIGGER, PROC_REF(alarm_signal)) + TEST_ASSERT_EQUAL(length(door.checkpoint_scanners), 2, "The checkpoint did not link both scanners") + return TRUE + +/// Move the actor without also exercising the automatic turf-entry scan. +/datum/unit_test/voidcrew_trader_checkpoint/proc/move_actor(turf/destination) + var/old_stat = scanner.machine_stat + var/other_stat = other_scanner.machine_stat + scanner.set_machine_stat(NOPOWER) + other_scanner.set_machine_stat(NOPOWER) + actor.forceMove(destination) + scanner.set_machine_stat(old_stat) + other_scanner.set_machine_stat(other_stat) + +/datum/unit_test/voidcrew_trader_checkpoint/proc/clean_signal(datum/source, atom/movable/thing) + SIGNAL_HANDLER + clean_signals++ + +/datum/unit_test/voidcrew_trader_checkpoint/proc/alarm_signal(datum/source, atom/movable/thing) + SIGNAL_HANDLER + alarm_signals++ + +/datum/unit_test/voidcrew_trader_checkpoint/signals/Run() + TEST_ASSERT(fixture(), "Could not prepare the checkpoint") + SEND_SIGNAL(scanner, COMSIG_SCANGATE_PASS_TRIGGER, actor) + TEST_ASSERT(door.density && !door.operating, "An alarm opened the checkpoint") + var/obj/item/coin/coin = allocate(/obj/item/coin) + SEND_SIGNAL(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, coin) + TEST_ASSERT(door.density && !door.operating, "A clean item opened the checkpoint") + SEND_SIGNAL(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, actor) + TEST_ASSERT(door.operating, "A clean living scan did not immediately start opening") + sleep(2 SECONDS) + TEST_ASSERT(!door.density, "A clean scan did not open the checkpoint") + TEST_ASSERT(door.close(), "The checkpoint could not close after a clean scan") + TEST_ASSERT(!door.open(), "A prior clean result was reusable") + move_actor(get_turf(other_scanner)) + SEND_SIGNAL(other_scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, actor) + sleep(2 SECONDS) + TEST_ASSERT(!door.density, "The opposite scanner did not open the checkpoint") + TEST_ASSERT(door.autoclose && door.safe, "Checkpoint lost normal autoclose or safety") + // Wait for the inherited timer, with nobody on the doorway. + sleep(10 SECONDS) + TEST_ASSERT(door.density && !door.operating, "Checkpoint did not autoclose") + TEST_ASSERT(!door.open(), "Autoclose left a reusable scan permission") + +/datum/unit_test/voidcrew_trader_checkpoint/opening_routes/Run() + TEST_ASSERT(fixture(), "Could not prepare the checkpoint") + for(var/force_type in list(DEFAULT_DOOR_CHECKS, FORCING_DOOR_CHECKS, BYPASS_DOOR_CHECKS)) + TEST_ASSERT(!door.open(force_type), "Direct open([force_type]) bypassed the scanner") + door.bumpopen(actor) + TEST_ASSERT(door.density && !door.operating, "Bump-open bypassed the scanner") + actor.last_bumped = 0 + door.Bumped(actor) + TEST_ASSERT(door.density && !door.operating, "Living Bumped bypassed the scanner") + door.attack_hand(actor, list()) + TEST_ASSERT(door.density && !door.operating, "Hand activation bypassed the scanner") + door.try_to_activate_door(actor) + TEST_ASSERT(door.density && !door.operating, "Ordinary activation bypassed the scanner") + door.try_to_activate_door(actor, TRUE) + TEST_ASSERT(door.density && !door.operating, "Access-bypass activation bypassed the scanner") + var/obj/item/card/id/advanced/id = allocate(/obj/item/card/id/advanced) + id.access = list(ACCESS_WEAPONS, ACCESS_SECURITY) + door.attackby(id, actor, list(), list()) + TEST_ASSERT(door.density && !door.operating, "An ID swipe bypassed the scanner") + door.Bumped(id) + TEST_ASSERT(door.density && !door.operating, "A thrown ID bypassed the scanner") + door.emergency = TRUE + door.unres_sides = ALL_CARDINALS + door.try_to_activate_door(actor) + TEST_ASSERT(door.density && !door.operating, "Emergency access or unrestricted sides bypassed the scanner") + door.wires.on_pulse(WIRE_OPEN) + door.on_magic_unlock(get_turf(door), null, actor) + door.prison_open() + TEST_ASSERT(door.density && !door.operating, "Wire, magic, or prison opening bypassed the scanner") + door.unbolt() + door.attack_ai(actor) + TEST_ASSERT(door.density && !door.operating, "Silicon control bypassed the scanner") + // Exercise the actual control-wand and silicon toggle routes with their own checks satisfied. + var/obj/item/door_remote/omni/remote = allocate(/obj/item/door_remote/omni) + door.opens_with_door_remote = TRUE + door.aiControlDisabled = AI_WIRE_NORMAL + remote.ranged_interact_with_atom(door, actor, list()) + TEST_ASSERT(door.density && !door.operating, "A control wand bypassed the scanner") + var/mob/living/silicon/robot/robot = allocate(/mob/living/silicon/robot) + door.user_toggle_open(robot) + TEST_ASSERT(door.density && !door.operating, "A silicon UI toggle bypassed the scanner") + // A power-free pry takes the same BYPASS route used by tools, aliens and mechs. + var/obj/item/crowbar/crowbar = allocate(/obj/item/crowbar) + door.set_machine_stat(NOPOWER) + door.try_to_crowbar(crowbar, actor) + TEST_ASSERT(door.density && !door.operating, "An unpowered crowbar bypassed the scanner") + door.set_machine_stat(NONE) + door.finish_emag_act() + TEST_ASSERT(door.density && !door.operating, "Emag opening bypassed the scanner") + // These security state changes never create a stored clean result. + door.obj_flags &= ~EMAGGED + door.unbolt() + TEST_ASSERT(!door.open(BYPASS_DOOR_CHECKS), "Clearing an emag created permission") + +/datum/unit_test/voidcrew_trader_checkpoint/guns/Run() + TEST_ASSERT(fixture(), "Could not prepare the checkpoint") + var/obj/item/storage/backpack/bag = allocate(/obj/item/storage/backpack, actor) + var/obj/item/storage/box/box = allocate(/obj/item/storage/box, bag) + var/obj/item/gun/ballistic/automatic/pistol/gun = allocate(/obj/item/gun/ballistic/automatic/pistol, box) + scanner.perform_scan(actor) + TEST_ASSERT_EQUAL(alarm_signals, 1, "A nested gun did not trigger the scanner") + TEST_ASSERT_EQUAL(clean_signals, 0, "A nested gun produced a clean scan") + ADD_TRAIT(actor, TRAIT_MINDSHIELD, TRAIT_GENERIC) + scanner.perform_scan(actor) + TEST_ASSERT_EQUAL(alarm_signals, 2, "Mindshield exempted an armed human") + REMOVE_TRAIT(actor, TRAIT_MINDSHIELD, TRAIT_GENERIC) + var/obj/item/card/id/advanced/id = allocate(/obj/item/card/id/advanced) + id.access = list(ACCESS_WEAPONS) + actor.equip_to_slot_or_del(allocate(/obj/item/clothing/under/color/grey), ITEM_SLOT_ICLOTHING) + actor.equip_to_slot_or_del(id, ITEM_SLOT_ID) + TEST_ASSERT_EQUAL(actor.get_idcard(FALSE), id, "Weapon-access ID was not equipped") + scanner.perform_scan(actor) + TEST_ASSERT_EQUAL(alarm_signals, 3, "Weapon-access ID exempted an armed human") + ADD_TRAIT(actor, TRAIT_MINDSHIELD, TRAIT_GENERIC) + scanner.perform_scan(actor) + TEST_ASSERT_EQUAL(alarm_signals, 4, "Combined exemptions let a gun pass") + TEST_ASSERT(door.density && !door.operating, "An armed actor opened the checkpoint") + // The upstream scanner still has its own exemptions; this change is confined to our subtype. + var/obj/machinery/scanner_gate/preset_guns/upstream = allocate(/obj/machinery/scanner_gate/preset_guns, get_step(other_scanner, NORTH)) + upstream.base_false_beep = 0 + RegisterSignal(upstream, COMSIG_SCANGATE_PASS_NO_TRIGGER, PROC_REF(clean_signal)) + upstream.perform_scan(actor) + TEST_ASSERT_EQUAL(clean_signals, 1, "Upstream Guns-mode exemptions changed") + // Contraband-blocking containers keep tg's shielding semantics. + ADD_TRAIT(bag, TRAIT_CONTRABAND_BLOCKER, TRAIT_GENERIC) + scanner.perform_scan(actor) + TEST_ASSERT_EQUAL(clean_signals, 2, "Contraband-blocking storage lost tg shielding") + sleep(2 SECONDS) + TEST_ASSERT(!door.density, "A tg-shielded inventory was not clean") + TEST_ASSERT(door.close(), "Could not close the checkpoint after a shielded scan") + REMOVE_TRAIT(bag, TRAIT_CONTRABAND_BLOCKER, TRAIT_GENERIC) + gun.forceMove(get_step(scanner, NORTH)) + scanner.perform_scan(gun) + TEST_ASSERT_EQUAL(alarm_signals, 5, "A loose gun was not detected") + box.forceMove(get_step(scanner, NORTH)) + gun.forceMove(box) + scanner.perform_scan(box) + TEST_ASSERT_EQUAL(alarm_signals, 6, "A gun in a nonhuman container was not detected") + TEST_ASSERT(door.density && !door.operating, "Scanning an object opened the checkpoint") + TEST_ASSERT_EQUAL(scanner.base_false_beep, 0, "Checkpoint has random false results") + TEST_ASSERT(scanner.locked, "Checkpoint configuration starts unlocked") + scanner.attackby(id, actor, list(), list()) + scanner.emag_act(actor, null) + scanner.ui_act("toggle_lock", list(), null, null) + scanner.ui_act("set_mode", list("new_mode" = "Off"), null, null) + scanner.ui_act("toggle_reverse", list(), null, null) + TEST_ASSERT(scanner.locked && !scanner.reverse && scanner.scangate_mode == "Guns", "Checkpoint configuration could be changed") + // Repeated scans must be deterministic, including when higher-tier parts change the modifier. + scanner.minus_false_beep = 5 + for(var/i in 1 to 20) + scanner.perform_scan(actor) + TEST_ASSERT_EQUAL(alarm_signals, 6, "An unarmed scan randomly alarmed") + TEST_ASSERT_EQUAL(clean_signals, 22, "An unarmed scan randomly failed") + +/datum/unit_test/voidcrew_trader_checkpoint/unavailable/Run() + TEST_ASSERT(fixture(), "Could not prepare the checkpoint") + for(var/bad_stat in list(BROKEN, NOPOWER, BROKEN | NOPOWER)) + scanner.set_machine_stat(bad_stat) + scanner.auto_scan(actor) + scanner.perform_scan(actor) + SEND_SIGNAL(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, actor) + TEST_ASSERT(door.density && !door.operating, "A scanner with status [bad_stat] granted entry") + scanner.set_machine_stat(NONE) + scanner.panel_open = TRUE + scanner.auto_scan(actor) + SEND_SIGNAL(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, actor) + TEST_ASSERT(door.density && !door.operating, "An open-panel scanner granted entry") + scanner.panel_open = FALSE + scanner.set_anchored(FALSE) + SEND_SIGNAL(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, actor) + TEST_ASSERT(door.density && !door.operating, "An unanchored scanner granted entry") + scanner.set_anchored(TRUE) + door.unlink_scanner(scanner) + SEND_SIGNAL(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, actor) + TEST_ASSERT(door.density && !door.operating, "An unlinked scanner granted entry") + TEST_ASSERT_EQUAL(length(door.checkpoint_scanners), 1, "Unlink left a scanner reference") + TEST_ASSERT(door.link_scanner(scanner), "Could not relink the scanner") + move_actor(get_step(scanner, NORTH)) + SEND_SIGNAL(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, actor) + TEST_ASSERT(door.density && !door.operating, "A remote actor granted entry") + move_actor(get_turf(scanner)) + scanner.checkpoint_id = "wrong_checkpoint" + SEND_SIGNAL(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, actor) + TEST_ASSERT(door.density && !door.operating, "A changed scanner ID granted entry") + scanner.checkpoint_id = door.checkpoint_id + qdel(scanner) + TEST_ASSERT_EQUAL(length(door.checkpoint_scanners), 1, "Deleted scanner stayed linked") + scanner = allocate(/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint, get_step(door, WEST)) + scanner.checkpoint_id = door.checkpoint_id + scanner.set_machine_stat(NONE) + TEST_ASSERT_NULL(scanner.checkpoint_door, "Rebuilt scanner inherited a link") + TEST_ASSERT(!door.open(), "Rebuilding granted entry") + SEND_SIGNAL(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, actor) + TEST_ASSERT(door.density && !door.operating, "A rebuilt, unlinked scanner granted entry") + TEST_ASSERT(door.link_scanner(scanner), "Rebuilt scanner could not be deliberately linked") + qdel(door) + TEST_ASSERT_NULL(scanner.checkpoint_door, "Deleted door left a scanner link") + door = allocate(/obj/machinery/door/airlock/outpost/checkpoint, get_step(scanner, EAST)) + door.checkpoint_id = scanner.checkpoint_id + TEST_ASSERT(!door.open(), "Rebuilt door inherited permission") + +/datum/unit_test/voidcrew_trader_checkpoint/reservation_scope/Run() + TEST_ASSERT(fixture(), "Could not prepare the checkpoint") + var/obj/structure/overmap/trader_outpost/other_host = allocate(/obj/structure/overmap/trader_outpost/general) + other_host.outpost_template = new /datum/map_template/trader_outpost + other_host.outpost_template.width = 3 + other_host.outpost_template.height = 3 + other_host.reservation = SSmapping.request_turf_block_reservation(3, 3, 1, host.template_bottom_left.z) + TEST_ASSERT_NOTNULL(other_host.reservation, "Could not reserve the other concourse") + other_host.template_bottom_left = other_host.reservation.bottom_left_turfs[1] + var/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/foreign = allocate(/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint, other_host.template_bottom_left) + foreign.checkpoint_id = door.checkpoint_id + other_host.link_interior_machinery() + host.link_interior_machinery() + TEST_ASSERT_NULL(foreign.checkpoint_door, "A matching ID linked across reservations") + TEST_ASSERT(!door.link_scanner(foreign), "Direct linking crossed reservation boundaries") + TEST_ASSERT_EQUAL(length(door.checkpoint_scanners), 2, "Relinking duplicated the local circuit") + TEST_ASSERT_EQUAL(host.template_bottom_left.z, other_host.template_bottom_left.z, "Scope fixture did not exercise a shared z-level") + move_actor(get_turf(scanner)) + SEND_SIGNAL(foreign, COMSIG_SCANGATE_PASS_NO_TRIGGER, actor) + TEST_ASSERT(door.density && !door.operating, "A foreign scanner opened this outpost's door") + +/datum/unit_test/voidcrew_trader_checkpoint/obstruction_safety/Run() + TEST_ASSERT(fixture(), "Could not prepare the checkpoint") + SEND_SIGNAL(scanner, COMSIG_SCANGATE_PASS_NO_TRIGGER, actor) + sleep(2 SECONDS) + TEST_ASSERT(!door.density, "The safety fixture never opened") + move_actor(get_turf(door)) + TEST_ASSERT(!door.close(), "Checkpoint closed on a dense obstruction") + TEST_ASSERT(!door.density, "Checkpoint obstructed a living actor") + move_actor(get_turf(scanner)) + TEST_ASSERT(door.close(), "Checkpoint could not close after the obstruction moved") + // Simulate an actor arriving in the closing animation: inherited CheckForMobs must reopen. + move_actor(get_turf(door)) + door.CheckForMobs() + TEST_ASSERT(!door.density, "Checkpoint safety could not reopen without a scan") + move_actor(get_turf(scanner)) + TEST_ASSERT(door.close(), "Safety reopen prevented later closing") + TEST_ASSERT(!door.open(), "Safety reopen left permission for an ordinary opening") + +/// Load all three templates and verify the six actual linked circuits, alcoves and approaches. +/datum/unit_test/voidcrew_trader_checkpoint_maps/Run() + var/list/circuits = list( + /obj/structure/overmap/trader_outpost/general = list(list(38, 34, NORTH, 37, 31)), + /obj/structure/overmap/trader_outpost/outfitter = list(list(15, 10, NORTH, 14, 7), list(13, 30, EAST), list(36, 8, EAST)), + /obj/structure/overmap/trader_outpost/black_market = list(list(29, 7, EAST, 30, 6), list(34, 18, EAST)), + ) + var/checked = 0 + for(var/host_type in circuits) + var/obj/structure/overmap/trader_outpost/market = allocate(host_type) + TEST_ASSERT(market.load_level(), "Could not load [host_type]") + var/turf/origin = market.template_bottom_left + var/list/entries = circuits[host_type] + for(var/list/entry as anything in entries) + var/turf/door_turf = locate(origin.x + entry[1] - 1, origin.y + entry[2] - 1, origin.z) + var/obj/machinery/door/airlock/outpost/checkpoint/checkpoint = locate() in door_turf + TEST_ASSERT_NOTNULL(checkpoint, "[host_type] is missing its checkpoint at [entry[1]],[entry[2]]") + TEST_ASSERT_EQUAL(checkpoint.outpost, market, "Mapped checkpoint linked to the wrong host") + TEST_ASSERT_EQUAL(length(checkpoint.checkpoint_scanners), 2, "Mapped checkpoint does not have two scanners") + TEST_ASSERT(HAS_TRAIT(checkpoint, "outpost_property"), "Mapped checkpoint lost property protection") + for(var/direction in list(entry[3], turn(entry[3], 180))) + var/turf/approach = get_step(door_turf, direction) + TEST_ASSERT(isopenturf(approach), "Mapped checkpoint has a closed approach") + var/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/gate = locate() in approach + TEST_ASSERT_NOTNULL(gate, "Mapped checkpoint is missing an approach scanner") + TEST_ASSERT(gate in checkpoint.checkpoint_scanners, "Mapped approach scanner is not in the circuit") + TEST_ASSERT_EQUAL(gate.checkpoint_door?.resolve(), checkpoint, "Mapped scanner points at the wrong door") + TEST_ASSERT(HAS_TRAIT(gate, "outpost_property"), "Mapped scanner lost property protection") + for(var/atom/movable/blocker in approach) + TEST_ASSERT(!blocker.density, "[blocker] blocks a checkpoint approach") + var/mob/living/carbon/human/rider = allocate(/mob/living/carbon/human, approach) + gate.perform_scan(rider) + sleep(2 SECONDS) + TEST_ASSERT(!checkpoint.density, "A mapped circuit did not open from direction [direction]") + qdel(rider) + TEST_ASSERT(checkpoint.close(), "A mapped checkpoint could not close") + TEST_ASSERT(!checkpoint.open(), "A mapped checkpoint cached a scan") + if(length(entry) >= 5) + TEST_ASSERT_EQUAL(length(market.lobby_alcove_turfs), 9, "Elevator lost a landing tile") + var/index = 0 + for(var/y_offset in 0 to 2) + for(var/x_offset in 0 to 2) + var/turf/landing = locate(origin.x + entry[4] + x_offset - 1, origin.y + entry[5] + y_offset - 1, origin.z) + TEST_ASSERT_EQUAL(market.lobby_alcove_turfs[++index], landing, "Elevator landing order changed") + TEST_ASSERT(isopenturf(landing), "Elevator landing was walled over") + TEST_ASSERT_EQUAL(length(market.lobby_panels), 1, "Elevator panel disappeared") + var/obj/machinery/outpost_elevator/panel = market.lobby_panels[1] + TEST_ASSERT_EQUAL(panel.get_own_alcove(), market.lobby_alcove_turfs, "Elevator panel lost its ordered landing") + check_elevator_travel(market, panel) + checked++ + TEST_ASSERT_EQUAL(checked, 6, "Did not check all six trader entrances") + +/// Move nine passengers down and back through the real elevator proc, retaining their tile order. +/datum/unit_test/voidcrew_trader_checkpoint_maps/proc/check_elevator_travel(obj/structure/overmap/trader_outpost/market, obj/machinery/outpost_elevator/lobby_panel) + var/datum/outpost_berth/berth = new(market, 1, null) + market.berths[1] = berth + berth.reservation = SSmapping.request_turf_block_reservation(3, 3, 1) + TEST_ASSERT_NOTNULL(berth.reservation, "Could not reserve an elevator destination") + for(var/turf/tile as anything in block(berth.reservation.bottom_left_turfs[1], berth.reservation.top_right_turfs[1])) + berth.alcove_turfs += tile.ChangeTurf(/turf/open/indestructible) + berth.panel = new /obj/machinery/outpost_elevator(berth.alcove_turfs[1]) + berth.panel.outpost = market + berth.panel.berth = berth + var/list/obj/item/coin/passengers = list() + for(var/turf/landing as anything in market.lobby_alcove_turfs) + passengers += allocate(/obj/item/coin, landing) + var/mob/living/carbon/human/rider = allocate(/mob/living/carbon/human, market.lobby_alcove_turfs[5]) + lobby_panel.complete_ride(1, WEAKREF(rider)) + for(var/i in 1 to 9) + TEST_ASSERT_EQUAL(get_turf(passengers[i]), berth.alcove_turfs[i], "Elevator changed the outgoing tile order") + TEST_ASSERT_EQUAL(get_turf(rider), berth.alcove_turfs[5], "Elevator did not carry the rider down") + berth.panel.complete_ride(0, WEAKREF(rider)) + for(var/i in 1 to 9) + TEST_ASSERT_EQUAL(get_turf(passengers[i]), market.lobby_alcove_turfs[i], "Elevator changed the returning tile order") + TEST_ASSERT_EQUAL(get_turf(rider), market.lobby_alcove_turfs[5], "Elevator did not return the rider") + qdel(rider) + for(var/obj/item/coin/passenger as anything in passengers) + qdel(passenger) + qdel(berth) From 143c74a5955fa268c5b58ea925bf7fed5b34b4e6 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:22:28 -0700 Subject: [PATCH 008/105] Replace dead map item paths --- _maps/voidcrew/ships/ship_box.dmm | 4 ++-- _maps/voidcrew/ships/ship_dwayne.dmm | 2 +- _maps/voidcrew/ships/ship_energia.dmm | 2 +- _maps/voidcrew/ships/ship_lamia.dmm | 2 +- _maps/voidcrew/ships/ship_libertatia.dmm | 4 ++-- _maps/voidcrew/ships/ship_luxembourg.dmm | 4 ++-- _maps/voidcrew/ships/ship_mechaton.dmm | 2 +- _maps/voidcrew/ships/ship_nano_bead.dmm | 2 +- _maps/voidcrew/ships/ship_nano_thunderbird.dmm | 2 +- _maps/voidcrew/ships/ship_osprey.dmm | 2 +- voidcrew/modules/unit_tests/voidcrew_ship_hulls.dm | 12 ++++++++++++ 11 files changed, 25 insertions(+), 13 deletions(-) diff --git a/_maps/voidcrew/ships/ship_box.dmm b/_maps/voidcrew/ships/ship_box.dmm index 5be575c17c5..0f73e4b5567 100644 --- a/_maps/voidcrew/ships/ship_box.dmm +++ b/_maps/voidcrew/ships/ship_box.dmm @@ -58,7 +58,7 @@ /obj/item/storage/belt/medical, /obj/item/storage/belt/medical, /obj/item/reagent_containers/spray/cleaner, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/storage/medkit/surgery, /obj/machinery/light/directional/west, /turf/open/floor/iron/dark, /area/shuttle/voidcrew/box/medbay) @@ -1091,7 +1091,7 @@ /area/shuttle/voidcrew/box/medbay) "mE" = ( /obj/structure/table/glass, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/storage/medkit/surgery, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, diff --git a/_maps/voidcrew/ships/ship_dwayne.dmm b/_maps/voidcrew/ships/ship_dwayne.dmm index 9cb63908af5..1a95a32feed 100644 --- a/_maps/voidcrew/ships/ship_dwayne.dmm +++ b/_maps/voidcrew/ships/ship_dwayne.dmm @@ -374,7 +374,7 @@ }, /obj/structure/table, /obj/item/book/manual/wiki/surgery, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/storage/medkit/surgery, /obj/item/clothing/mask/surgical, /obj/item/clothing/suit/apron/surgical, /obj/item/clothing/gloves/latex/nitrile, diff --git a/_maps/voidcrew/ships/ship_energia.dmm b/_maps/voidcrew/ships/ship_energia.dmm index c7a65d57b8c..4ff45f4296d 100644 --- a/_maps/voidcrew/ships/ship_energia.dmm +++ b/_maps/voidcrew/ships/ship_energia.dmm @@ -637,7 +637,7 @@ /area/shuttle/voidcrew/energia/maintenance) "IZ" = ( /obj/structure/table/reinforced, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/storage/medkit/surgery, /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron, /area/shuttle/voidcrew/energia/medbay) diff --git a/_maps/voidcrew/ships/ship_lamia.dmm b/_maps/voidcrew/ships/ship_lamia.dmm index 14f9f47e76f..08181d8ab4b 100644 --- a/_maps/voidcrew/ships/ship_lamia.dmm +++ b/_maps/voidcrew/ships/ship_lamia.dmm @@ -350,7 +350,7 @@ /obj/item/storage/medkit/regular, /obj/item/storage/medkit/o2, /obj/item/storage/medkit/toxin, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/storage/medkit/surgery, /obj/machinery/power/apc/auto_name/directional/west, /obj/structure/cable, /turf/open/floor/iron, diff --git a/_maps/voidcrew/ships/ship_libertatia.dmm b/_maps/voidcrew/ships/ship_libertatia.dmm index ba8fddfb33b..599f196dddd 100644 --- a/_maps/voidcrew/ships/ship_libertatia.dmm +++ b/_maps/voidcrew/ships/ship_libertatia.dmm @@ -93,7 +93,7 @@ pixel_x = 5; pixel_y = -5 }, -/obj/item/storage/belt/sabre, +/obj/item/storage/belt/sheath/sabre, /obj/effect/decal/cleanable/dirt/dust, /obj/item/gun/ballistic/revolver/c38, /turf/open/floor/pod/light, @@ -632,7 +632,7 @@ /obj/machinery/vending/wallmed{ pixel_y = 30 }, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/storage/medkit/surgery, /obj/item/clothing/mask/surgical, /obj/item/clothing/suit/apron/surgical, /obj/structure/sign/departments/medbay/alt/directional/west, diff --git a/_maps/voidcrew/ships/ship_luxembourg.dmm b/_maps/voidcrew/ships/ship_luxembourg.dmm index ca2a4df136a..c26f2eaebfb 100644 --- a/_maps/voidcrew/ships/ship_luxembourg.dmm +++ b/_maps/voidcrew/ships/ship_luxembourg.dmm @@ -109,7 +109,7 @@ /obj/item/storage/box/syndie_kit/chameleon, /obj/item/card/id/advanced/black/syndicate_command, /obj/item/card/emag, -/obj/item/storage/belt/sabre, +/obj/item/storage/belt/sheath/sabre, /obj/item/gun/energy/recharge/kinetic_accelerator, /obj/item/tank/internals/emergency_oxygen/double, /obj/item/clothing/under/syndicate, @@ -296,7 +296,7 @@ /obj/machinery/light{ dir = 4 }, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/storage/medkit/surgery, /turf/open/floor/iron/dark, /area/shuttle/voidcrew/luxembourg/medbay) "gM" = ( diff --git a/_maps/voidcrew/ships/ship_mechaton.dmm b/_maps/voidcrew/ships/ship_mechaton.dmm index fe807ebf90f..bb90e6492d0 100644 --- a/_maps/voidcrew/ships/ship_mechaton.dmm +++ b/_maps/voidcrew/ships/ship_mechaton.dmm @@ -642,7 +642,7 @@ /obj/structure/cable, /obj/effect/decal/cleanable/dirt/dust, /obj/structure/table/reinforced, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/storage/medkit/surgery, /turf/open/floor/iron/dark, /area/shuttle/voidcrew/mechaton/robotics) "Dc" = ( diff --git a/_maps/voidcrew/ships/ship_nano_bead.dmm b/_maps/voidcrew/ships/ship_nano_bead.dmm index d7c861a068b..cf9f305971a 100644 --- a/_maps/voidcrew/ships/ship_nano_bead.dmm +++ b/_maps/voidcrew/ships/ship_nano_bead.dmm @@ -979,7 +979,7 @@ /obj/structure/cable, /obj/machinery/power/apc/auto_name/directional/east, /obj/structure/table/reinforced/rglass, -/obj/item/storage/backpack/duffelbag/med/surgery{ +/obj/item/storage/medkit/surgery{ pixel_y = 14 }, /obj/item/storage/medkit{ diff --git a/_maps/voidcrew/ships/ship_nano_thunderbird.dmm b/_maps/voidcrew/ships/ship_nano_thunderbird.dmm index 73abf9e03ab..f1d29a8a686 100644 --- a/_maps/voidcrew/ships/ship_nano_thunderbird.dmm +++ b/_maps/voidcrew/ships/ship_nano_thunderbird.dmm @@ -500,7 +500,7 @@ /area/shuttle/voidcrew/thunderbird/security/armory) "Fc" = ( /obj/structure/table/reinforced, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/storage/medkit/surgery, /obj/effect/turf_decal/tile/blue, /turf/open/floor/mineral/titanium, /area/shuttle/voidcrew/thunderbird/dormitories) diff --git a/_maps/voidcrew/ships/ship_osprey.dmm b/_maps/voidcrew/ships/ship_osprey.dmm index 72fd61c6eaa..89b4d3f89ff 100644 --- a/_maps/voidcrew/ships/ship_osprey.dmm +++ b/_maps/voidcrew/ships/ship_osprey.dmm @@ -4210,7 +4210,7 @@ /obj/effect/turf_decal/trimline/dark_blue/warning, /obj/effect/turf_decal/siding/thinplating_new/light, /obj/structure/table/glass, -/obj/item/storage/backpack/duffelbag/med/surgery{ +/obj/item/storage/medkit/surgery{ pixel_x = -3; pixel_y = 13 }, diff --git a/voidcrew/modules/unit_tests/voidcrew_ship_hulls.dm b/voidcrew/modules/unit_tests/voidcrew_ship_hulls.dm index 1027b39db5a..7a1054560e6 100644 --- a/voidcrew/modules/unit_tests/voidcrew_ship_hulls.dm +++ b/voidcrew/modules/unit_tests/voidcrew_ship_hulls.dm @@ -386,4 +386,16 @@ SSshuttle.unload_preview() TEST_ASSERT(checked >= 5, "only [checked] purchasable hulls were checked for port overhang") +/// Replacement storage paths used by legacy hulls must spawn their supplies during initialization. +/datum/unit_test/voidcrew_hull_storage_contents + +/datum/unit_test/voidcrew_hull_storage_contents/Run() + var/list/storage_types = list( + /obj/item/storage/belt/sheath/sabre, + /obj/item/storage/medkit/surgery, + ) + for(var/storage_type in storage_types) + var/obj/item/storage/container = allocate(storage_type) + TEST_ASSERT(length(container.contents) > 0, "[storage_type] spawned without supplies") + #undef SHIP_MODULE_MAP_ROOT From 262f316187bc0578cdbf0ce3c9ea94f6e8e50b9e Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:36:18 -0700 Subject: [PATCH 009/105] Random ore, finite asteroid fields and finite vents --- .../objects/structures/lavaland/ore_vent.dm | 52 ++- code/game/turfs/closed/minerals.dm | 25 +- tgstation.dme | 2 + voidcrew/_DEFINES/overmap_zones.dm | 4 - .../datums/mapgen/Cavegens/AsteroidCaves.dm | 8 +- voidcrew/modules/mining/ore_profiles.dm | 101 +++++ voidcrew/modules/mining/ore_vents.dm | 143 +++++++ .../overmap/code/modules/overmap/events.dm | 151 ++------ .../code/modules/overmap/generation.dm | 20 + voidcrew/modules/unit_tests/_unit_tests.dm | 1 + .../unit_tests/voidcrew_ore_balance.dm | 364 ++++++++++++++++++ voidcrew/turfs/closed/minerals.dm | 54 +-- 12 files changed, 704 insertions(+), 221 deletions(-) create mode 100644 voidcrew/modules/mining/ore_profiles.dm create mode 100644 voidcrew/modules/mining/ore_vents.dm create mode 100644 voidcrew/modules/unit_tests/voidcrew_ore_balance.dm diff --git a/code/game/objects/structures/lavaland/ore_vent.dm b/code/game/objects/structures/lavaland/ore_vent.dm index 0a51fdfa612..97dc3a16d33 100644 --- a/code/game/objects/structures/lavaland/ore_vent.dm +++ b/code/game/objects/structures/lavaland/ore_vent.dm @@ -6,7 +6,7 @@ /obj/structure/ore_vent name = "ore vent" - desc = "An ore vent, brimming with underground ore. Scan with an advanced mining scanner to start extracting ore from it." + desc = "A fissure brimming with underground ore." // VOIDCREW EDIT: keep descriptions in character. icon = 'icons/obj/mining_zones/terrain.dmi' icon_state = "ore_vent" base_icon_state = "ore_vent" @@ -116,15 +116,15 @@ if(!HAS_TRAIT(user, TRAIT_BOULDER_BREAKER)) return if(!discovered) - to_chat(user, span_notice("You can't quite find the weakpoint of [src]... Perhaps it needs to be scanned first?")) + to_chat(user, span_notice("You can't find a weak point in [src].")) // VOIDCREW EDIT: omit scanner instructions. return to_chat(user, span_notice("You start striking [src] with your golem's fist, attempting to dredge up a boulder...")) for(var/i in 1 to 3) if(do_after(user, boulder_size * 1 SECONDS, src)) user.apply_damage(20, STAMINA) playsound(src, 'sound/items/weapons/genhit.ogg', 50, TRUE) - produce_boulder(TRUE) - visible_message(span_notice("You've successfully produced a boulder! Boy are your arms tired.")) + if(produce_boulder(TRUE)) // VOIDCREW EDIT: exhausted vents produce nothing. + visible_message(span_notice("A boulder breaks free!")) /obj/structure/ore_vent/attack_basic_mob(mob/user, list/modifiers) . = ..() @@ -148,8 +148,7 @@ . += span_notice("This vent produces [span_bold("medium")] boulders containing [ore_string]") if(BOULDER_SIZE_LARGE) . += span_notice("This vent produces [span_bold("large")] boulders containing [ore_string]") - else - . += span_notice("This vent can be scanned with a [span_bold("Mining Scanner")].") + // VOIDCREW EDIT: omit scanner instructions. /obj/structure/ore_vent/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) if(is_type_in_list(held_item, scanning_equipment)) @@ -160,7 +159,8 @@ * This proc is called when the ore vent is initialized, in order to determine what minerals boulders it spawns can contain. * The materials available are determined by SSore_generation.ore_vent_minerals, which is a list of all minerals that can be contained in ore vents for a given cave generation. * As a result, minerals use a weighted list as seen by ore_vent_minerals_lavaland, which is then copied to ore_vent_minerals. - * Once a material is picked from the weighted list, it's removed from ore_vent_minerals, so that it can't be picked again and provided its own internal weight used when assigning minerals to boulders spawned by this vent. + * VOIDCREW EDIT: each weighted pick spends one allocation; only exhausted entries are removed. + * The selected material gets its own internal weight for this vent's boulders. * May also be called after the fact, as seen in SSore_generation's initialize, to add more minerals to an existing vent. * * The above applies only when spawning in at mapload, otherwise we pick randomly from ore_vent_minerals_lavaland. @@ -171,25 +171,13 @@ /obj/structure/ore_vent/proc/generate_mineral_breakdown(new_minerals = MINERAL_TYPE_OPTIONS_RANDOM, map_loading = FALSE) if(new_minerals < 1) CRASH("generate_mineral_breakdown called with new_minerals < 1.") - var/list/available_mats = difflist(first = SSore_generation.ore_vent_minerals, second = mineral_breakdown, skiprep = 1) + // VOIDCREW EDIT ADDITION START - weighted, finite allocation (mining/ore_vents.dm). for(var/i in 1 to new_minerals) - if(!length(SSore_generation.ore_vent_minerals) && map_loading) - // We should prevent this from happening in SSore_generation, but if not then we crash here - CRASH("No minerals left to pick from! We may have spawned too many ore vents in init, or the map config in seedRuins may not have enough resources for the mineral budget.") - var/datum/material/new_material - if(map_loading) - if(length(available_mats)) - new_material = pick(GLOB.ore_vent_minerals_lavaland) - var/datum/material/surrogate_mat = pick(SSore_generation.ore_vent_minerals) - available_mats -= surrogate_mat - SSore_generation.ore_vent_minerals -= surrogate_mat - else - new_material = pick(available_mats) - available_mats -= new_material - SSore_generation.ore_vent_minerals -= new_material - else - new_material = pick(GLOB.ore_vent_minerals_lavaland) + var/new_material = select_vent_mineral(map_loading) + if(isnull(new_material)) + break mineral_breakdown[new_material] = rand(1, 4) + // VOIDCREW EDIT ADDITION END /** @@ -417,6 +405,17 @@ return // VOIDCREW EDIT END + // VOIDCREW EDIT ADDITION START - prepare and debit both finite limits before emission. + if(!can_produce_ore()) + return + var/list/mats_list = list() + for(var/iteration in 1 to MINERALS_PER_BOULDER) + var/datum/material/material = pick_weight(mineral_breakdown) + mats_list[material] += ore_quantity_function(iteration) + if(!commit_ore_payload(mats_list)) + return + // VOIDCREW EDIT ADDITION END + //produce the boulder var/obj/item/boulder/new_rock if(prob(artifact_chance)) @@ -425,11 +424,6 @@ new_rock = new /obj/item/boulder(loc) Shake(duration = 1.5 SECONDS) - //decorate the boulder with materials - var/list/mats_list = list() - for(var/iteration in 1 to MINERALS_PER_BOULDER) - var/datum/material/material = pick_weight(mineral_breakdown) - mats_list[material] += ore_quantity_function(iteration) new_rock.set_custom_materials(mats_list) //set size & durability diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm index 9d198d1983c..b7ec424fb0e 100644 --- a/code/game/turfs/closed/minerals.dm +++ b/code/game/turfs/closed/minerals.dm @@ -92,8 +92,12 @@ M.Change_Ore(mineralType) /turf/closed/mineral/proc/Change_Ore(ore_type, random = 0) - if(random) + // VOIDCREW EDIT ADDITION START - ordinary ore ranges also apply to vein spreading. + if(is_ordinary_ore(ore_type)) + mineralAmt = ordinary_ore_amount(ore_type) + else if(random) mineralAmt = rand(1, 5) + // VOIDCREW EDIT ADDITION END if(ispath(ore_type, /obj/item/stack/ore)) //If it has a scan_state, switch to it var/obj/item/stack/ore/the_ore = ore_type scan_state = initial(the_ore.scan_state) // I SAID. SWITCH. TO. IT. @@ -230,7 +234,6 @@ if(istype(user)) SEND_SIGNAL(user, COMSIG_MOB_MINED, src, exp_multiplier) if(mineralType && (mineralAmt > 0)) - mineralAmt = zone_scaled_ore_amount(mineralAmt) // VOIDCREW EDIT: deeper-zone planets yield more ore per wall (see voidcrew/turfs/closed/minerals.dm) new mineralType(src, mineralAmt) SSblackbox.record_feedback("tally", "ore_mined", mineralAmt, mineralType) if(spawned_boulder) @@ -315,17 +318,11 @@ ) /turf/closed/mineral/random/Initialize(mapload) - var/static/list/mineral_chances_by_type = list() - . = ..() - var/dynamic_prob = mineralChance - if(proximity_based) - dynamic_prob = proximity_ore_chance() // We assign the chance of ore spawning based on probability. - if (prob(dynamic_prob)) - var/list/spawn_chance_list = mineral_chances_by_type[type] - if (isnull(spawn_chance_list)) - mineral_chances_by_type[type] = expand_weights(mineral_chances()) - spawn_chance_list = mineral_chances_by_type[type] + // VOIDCREW EDIT ADDITION START - zone profiles, independent of vent proximity (mining/ore_profiles.dm). + if (ore_initial_roll()) + var/list/spawn_chance_list = ore_spawn_choices() + // VOIDCREW EDIT ADDITION END var/path = pick(spawn_chance_list) if(ispath(path, /turf)) var/stored_flags = 0 @@ -337,7 +334,7 @@ if(ismineralturf(T)) var/turf/closed/mineral/M = T M.turf_type = src.turf_type - M.mineralAmt = scale_ore_to_vent() + // VOIDCREW EDIT: special veins retain their authored quantity and gibtonite bookkeeping. GLOB.post_ore_random["[M.mineralAmt]"] += 1 src = M M.levelupdate() @@ -348,7 +345,7 @@ else Change_Ore(path, FALSE) Spread_Vein(path) - mineralAmt = scale_ore_to_vent() + // VOIDCREW EDIT: Change_Ore() assigns ordinary ore quantities, including spread walls. GLOB.post_ore_manual["[mineralAmt]"] += 1 /turf/closed/mineral/random/high_chance diff --git a/tgstation.dme b/tgstation.dme index db2310e4d1e..88d6177beca 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7248,7 +7248,9 @@ #include "voidcrew\modules\metrics\research_metrics.dm" #include "voidcrew\modules\metrics\ship_metrics.dm" #include "voidcrew\modules\metrics\structured_logging_fallback.dm" +#include "voidcrew\modules\mining\ore_profiles.dm" #include "voidcrew\modules\mining\ore_redemption.dm" +#include "voidcrew\modules\mining\ore_vents.dm" #include "voidcrew\modules\mining\edits\fulton.dm" #include "voidcrew\modules\mining\edits\order_consumables.dm" #include "voidcrew\modules\mining\equipment\explorer_gear.dm" diff --git a/voidcrew/_DEFINES/overmap_zones.dm b/voidcrew/_DEFINES/overmap_zones.dm index 7b9e7e3458f..ba3a375685d 100644 --- a/voidcrew/_DEFINES/overmap_zones.dm +++ b/voidcrew/_DEFINES/overmap_zones.dm @@ -140,7 +140,3 @@ /// is nearly all taken simply goes without rather than spinning. #define PLANET_ANOMALY_PLACEMENT_ATTEMPTS 400 -/// Multiplier on ore mined per planet rock wall (mineralAmt), per zone, green stays baseline (x1). Applied in /turf/closed/mineral/proc/zone_scaled_ore_amount() -#define ZONE_PLANET_ORE_MULT_YELLOW 1.5 -#define ZONE_PLANET_ORE_MULT_RED 2 - diff --git a/voidcrew/datums/mapgen/Cavegens/AsteroidCaves.dm b/voidcrew/datums/mapgen/Cavegens/AsteroidCaves.dm index 8b72f7c2624..870d68346db 100644 --- a/voidcrew/datums/mapgen/Cavegens/AsteroidCaves.dm +++ b/voidcrew/datums/mapgen/Cavegens/AsteroidCaves.dm @@ -63,9 +63,7 @@ * Same recipe as /datum/map_generator/cave_generator/asteroid above (cellular-automata * rock/sand mix, mining mob/geyser spawn tables, /area/centcom/asteroid/voidcrew ground) * but scattered as several independent blobs instead of one solid field, with real vacuum - * left between and around them - "an asteroid field", not a single asteroid. Ore seeding - * itself is handled separately by seed_asteroid_ore_block() (events.dm) after generation, - * the way space ruin asteroid signals used to be seeded before that category was retired. + * left between and around them - "an asteroid field", not a single asteroid. Ore profiles are selected before the mineral turfs initialize; there is no second ore pass. * * Unlike /datum/map_generator/cave_generator/asteroid, weighted_* vars are used (not the * expanded open_turf_types/closed_turf_types/mob_spawn_list/feature_spawn_list directly) - @@ -75,7 +73,7 @@ /datum/map_generator/cave_generator/asteroid_field name = "Asteroid Field Generator" weighted_open_turf_types = list(/turf/open/misc/asteroid/airless = 1) - weighted_closed_turf_types = list(/turf/closed/mineral/random = 1) + weighted_closed_turf_types = list(/turf/closed/mineral/random/asteroid_field = 1) feature_spawn_chance = 1 weighted_feature_spawn_list = list(/obj/structure/geyser/random = 1) @@ -100,12 +98,14 @@ var/blob_radius_max = EVENT_FIELD_BLOB_RADIUS_MAX /datum/map_generator/cave_generator/asteroid_field/minor + weighted_closed_turf_types = list(/turf/closed/mineral/random/asteroid_field/minor = 1) blob_count_min = 22 blob_count_max = 28 blob_radius_min = 4 blob_radius_max = 7 /datum/map_generator/cave_generator/asteroid_field/majour + weighted_closed_turf_types = list(/turf/closed/mineral/random/asteroid_field/majour = 1) blob_count_min = 46 blob_count_max = 58 blob_radius_min = 6 diff --git a/voidcrew/modules/mining/ore_profiles.dm b/voidcrew/modules/mining/ore_profiles.dm new file mode 100644 index 00000000000..97c073ab5c3 --- /dev/null +++ b/voidcrew/modules/mining/ore_profiles.dm @@ -0,0 +1,101 @@ +/// Return copies: neither callers nor the expanded wall cache may mutate the profiles. +/proc/ordinary_ore_weights(zone_type) + var/static/list/profiles = list( + list(110, 40, 16, 16, 8, 5, 2, 2, 1), + list(80, 40, 20, 20, 16, 12, 6, 4, 2), + list(50, 36, 24, 24, 24, 20, 12, 8, 2), + ) + var/static/list/ores = list( + /obj/item/stack/ore/iron, + /obj/item/stack/ore/plasma, + /obj/item/stack/ore/silver, + /obj/item/stack/ore/titanium, + /obj/item/stack/ore/gold, + /obj/item/stack/ore/uranium, + /obj/item/stack/ore/diamond, + /obj/item/stack/ore/bluespace_crystal, + /obj/item/stack/ore/bananium, + ) + var/list/weights = profiles[ordinary_ore_zone(zone_type)] + var/list/result = list() + for(var/index in 1 to length(ores)) + result[ores[index]] = weights[index] + return result + +/proc/ordinary_ore_zone(zone_type) + return (zone_type == ZONE_YELLOW || zone_type == ZONE_RED) ? zone_type : ZONE_GREEN + +/proc/is_ordinary_ore(ore_type) + var/static/list/ores = ordinary_ore_weights(ZONE_GREEN) + return ore_type in ores + +/obj/structure/overmap/planet/proc/ore_zone() + if(!isnull(zone_band)) + return ordinary_ore_zone(zone_band) + var/turf/chart = get_turf(src) + if(!istype(chart, /turf/open/overmap)) + return ZONE_GREEN + return ordinary_ore_zone(SSovermap_zones?.resolve_zone_for_overmap_turf(chart)) + +/// Resolve the wall's own site, including during terrain generation. Never cache by z. +/turf/closed/mineral/proc/ore_profile_zone() + var/obj/structure/overmap/holder = SSovermap_zones?.get_overmap_object_for_turf(src) + if(istype(holder, /obj/structure/overmap/planet)) + var/obj/structure/overmap/planet/planet = holder + return planet.ore_zone() + if(holder) + var/turf/chart = get_turf(holder) + return istype(chart, /turf/open/overmap) ? ordinary_ore_zone(SSovermap_zones.resolve_zone_for_overmap_turf(chart)) : ZONE_GREEN + return ordinary_ore_zone(SSmapping.get_planet_zone_band_for_turf(src)) + +/turf/closed/mineral/random/proc/ore_roll_chance() + switch(ore_profile_zone()) + if(ZONE_YELLOW) + return 12 + if(ZONE_RED) + return 16 + return 8 + +/// A supplied percentile lets tests exercise the same boundary used by initialization. +/turf/closed/mineral/random/proc/ore_initial_roll(percentile = rand(1, 100)) + return percentile <= ore_roll_chance() + +/turf/closed/mineral/random/proc/ore_spawn_choices() + var/static/list/choices_by_profile = list() + var/zone_type = ore_profile_zone() + var/key = "[zone_type]:[type]" + if(isnull(choices_by_profile[key])) + var/list/weights = mineral_chances() + if(!istype(src, /turf/closed/mineral/random/labormineral)) + // Replace only ordinary ore entries; authored special veins keep their weights. + var/list/ordinary = ordinary_ore_weights(zone_type) + for(var/ore in ordinary) + weights[ore] = ordinary[ore] + choices_by_profile[key] = expand_weights(weights) + return choices_by_profile[key] + +/// Only ordinary ore uses the new range. Gibtonite and gulag bookkeeping stay separate. +/turf/closed/mineral/proc/ordinary_ore_amount(ore_type) + if(!is_ordinary_ore(ore_type)) + return mineralAmt + if(istype(src, /turf/closed/mineral/random/asteroid_field)) + switch(ore_profile_zone()) + if(ZONE_YELLOW) + return rand(1, 3) + if(ZONE_RED) + return rand(2, 3) + return rand(1, 2) + return rand(1, 3) + +// The generator chooses these types before Initialize(), so there is only one ore roll. +/turf/closed/mineral/random/asteroid_field/ore_roll_chance() + return 12 + +/turf/closed/mineral/random/asteroid_field/minor/ore_roll_chance() + return 10 + +/turf/closed/mineral/random/asteroid_field/majour/ore_roll_chance() + return 15 + +/turf/closed/mineral/random/labormineral/ore_roll_chance() + return mineralChance diff --git a/voidcrew/modules/mining/ore_vents.dm b/voidcrew/modules/mining/ore_vents.dm new file mode 100644 index 00000000000..a88e8bcf33e --- /dev/null +++ b/voidcrew/modules/mining/ore_vents.dm @@ -0,0 +1,143 @@ +/// This datum belongs to the persistent planet, never its disposable surface. +/datum/planet_ore_reserve + var/sheets_remaining + +/datum/planet_ore_reserve/New(zone_type) + . = ..() + switch(ordinary_ore_zone(zone_type)) + if(ZONE_YELLOW) + sheets_remaining = 6000 + if(ZONE_RED) + sheets_remaining = 10000 + else + sheets_remaining = 3000 + +/obj/structure/overmap/planet + var/datum/planet_ore_reserve/ore_reserve + +/obj/structure/overmap/planet/Destroy() + QDEL_NULL(ore_reserve) + return ..() + +/obj/structure/overmap/planet/proc/get_ore_reserve() + if(!ore_reserve) + ore_reserve = new(ore_zone()) + return ore_reserve + +/obj/structure/ore_vent + /// Binding is permanent, including if the source is subsequently deleted. + var/ore_source_bound = FALSE + var/datum/weakref/ore_source_ref + /// Unowned vents use a finite green reserve of their own. + var/datum/planet_ore_reserve/unowned_ore_reserve + var/boulders_remaining + +/obj/structure/ore_vent/Initialize(mapload) + . = ..() + bind_ore_reserve() + +/obj/structure/ore_vent/Destroy() + ore_source_ref = null + QDEL_NULL(unowned_ore_reserve) + return ..() + +/obj/structure/ore_vent/proc/bind_ore_reserve() + if(ore_source_bound) + return + ore_source_bound = TRUE + var/turf/location = get_turf(src) + var/obj/structure/overmap/planet/source = location ? SSovermap_zones?.get_overmap_object_for_turf(location) : null + var/zone_type = ZONE_GREEN + if(istype(source)) + ore_source_ref = WEAKREF(source) + source.get_ore_reserve() + zone_type = source.ore_zone() + else + unowned_ore_reserve = new(ZONE_GREEN) + switch(ordinary_ore_zone(zone_type)) + if(ZONE_YELLOW) + boulders_remaining = 30 + if(ZONE_RED) + boulders_remaining = 40 + else + boulders_remaining = 20 + +/obj/structure/ore_vent/proc/bound_ore_reserve() + bind_ore_reserve() + if(unowned_ore_reserve) + return unowned_ore_reserve + var/obj/structure/overmap/planet/source = ore_source_ref?.resolve() + return source?.ore_reserve + +/obj/structure/ore_vent/proc/can_produce_ore() + var/datum/planet_ore_reserve/reserve = bound_ore_reserve() + if(boulders_remaining <= 0 || !reserve || reserve.sheets_remaining < 1) + SSore_generation.processed_vents -= src + return FALSE + return !isnull(get_turf(src)) + +/// Truncate to whole sheets of contained material, before refinery efficiency bonuses. +/// No sleeps between rechecking the shared balance, debiting it, and debiting the vent. +/obj/structure/ore_vent/proc/commit_ore_payload(list/materials) + if(!can_produce_ore()) + return FALSE + var/datum/planet_ore_reserve/reserve = bound_ore_reserve() + var/remaining = reserve.sheets_remaining + var/spent = 0 + for(var/material in materials.Copy()) + var/sheets = min(remaining, max(0, round(materials[material] / SHEET_MATERIAL_AMOUNT))) + if(!sheets) + materials -= material + continue + materials[material] = sheets * SHEET_MATERIAL_AMOUNT + remaining -= sheets + spent += sheets + if(!spent) + return FALSE + reserve.sheets_remaining -= spent + boulders_remaining-- + if(!boulders_remaining) + SSore_generation.processed_vents -= src + if(reserve.sheets_remaining < 1) + for(var/obj/structure/ore_vent/vent in SSore_generation.processed_vents.Copy()) + if(vent.bound_ore_reserve() == reserve) + SSore_generation.processed_vents -= vent + return TRUE + +/// The finite allocation pool stores counts, not just membership. +/obj/structure/ore_vent/proc/take_vent_allocation(list/pool) + for(var/material in pool.Copy()) + if(pool[material] <= 0) + pool -= material + if(!length(pool)) + return null + var/material = pick_weight(pool) + pool[material]-- + if(pool[material] <= 0) + pool -= material + return material + +/obj/structure/ore_vent/proc/select_vent_mineral(map_loading) + var/list/pool = SSore_generation.ore_vent_minerals + for(var/material in pool.Copy()) + if(pool[material] <= 0) + pool -= material + var/list/available = map_loading ? pool.Copy() : GLOB.ore_vent_minerals_lavaland.Copy() + available -= mineral_breakdown + if(length(available)) + var/material = pick_weight(available) + if(map_loading) + pool[material]-- + if(pool[material] <= 0) + pool -= material + return material + if(!map_loading || !length(pool)) + return null + // This vent already contains every remaining allocation. Spend one allocation, + // but obtain its additional material from the weighted fallback pool. + var/list/fallback = GLOB.ore_vent_minerals_lavaland.Copy() + fallback -= mineral_breakdown + if(!length(fallback)) + return null + take_vent_allocation(pool) + return pick_weight(fallback) diff --git a/voidcrew/modules/overmap/code/modules/overmap/events.dm b/voidcrew/modules/overmap/code/modules/overmap/events.dm index 0b71ccf4fca..286f05d66e4 100644 --- a/voidcrew/modules/overmap/code/modules/overmap/events.dm +++ b/voidcrew/modules/overmap/code/modules/overmap/events.dm @@ -37,25 +37,11 @@ GLOBAL_LIST_EMPTY(meteor_fields) chart_variant = "rock" parallax_theme = PARALLAX_THEME_ASTEROIDS // crews over/inside the field see drifting asteroids survey_value = 100 - /// Notable minerals shown on the survey report. Keep in sync with ore_weights - var/mineral_types = list(/datum/material/iron, /datum/material/plasma, /datum/material/silver, /datum/material/titanium, /datum/material/gold) + /// Minerals available in every field; zone weights determine their relative abundance. + var/mineral_types = list(/datum/material/iron, /datum/material/plasma, /datum/material/silver, /datum/material/titanium, /datum/material/gold, /datum/material/uranium, /datum/material/diamond, /datum/material/bluespace, /datum/material/bananium) /// Map generator used to carve this severity's landable rock field (see AsteroidCaves.dm) var/datum/map_generator/cave_generator/asteroid_field/mapgen_type = /datum/map_generator/cave_generator/asteroid_field - /// Weighted ore table seeded into this severity's rock (seed_asteroid_ore_block); - /// higher severities carry rarer minerals. Braving the worse storm pays better - var/list/ore_weights = list( - /obj/item/stack/ore/iron = 40, - /obj/item/stack/ore/plasma = 20, - /obj/item/stack/ore/silver = 12, - /obj/item/stack/ore/titanium = 12, - /obj/item/stack/ore/gold = 10, - /obj/item/stack/ore/uranium = 5, - /obj/item/stack/ore/diamond = 2, - /obj/item/stack/ore/bluespace_crystal = 1, - ) - /// Fraction of the field's rock turfs seeded ore-bearing - var/ore_target_ratio = EVENT_FIELD_ORE_TARGET_RATIO /// Chance (0-100) the field hides a zone-scaled expedition cache (zone_loot.dm) var/crate_chance = 40 /// How many roaming zone-scaled mob packs guard the field: list(min, max) @@ -85,10 +71,8 @@ GLOBAL_LIST_EMPTY(meteor_fields) var/dock_index /// Bottom-left turf of the field's padded generation footprint (set by load_level, cleared on unload) var/turf/field_bottom_left - /// Whether this field's ore and caches have already been rolled once. The rock - /// regenerates on every dock (it is the hazard), but the payout does not - without - /// this, undocking for 20 seconds and re-docking re-rolled a fresh ore-seeded field. - var/field_mined = FALSE + /// Terminal once teardown starts; no caller may regenerate this field. + var/retiring = FALSE /obj/structure/overmap/event/meteor/Initialize(mapload) . = ..() @@ -97,6 +81,15 @@ GLOBAL_LIST_EMPTY(meteor_fields) /obj/structure/overmap/event/meteor/Destroy() GLOB.meteor_fields -= src + // The chart was previously static. Retiring a field must also open its cached route. + var/turf/chart = get_turf(src) + var/still_blocked = FALSE + for(var/obj/structure/overmap/event/other in chart) + if(other != src && !QDELETED(other) && !istype(other, /obj/structure/overmap/event/nebula)) + still_blocked = TRUE + break + if(!still_blocked) + GLOB.overmap_blocked_turfs -= chart field_bottom_left = null field_area = null // The orderly teardown (unload_level -> remove_mapzone) leaves both of these null. What @@ -121,16 +114,6 @@ GLOBAL_LIST_EMPTY(meteor_fields) max_cluster_size = 4 chart_severity = 1 mapgen_type = /datum/map_generator/cave_generator/asteroid_field/minor - mineral_types = list(/datum/material/iron, /datum/material/plasma, /datum/material/silver, /datum/material/titanium) - // Common rock only: no uranium, diamond or bluespace this shallow - ore_weights = list( - /obj/item/stack/ore/iron = 50, - /obj/item/stack/ore/plasma = 22, - /obj/item/stack/ore/silver = 12, - /obj/item/stack/ore/titanium = 12, - /obj/item/stack/ore/gold = 4, - ) - ore_target_ratio = 0.25 crate_chance = 20 mob_pack_count = list(1, 2) @@ -139,21 +122,7 @@ GLOBAL_LIST_EMPTY(meteor_fields) spread_chance = 25 max_cluster_size = 7 chart_severity = 3 - mineral_types = list(/datum/material/gold, /datum/material/uranium, /datum/material/diamond, /datum/material/bluespace) mapgen_type = /datum/map_generator/cave_generator/asteroid_field/majour - // The deep-storm payout: still mostly working rock, but the precious tail - // is fat enough that a full strip run banks real diamond/bluespace - ore_weights = list( - /obj/item/stack/ore/iron = 18, - /obj/item/stack/ore/plasma = 14, - /obj/item/stack/ore/silver = 12, - /obj/item/stack/ore/titanium = 12, - /obj/item/stack/ore/gold = 16, - /obj/item/stack/ore/uranium = 14, - /obj/item/stack/ore/diamond = 9, - /obj/item/stack/ore/bluespace_crystal = 5, - ) - ore_target_ratio = 0.4 crate_chance = 65 mob_pack_count = list(3, 4) @@ -187,6 +156,9 @@ GLOBAL_LIST_EMPTY(meteor_fields) * contract: null takes the default, UI callers pass WORLDGEN_QUEUE_NO_WAIT. */ /obj/structure/overmap/event/meteor/proc/load_level(mob/user, obj/structure/overmap/ship/waiting_ship, queue_timeout) + if(retiring) + SEND_SIGNAL(src, COMSIG_VOIDCREW_SITE_LOAD_FINISHED, FALSE) + return if(mapzone) SEND_SIGNAL(src, COMSIG_VOIDCREW_SITE_LOAD_FINISHED, is_loaded()) return @@ -203,7 +175,13 @@ GLOBAL_LIST_EMPTY(meteor_fields) SEND_SIGNAL(src, COMSIG_VOIDCREW_SITE_LOAD_FINISHED, FALSE) return - // The world moved while we queued: another caller may have loaded us already. + // The world moved while we queued: recheck terminal teardown as well. + if(retiring) + SSovermap.worldgen_release(src) + loading = FALSE + worldgen_end(probe, "retiring") + SEND_SIGNAL(src, COMSIG_VOIDCREW_SITE_LOAD_FINISHED, FALSE) + return if(mapzone) SSovermap.worldgen_release(src) loading = FALSE @@ -255,8 +233,7 @@ GLOBAL_LIST_EMPTY(meteor_fields) var/list/field_candidates = block(field_bottom_left, field_top_right) // Carve the rock field via the map generator framework (same architecture as - // planets - see AsteroidCaves.dm) then top up ore the same way asteroid space - // ruin signals used to, before that category was retired in favor of this field. + // planets - see AsteroidCaves.dm). Mineral turfs perform the only ore roll. // // The area is OURS, minted per load. /area/centcom/asteroid/voidcrew used to be // UNIQUE_AREA, so every field alive at once shared one instance spanning all of them - @@ -266,12 +243,7 @@ GLOBAL_LIST_EMPTY(meteor_fields) var/list/field_turfs = mapgen.generate_terrain(field_candidates, field_area) if(length(field_turfs)) mapgen.populate_terrain(field_turfs, field_area) - // One payout per field per round: the rock (and the meteor hazard) come back on - // every dock, but the ore roll and the cache extras only happen the first time. - if(!field_mined) - field_mined = TRUE - seed_asteroid_ore_block(field_bottom_left, field_top_right, ore_target_ratio, "hazard field '[name]'", ore_weights) - populate_field_extras(field_turfs) + populate_field_extras(field_turfs) else // Nothing was carved, so nothing ever entered our area instance - and // reap_emptied_areas() only collects areas a teardown takes turfs AWAY from, so an @@ -302,7 +274,7 @@ GLOBAL_LIST_EMPTY(meteor_fields) // exist, and request_site_load()'s fast path re-invokes ship_act off this answer - // answering "loaded" while the slot is gone would bounce the two procs off each other // in an unbroken INVOKE_ASYNC loop. - return loaded && mapzone && reserve_dock + return !retiring && loaded && mapzone && reserve_dock /// A wedged load or teardown leaves these flags latched (the watchdog force-released /// the queue, but nothing else ever resets them), and ships may be registered for a @@ -334,6 +306,8 @@ GLOBAL_LIST_EMPTY(meteor_fields) return "[name] (mining anchorage)" /obj/structure/overmap/event/meteor/ship_act(mob/user, obj/structure/overmap/ship/acting, obj/structure/overmap/ship/optional_partner) + if(retiring) + return // dock() refuses interdicted ships only after the dock slot below is claimed - // refuse up front instead if(acting.is_interdicted) @@ -467,8 +441,8 @@ GLOBAL_LIST_EMPTY(meteor_fields) SSambient_npcs.populate_field(src, open_turfs) /** - * Releases the field's map slot and docks when nobody's using it. Unlike space ruins, - * the event itself is never deleted or moved - only its (lazily-loaded) interior is freed. + * Releases the field's map slot and docks when nobody's using it. + * Successful teardown also retires the event permanently. */ /obj/structure/overmap/event/meteor/proc/can_release_interior() return isnull(get_interior_release_blocker(log_failure = TRUE)) @@ -513,7 +487,7 @@ GLOBAL_LIST_EMPTY(meteor_fields) return null /obj/structure/overmap/event/meteor/proc/unload_level() - if(concerned) + if(retiring || concerned) return if(!can_release_interior()) @@ -561,11 +535,12 @@ GLOBAL_LIST_EMPTY(meteor_fields) // is_loaded() must read FALSE the moment the ground stops being safe to dock into, // or an arriving ship's fast path resumes an approach into turfs that are // mid-recycle. + retiring = TRUE loaded = FALSE remove_docks() remove_mapzone() SSovermap.worldgen_release(src) - concerned = FALSE + qdel(src) /obj/structure/overmap/event/meteor/proc/remove_docks() if(reserve_dock) @@ -597,66 +572,6 @@ GLOBAL_LIST_EMPTY(meteor_fields) field_area = null field_bottom_left = null -/** - * Seeds ore deposits into a rectangular block of rock turfs, converting barren - * /turf/closed/mineral rock into ore deposits until target_ratio of the mineral - * turfs in the block are ore-bearing. Originally shared with space ruin asteroid - * signals; those were retired in favor of landable fields, so this is now solely - * the field ore-seeding step, called from load_level() above. - * - * source_desc is a human-readable label for the mapping log line only. - * ore_weights optionally overrides the default weighted ore table, the meteor - * severity tiers pass their own so worse storms seed richer rock. - * - * Mining itself needs no z-level traits: off mining levels, prox_to_vent() returns 0 and - * the mineral turf machinery falls back to flat random yields, so this works fine inside - * a map slot on a shared encounter z-level. - */ -/proc/seed_asteroid_ore_block(turf/bottom_left, turf/top_right, target_ratio, source_desc, list/ore_weights) - if(!bottom_left || !top_right) - return - - // Default weighted ore table - iron/plasma-heavy like planet rock, no bananium, and - // no gibtonite (its detonation admin-alerts are tuned for mining levels, and surprise - // bombs shouldn't be procedurally injected into rock the mapper made inert) - var/static/list/asteroid_ore_weights = list( - /obj/item/stack/ore/iron = 40, - /obj/item/stack/ore/plasma = 20, - /obj/item/stack/ore/silver = 12, - /obj/item/stack/ore/titanium = 12, - /obj/item/stack/ore/gold = 10, - /obj/item/stack/ore/uranium = 5, - /obj/item/stack/ore/diamond = 2, - /obj/item/stack/ore/bluespace_crystal = 1, - ) - var/list/table = (length(ore_weights)) ? ore_weights : asteroid_ore_weights - - var/mineral_turf_count = 0 - var/ore_bearing_count = 0 - var/list/barren_rock = list() - for(var/turf/closed/mineral/rock in block(bottom_left, top_right)) - mineral_turf_count++ - // Already has ore, a boulder, or is gibtonite (mineralType-less but very much not barren) - if(rock.mineralType || rock.spawned_boulder || istype(rock, /turf/closed/mineral/gibtonite)) - ore_bearing_count++ - continue - barren_rock += rock - // Scans a whole site block mid-round - yield (see worldgen_yield()) - SSovermap.worldgen_yield() - - var/target = CEILING(mineral_turf_count * target_ratio, 1) - var/to_seed = target - ore_bearing_count - var/seeded = 0 - while(to_seed > 0 && length(barren_rock)) - var/turf/closed/mineral/rock = pick_n_take(barren_rock) - rock.Change_Ore(pick_weight(table)) - rock.mineralAmt = rand(ASTEROID_ORE_AMOUNT_MIN, ASTEROID_ORE_AMOUNT_MAX) - to_seed-- - seeded++ - - if(seeded) - log_mapping("SPACE RUIN: Seeded [seeded] ore deposits into [source_desc] ([ore_bearing_count]/[mineral_turf_count] rock was already ore-bearing)") - /obj/structure/overmap/event/emp name = "ion storm (moderate)" icon_state = "ion1" diff --git a/voidcrew/modules/overmap/code/modules/overmap/generation.dm b/voidcrew/modules/overmap/code/modules/overmap/generation.dm index c1da3e1e342..362be922cfa 100644 --- a/voidcrew/modules/overmap/code/modules/overmap/generation.dm +++ b/voidcrew/modules/overmap/code/modules/overmap/generation.dm @@ -215,6 +215,7 @@ for(var/path in weights) if(!tally[path]) weights[path] *= 2 + weights = meteor_event_weights(weights, band) event_type = pick_weight(weights) grow_cluster(seed, event_type) CHECK_TICK @@ -240,6 +241,25 @@ return FALSE return ensure_event_supply() +/// Severity changes within the existing meteor budget, leaving hazard coverage intact. +/proc/meteor_severity_weights(zone_type) + switch(ordinary_ore_zone(zone_type)) + if(ZONE_YELLOW) + return list(/obj/structure/overmap/event/meteor/minor = 25, /obj/structure/overmap/event/meteor = 50, /obj/structure/overmap/event/meteor/majour = 25) + if(ZONE_RED) + return list(/obj/structure/overmap/event/meteor/minor = 10, /obj/structure/overmap/event/meteor = 30, /obj/structure/overmap/event/meteor/majour = 60) + return list(/obj/structure/overmap/event/meteor/minor = 60, /obj/structure/overmap/event/meteor = 30, /obj/structure/overmap/event/meteor/majour = 10) + +/proc/meteor_event_weights(list/weights, zone_type) + var/list/result = weights.Copy() + var/list/severities = meteor_severity_weights(zone_type) + var/total = 0 + for(var/path in severities) + total += weights[path] + for(var/path in severities) + result[path] = total * severities[path] / 100 + return result + /// Repairs only remove hazards, so this converges. A cross-zone opening can expose /// another pocket inside one band; recheck until both guarantees hold together. /datum/overmap_layout/proc/connect_clear_space() diff --git a/voidcrew/modules/unit_tests/_unit_tests.dm b/voidcrew/modules/unit_tests/_unit_tests.dm index 306835028b8..8586c126751 100644 --- a/voidcrew/modules/unit_tests/_unit_tests.dm +++ b/voidcrew/modules/unit_tests/_unit_tests.dm @@ -167,6 +167,7 @@ #include "voidcrew_outpost_upgrade_snaps.dm" #include "voidcrew_outpost_upgrades.dm" #include "voidcrew_outpost_yard_droids.dm" +#include "voidcrew_ore_balance.dm" #include "voidcrew_overmap_management.dm" #include "voidcrew_pandora_links.dm" #include "voidcrew_planet_cleanup.dm" diff --git a/voidcrew/modules/unit_tests/voidcrew_ore_balance.dm b/voidcrew/modules/unit_tests/voidcrew_ore_balance.dm new file mode 100644 index 00000000000..47595d1b10d --- /dev/null +++ b/voidcrew/modules/unit_tests/voidcrew_ore_balance.dm @@ -0,0 +1,364 @@ +// Zone literals: the test harness is included before Voidcrew defines. +/datum/unit_test/voidcrew_ore_balance + var/list/sites = list() + var/list/changed_turfs = list() + var/list/original_areas = list() + var/list/original_blocked = list() + +/datum/unit_test/voidcrew_ore_balance/Destroy() + for(var/obj/structure/ore_vent/vent in allocated) + SSore_generation.processed_vents -= vent + for(var/obj/structure/overmap/event/meteor/field in allocated) + field.mapzone = null + field.footprint = null + for(var/obj/structure/overmap/planet/site in sites) + site.mapzone = null + site.footprint = null + for(var/turf/changed as anything in original_areas) + changed.change_area(get_area(changed), original_areas[changed]) + for(var/turf/changed as anything in changed_turfs) + if(istype(changed, /turf/open/overmap)) + var/turf/open/overmap/chart = changed + chart.current_zone = null + changed.ChangeTurf(changed_turfs[changed]) + . = ..() + for(var/turf/chart as anything in original_blocked) + if(original_blocked[chart]) + GLOB.overmap_blocked_turfs[chart] = original_blocked[chart] + else + GLOB.overmap_blocked_turfs -= chart + +/datum/unit_test/voidcrew_ore_balance/proc/change(turf/location, turf_type) + var/old_type = location.type + var/turf/result = location.ChangeTurf(turf_type) + if(!changed_turfs[result]) + changed_turfs[result] = old_type + return result + +/datum/unit_test/voidcrew_ore_balance/proc/planet_at(turf/surface, turf/token, zone_type) + var/turf/open/overmap/chart = change(token, /turf/open/overmap) + chart.current_zone = allocate(/datum/overmap_zone, zone_type) + var/obj/structure/overmap/planet/site = allocate(/obj/structure/overmap/planet, chart) + site.zone_band = zone_type + var/datum/map_zone/zone = allocate(/datum/map_zone) + zone.z_levels = list(reservation) + var/datum/map_footprint/footprint = allocate(/datum/map_footprint) + footprint.z_value = surface.z + footprint.set_rect(surface.x, surface.y, 1, 1) + site.mapzone = zone + site.footprint = footprint + sites += site + return site + +/datum/unit_test/voidcrew_ore_balance/Run() + var/list/expected = list( + list(110, 40, 16, 16, 8, 5, 2, 2, 1), + list(80, 40, 20, 20, 16, 12, 6, 4, 2), + list(50, 36, 24, 24, 24, 20, 12, 8, 2), + ) + var/list/ores = list(/obj/item/stack/ore/iron, /obj/item/stack/ore/plasma, /obj/item/stack/ore/silver, /obj/item/stack/ore/titanium, /obj/item/stack/ore/gold, /obj/item/stack/ore/uranium, /obj/item/stack/ore/diamond, /obj/item/stack/ore/bluespace_crystal, /obj/item/stack/ore/bananium) + for(var/zone_type in 1 to 3) + var/list/weights = ordinary_ore_weights(zone_type) + var/list/row = expected[zone_type] + TEST_ASSERT_EQUAL(length(weights), 9, "Every profile must contain all nine ordinary ores") + for(var/index in 1 to length(ores)) + TEST_ASSERT_EQUAL(weights[ores[index]], row[index], "Incorrect zone ore weight") + TEST_ASSERT(weights[ores[index]] > 0, "An ordinary ore is zone-exclusive") + weights[/obj/item/stack/ore/iron] = -1 + var/list/fresh = ordinary_ore_weights(zone_type) + TEST_ASSERT_EQUAL(fresh[/obj/item/stack/ore/iron], row[1], "A caller mutated the profile") + TEST_ASSERT_EQUAL(ordinary_ore_zone(null), 1, "Unzoned rock must use green") + TEST_ASSERT_EQUAL(ordinary_ore_zone(99), 1, "Unknown rock must use green") + var/list/severity_rows = list(list(60, 30, 10), list(25, 50, 25), list(10, 30, 60)) + var/list/meteor_types = list(/obj/structure/overmap/event/meteor/minor, /obj/structure/overmap/event/meteor, /obj/structure/overmap/event/meteor/majour) + for(var/zone_type in 1 to 3) + var/list/weights = meteor_severity_weights(zone_type) + var/list/row = severity_rows[zone_type] + var/list/applied = meteor_event_weights(GLOB.overmap_event_pick_list, zone_type) + var/old_total = 0 + var/new_total = 0 + for(var/index in 1 to 3) + var/path = meteor_types[index] + TEST_ASSERT_EQUAL(weights[path], row[index], "Incorrect meteor severity weight") + old_total += GLOB.overmap_event_pick_list[path] + new_total += applied[path] + TEST_ASSERT_EQUAL(new_total, old_total, "Severity changed the total meteor selection weight") + +// Suppress special turf replacements in this fixture, while using production profiles. +/turf/closed/mineral/random/ore_balance_probe + var/test_zone = 1 + var/allow_test_roll = FALSE + +/turf/closed/mineral/random/ore_balance_probe/ore_profile_zone() + return test_zone + +/turf/closed/mineral/random/ore_balance_probe/mineral_chances() + return list(/turf/closed/mineral/glacial = 5) + +/turf/closed/mineral/random/ore_balance_probe/ore_initial_roll(percentile = rand(1, 100)) + if(!allow_test_roll) + return FALSE + return ..() + +/datum/unit_test/voidcrew_ore_balance/walls/Run() + var/turf/closed/mineral/random/ore_balance_probe/wall = change(run_loc_floor_bottom_left, /turf/closed/mineral/random/ore_balance_probe) + var/list/chances = list(8, 12, 16) + for(var/zone_type in 1 to 3) + wall.test_zone = zone_type + wall.allow_test_roll = TRUE + TEST_ASSERT_EQUAL(wall.ore_roll_chance(), chances[zone_type], "Incorrect initial planet wall chance") + TEST_ASSERT(wall.ore_initial_roll(chances[zone_type]), "The final successful percentile failed") + TEST_ASSERT(!wall.ore_initial_roll(chances[zone_type] + 1), "The first failed percentile succeeded") + var/list/choices = wall.ore_spawn_choices() + var/list/counts = list() + for(var/choice in choices) + counts[choice]++ + var/list/expected = ordinary_ore_weights(zone_type) + for(var/ore in expected) + TEST_ASSERT_EQUAL(counts[ore], expected[ore], "The subtype cache leaked a different zone profile") + TEST_ASSERT_EQUAL(counts[/turf/closed/mineral/glacial], 5, "An authored special vein lost its weight") + for(var/iteration in 1 to 30) + wall.Change_Ore(/obj/item/stack/ore/iron, iteration % 2) + TEST_ASSERT(wall.mineralAmt >= 1 && wall.mineralAmt <= 3, "A direct or spread-style Change_Ore used the old amount") + var/obj/structure/ore_vent/vent = allocate(/obj/structure/ore_vent, get_step(wall, NORTH)) + wall.test_zone = 1 + TEST_ASSERT_EQUAL(wall.proximity_ore_chance(), 8, "A nearby vent changed the wall chance") + for(var/iteration in 1 to 20) + TEST_ASSERT(wall.scale_ore_to_vent() in list(1, 2, 3), "A nearby vent changed the wall yield") + vent.forceMove(get_step(wall, EAST)) + TEST_ASSERT_EQUAL(wall.proximity_ore_chance(), 8, "Moving a vent changed the wall chance") + var/turf/closed/mineral/gibtonite/gib = change(get_step(wall, EAST), /turf/closed/mineral/gibtonite) + TEST_ASSERT_EQUAL(gib.ordinary_ore_amount(null), initial(gib.mineralAmt), "Gibtonite bookkeeping was treated as ore") + wall.mineralAmt = 7 + wall.Change_Ore(/obj/item/boulder/gulag) + TEST_ASSERT_EQUAL(wall.mineralAmt, 7, "A gulag boulder was treated as ordinary ore") + +/turf/closed/mineral/random/asteroid_field/ore_balance_probe + var/test_zone = 1 + var/roll_calls = 0 + +/turf/closed/mineral/random/asteroid_field/ore_balance_probe/ore_profile_zone() + return test_zone + +/turf/closed/mineral/random/asteroid_field/ore_balance_probe/ore_initial_roll(percentile = rand(1, 100)) + roll_calls++ + return FALSE + +/turf/closed/mineral/random/asteroid_field/minor/ore_balance_probe/ore_initial_roll(percentile = rand(1, 100)) + return FALSE + +/turf/closed/mineral/random/asteroid_field/majour/ore_balance_probe/ore_initial_roll(percentile = rand(1, 100)) + return FALSE + +/datum/map_generator/cave_generator/asteroid_field/ore_balance_probe + weighted_closed_turf_types = list(/turf/closed/mineral/random/asteroid_field/ore_balance_probe = 1) + blob_count_min = 1 + blob_count_max = 1 + blob_radius_min = 3 + blob_radius_max = 3 + initial_closed_chance = 100 + smoothing_iterations = 0 + mob_spawn_chance = 0 + flora_spawn_chance = 0 + feature_spawn_chance = 0 + +/datum/unit_test/voidcrew_ore_balance/asteroids/Run() + var/list/generators = list(/datum/map_generator/cave_generator/asteroid_field/minor, /datum/map_generator/cave_generator/asteroid_field, /datum/map_generator/cave_generator/asteroid_field/majour) + var/list/walls = list(/turf/closed/mineral/random/asteroid_field/minor, /turf/closed/mineral/random/asteroid_field, /turf/closed/mineral/random/asteroid_field/majour) + for(var/index in 1 to 3) + var/datum/map_generator/cave_generator/asteroid_field/generator = allocate(generators[index]) + TEST_ASSERT_EQUAL(generator.closed_turf_types[1], walls[index], "Severity was not configured before wall initialization") + var/turf/closed/mineral/random/asteroid_field/minor_rock = change(run_loc_floor_bottom_left, /turf/closed/mineral/random/asteroid_field/minor/ore_balance_probe) + TEST_ASSERT_EQUAL(minor_rock.ore_roll_chance(), 10, "Incorrect minor storm chance") + var/turf/closed/mineral/random/asteroid_field/major_rock = change(run_loc_floor_bottom_left, /turf/closed/mineral/random/asteroid_field/majour/ore_balance_probe) + TEST_ASSERT_EQUAL(major_rock.ore_roll_chance(), 15, "Incorrect major storm chance") + var/turf/closed/mineral/random/asteroid_field/ore_balance_probe/wall = change(run_loc_floor_bottom_left, /turf/closed/mineral/random/asteroid_field/ore_balance_probe) + TEST_ASSERT_EQUAL(wall.ore_roll_chance(), 12, "Incorrect moderate storm chance") + TEST_ASSERT_EQUAL(wall.roll_calls, 1, "Asteroid initialization rolled ore more than once") + TEST_ASSERT_NULL(wall.mineralType, "A failed initial roll was topped up") + for(var/zone_type in 1 to 3) + wall.test_zone = zone_type + for(var/iteration in 1 to 30) + wall.Change_Ore(/obj/item/stack/ore/diamond) + TEST_ASSERT(wall.mineralAmt >= (zone_type == 3 ? 2 : 1) && wall.mineralAmt <= (zone_type == 1 ? 2 : 3), "Incorrect asteroid zone quantity") + var/turf/closed/mineral/random/asteroid_field/ore_balance_probe/spread_wall = change(get_step(wall, EAST), /turf/closed/mineral/random/asteroid_field/ore_balance_probe) + spread_wall.mineralAmt = 99 + wall.Change_Ore(/obj/item/stack/ore/iron) + // Exercise classic spreading itself, with ample attempts at the unchanged 20% roll. + for(var/iteration in 1 to 200) + wall.Spread_Vein() + if(spread_wall.mineralType) + break + TEST_ASSERT_EQUAL(spread_wall.mineralType, /obj/item/stack/ore/iron, "Classic vein spreading no longer reaches adjacent random rock") + TEST_ASSERT(spread_wall.mineralAmt >= 1 && spread_wall.mineralAmt <= 2, "A spread-created asteroid wall retained its old quantity") + var/datum/map_generator/cave_generator/asteroid_field/generator = allocate(/datum/map_generator/cave_generator/asteroid_field/ore_balance_probe) + var/area/centcom/asteroid/voidcrew/field_area = new + allocated += field_area + var/turf/bottom_left = get_step(get_step(run_loc_floor_bottom_left, NORTH), NORTH) + var/list/candidates = block(bottom_left, locate(bottom_left.x + 12, bottom_left.y + 12, bottom_left.z)) + for(var/turf/candidate as anything in candidates) + changed_turfs[candidate] = candidate.type + original_areas[candidate] = get_area(candidate) + var/list/generated = generator.generate_terrain(candidates, field_area) + generator.populate_terrain(generated, field_area) + var/rock_count = 0 + for(var/turf/closed/mineral/random/asteroid_field/ore_balance_probe/rock in generated) + rock_count++ + TEST_ASSERT_EQUAL(rock.roll_calls, 1, "Generation seeded the same asteroid wall twice") + TEST_ASSERT_NULL(rock.mineralType, "Generation topped up an unsuccessful wall roll") + TEST_ASSERT(rock_count > 0, "The asteroid generation fixture produced no rock") + +/datum/unit_test/voidcrew_ore_balance/vents/Run() + var/turf/green_surface = run_loc_floor_bottom_left + var/turf/red_surface = get_step(green_surface, EAST) + var/obj/structure/overmap/planet/green = planet_at(green_surface, get_step(green_surface, NORTH), 1) + var/obj/structure/overmap/planet/red = planet_at(red_surface, get_step(red_surface, NORTH), 3) + var/turf/yellow_surface = get_step(red_surface, EAST) + var/obj/structure/overmap/planet/yellow_site = planet_at(yellow_surface, get_step(yellow_surface, NORTH), 2) + var/turf/closed/mineral/green_rock = change(green_surface, /turf/closed/mineral) + var/turf/closed/mineral/red_rock = change(red_surface, /turf/closed/mineral) + TEST_ASSERT_EQUAL(green_rock.ore_profile_zone(), 1, "Green rock inherited its packed neighbour's profile") + TEST_ASSERT_EQUAL(red_rock.ore_profile_zone(), 3, "Red rock inherited its packed neighbour's profile") + var/obj/structure/ore_vent/first = allocate(/obj/structure/ore_vent, green_surface) + var/obj/structure/ore_vent/second = allocate(/obj/structure/ore_vent, green_surface) + var/obj/structure/ore_vent/other = allocate(/obj/structure/ore_vent, red_surface) + var/obj/structure/ore_vent/yellow_vent = allocate(/obj/structure/ore_vent, yellow_surface) + TEST_ASSERT_EQUAL(first.boulders_remaining, 20, "Incorrect green vent cap") + TEST_ASSERT_EQUAL(other.boulders_remaining, 40, "Incorrect red vent cap") + TEST_ASSERT_EQUAL(yellow_vent.boulders_remaining, 30, "Incorrect yellow vent cap") + TEST_ASSERT_EQUAL(green.ore_reserve.sheets_remaining, 3000, "Incorrect green reserve") + TEST_ASSERT_EQUAL(red.ore_reserve.sheets_remaining, 10000, "Incorrect red reserve") + TEST_ASSERT_EQUAL(yellow_site.ore_reserve.sheets_remaining, 6000, "Incorrect yellow reserve") + first.mineral_breakdown = list(/datum/material/iron = 1) + second.mineral_breakdown = first.mineral_breakdown.Copy() + green.ore_reserve.sheets_remaining = 2 + SSore_generation.processed_vents |= list(first, second) + var/obj/item/boulder/last = first.produce_boulder(TRUE) + TEST_ASSERT(last, "The final partial boulder was refused") + allocated += last + var/total = 0 + for(var/material in last.custom_materials) + total += last.custom_materials[material] + TEST_ASSERT_EQUAL(total / SHEET_MATERIAL_AMOUNT, 2, "The final boulder exceeded the shared reserve") + TEST_ASSERT_EQUAL(first.boulders_remaining, 19, "A partial boulder did not debit the vent counter once") + TEST_ASSERT_EQUAL(green.ore_reserve.sheets_remaining, 0, "Manual extraction did not debit the shared reserve") + TEST_ASSERT_NULL(second.produce_boulder(), "Automatic production bypassed the shared reserve") + TEST_ASSERT_EQUAL(second.boulders_remaining, 20, "Failed extraction consumed a vent counter") + TEST_ASSERT(!(first in SSore_generation.processed_vents) && !(second in SSore_generation.processed_vents), "Exhausted vents remained in automatic processing") + TEST_ASSERT_EQUAL(red.ore_reserve.sheets_remaining, 10000, "Packed neighbour reserves were shared") + first.forceMove(red_surface) + TEST_ASSERT_EQUAL(first.bound_ore_reserve(), green.ore_reserve, "An imported vent rebound to its destination") + var/datum/map_zone/old_zone = green.mapzone + var/datum/map_footprint/old_footprint = green.footprint + green.mapzone = null + green.footprint = null + TEST_ASSERT_EQUAL(green.get_ore_reserve().sheets_remaining, 0, "Unloading refilled the planet reserve") + green.mapzone = old_zone + green.footprint = old_footprint + var/obj/structure/ore_vent/replacement = allocate(/obj/structure/ore_vent, green_surface) + TEST_ASSERT_EQUAL(replacement.bound_ore_reserve(), green.ore_reserve, "Reload or replacement created a new reserve") + TEST_ASSERT_NULL(replacement.produce_boulder(TRUE), "Replacement refilled the reserve") + other.mineral_breakdown = list(/datum/material/iron = 1) + var/list/empty_payload = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT - 1) + var/unchanged_balance = red.ore_reserve.sheets_remaining + var/unchanged_counter = other.boulders_remaining + TEST_ASSERT(!other.commit_ore_payload(empty_payload), "A payload without a whole sheet produced a boulder") + TEST_ASSERT_EQUAL(red.ore_reserve.sheets_remaining, unchanged_balance, "An empty payload debited the reserve") + TEST_ASSERT_EQUAL(other.boulders_remaining, unchanged_counter, "An empty payload debited the vent counter") + other.boulders_remaining = 1 + SSore_generation.processed_vents |= other + var/obj/item/boulder/final_automatic = other.produce_boulder() + TEST_ASSERT(final_automatic, "Automatic extraction failed with both limits available") + allocated += final_automatic + var/balance = red.ore_reserve.sheets_remaining + TEST_ASSERT_NULL(other.produce_boulder(TRUE), "Manual extraction bypassed the automatic vent counter") + TEST_ASSERT_EQUAL(red.ore_reserve.sheets_remaining, balance, "Failed manual extraction debited the reserve") + TEST_ASSERT(!(other in SSore_generation.processed_vents), "A capped vent remained in automatic processing") + +/datum/unit_test/voidcrew_ore_balance/vent_weights/Run() + var/list/old_pool = SSore_generation.ore_vent_minerals + var/obj/structure/ore_vent/vent = allocate(/obj/structure/ore_vent) + // One positive option makes weighted selection deterministic; uniform pick can select zero. + SSore_generation.ore_vent_minerals = list(/datum/material/iron = 2, /datum/material/gold = 0) + var/first = vent.select_vent_mineral(TRUE) + var/remaining = SSore_generation.ore_vent_minerals[/datum/material/iron] + var/second = vent.select_vent_mineral(TRUE) + var/empty = length(SSore_generation.ore_vent_minerals) + // Exercise the branch where this vent already owns every remaining allocation. + SSore_generation.ore_vent_minerals = list(/datum/material/iron = 1) + vent.mineral_breakdown = list(/datum/material/iron = 1) + var/fallback = vent.select_vent_mineral(TRUE) + var/after_fallback = length(SSore_generation.ore_vent_minerals) + var/list/old_fallback = GLOB.ore_vent_minerals_lavaland + GLOB.ore_vent_minerals_lavaland = list(/datum/material/iron = 1000, /datum/material/gold = 1) + SSore_generation.ore_vent_minerals = list(/datum/material/iron = 1000000, /datum/material/gold = 1000) + vent.mineral_breakdown = list() + var/mapload_iron = 0 + var/dynamic_iron = 0 + for(var/iteration in 1 to 256) + if(vent.select_vent_mineral(TRUE) == /datum/material/iron) + mapload_iron++ + if(vent.select_vent_mineral(FALSE) == /datum/material/iron) + dynamic_iron++ + GLOB.ore_vent_minerals_lavaland = old_fallback + SSore_generation.ore_vent_minerals = old_pool + TEST_ASSERT_EQUAL(first, /datum/material/iron, "Mapload selection ignored the available weighted pool") + TEST_ASSERT_EQUAL(second, /datum/material/iron, "An allocation count was removed before exhaustion") + TEST_ASSERT_EQUAL(remaining, 1, "Allocation did not decrement by one") + TEST_ASSERT_EQUAL(empty, 0, "Exhausted allocations were retained") + TEST_ASSERT(fallback && fallback != /datum/material/iron, "Empty available pool selected a null or duplicate material") + TEST_ASSERT_EQUAL(after_fallback, 0, "Fallback did not spend its surrogate allocation") + TEST_ASSERT(mapload_iron >= 240, "Mapload allocation used uniform rather than weighted selection") + TEST_ASSERT(dynamic_iron >= 240, "Dynamic allocation used uniform rather than weighted selection") + +// Borrow the test room without sweeping it; exercise the real unload state machine. +/obj/structure/overmap/event/meteor/ore_balance_probe + var/docks_removed_while_retiring = FALSE + var/footprint_released_while_claimed = FALSE + +/obj/structure/overmap/event/meteor/ore_balance_probe/remove_docks() + docks_removed_while_retiring = retiring && !loaded + return ..() + +/obj/structure/overmap/event/meteor/ore_balance_probe/remove_mapzone() + footprint_released_while_claimed = retiring && SSovermap.worldgen_owner == src && !reserve_dock + mapzone = null + footprint = null + +/datum/unit_test/voidcrew_ore_balance/teardown/Run() + var/turf/inside = run_loc_floor_bottom_left + var/obj/structure/overmap/event/meteor/ore_balance_probe/field = allocate(/obj/structure/overmap/event/meteor/ore_balance_probe) + var/datum/map_zone/zone = allocate(/datum/map_zone) + zone.z_levels = list(reservation) + var/datum/map_footprint/footprint = allocate(/datum/map_footprint) + footprint.z_value = inside.z + footprint.set_rect(inside.x, inside.y, 1, 1) + field.mapzone = zone + field.footprint = footprint + field.loaded = TRUE + field.reserve_dock = allocate(/obj/docking_port/stationary, inside) + field.first_dock_taken = TRUE + field.unload_level() + TEST_ASSERT(!field.retiring && field.loaded, "An occupied berth was torn down") + field.first_dock_taken = FALSE + var/mob/living/basic/player = allocate(/mob/living/basic, inside) + GLOB.player_list |= player + var/player_blocked = !field.can_release_interior() + GLOB.player_list -= player + TEST_ASSERT(player_blocked, "A connected occupant did not prevent teardown") + field.load_level() // The loaded field must be reused, never regenerated. + TEST_ASSERT_EQUAL(field.footprint, footprint, "Redocking replaced an existing field") + var/fields_before = length(GLOB.meteor_fields) + original_blocked[inside] = GLOB.overmap_blocked_turfs[inside] + GLOB.overmap_blocked_turfs[inside] = TRUE + field.unload_level() + TEST_ASSERT(field.docks_removed_while_retiring, "Docks were removed before marking the field terminal") + TEST_ASSERT(field.footprint_released_while_claimed, "Footprint release lost the worldgen claim") + TEST_ASSERT(QDELETED(field), "Successful unloading left the event alive") + TEST_ASSERT_EQUAL(length(GLOB.meteor_fields), fields_before - 1, "Teardown generated a replacement field") + TEST_ASSERT(!GLOB.overmap_blocked_turfs[inside], "A retired field left a phantom route obstruction") + TEST_ASSERT(SSovermap.worldgen_owner != field, "Successful teardown leaked its worldgen lock") + var/obj/structure/overmap/event/meteor/retired = allocate(/obj/structure/overmap/event/meteor) + retired.retiring = TRUE + retired.load_level() + TEST_ASSERT_NULL(retired.mapzone, "Loading regenerated a retiring field") diff --git a/voidcrew/turfs/closed/minerals.dm b/voidcrew/turfs/closed/minerals.dm index c9ae8a7ae0a..ed01117ec84 100644 --- a/voidcrew/turfs/closed/minerals.dm +++ b/voidcrew/turfs/closed/minerals.dm @@ -1,49 +1,3 @@ -/** - * Zone ore scaling: planets in deeper overmap zone bands yield MORE ore per - * mineral wall (same ore tables; kinds are never zone-gated, only amounts). - * - * Called from the one-line VOIDCREW EDIT in the base gets_drilled() - * (code/game/turfs/closed/minerals.dm), the single payout choke point every - * mining path funnels through (picks, drills, KA/plasma projectiles, ex_act, - * blob). Scaling at payout instead of Initialize means spread-vein walls - * (which keep the default mineralAmt of 3, never touched by - * scale_ore_to_vent()) and mapper-placed ore walls inside planet ruins get - * scaled too, and it costs nothing at planet init. Walls created after init - * are equally covered, and on non-planet z-levels (space ruins, - * asteroid-field reservations, outposts, transit) the band lookup returns - * null, so behavior there is byte-identical to upstream. - * - * Deliberately NOT scaled: - * * telecrystal + glacial core veins: the planetary trade goods - * (voidcrew/modules/trade/planetary_goods.dm); their supply is - * economy-tuned, so a richer red-band spigot would distort the - * voucher/credit ladder - * * gibtonite and "very strong rock": their gets_drilled() overrides never - * call the base proc, so they never reach this hook; gibtonite's - * mineralAmt is detonation bookkeeping, not an ore payout - * * gulag boulder walls: they use spawned_boulder, not mineralType, so the - * base proc's mineralType guard already skips them - */ -/turf/closed/mineral/proc/zone_scaled_ore_amount(amount) - if(amount <= 0) - return amount - // trade-good veins keep their tuned yields (see block comment) - if(istype(src, /turf/closed/mineral/telecrystal) || istype(src, /turf/closed/mineral/glacial)) - return amount - // Resolved live, from THIS wall's turf. SSmapping.get_planet_zone_band_for_z() alone - // only answers for pre-generated roundstart planets, and every planet this round is - // dynamic, so it always came back null; planet_zone_type_for_turf() asks the overmap - // first and falls back to it. Turf-scoped, not z-scoped: a z-level can carry more than - // one planet and they can sit in different bands, so the wall has to speak for itself. - // Not cached per z either - dynamic planet z-levels are recycled, so a cached band - // would follow the z-level onto the next planet to inherit it. - switch(SSovermap_zones?.planet_zone_type_for_turf(src)) - if(ZONE_YELLOW) - return round(amount * ZONE_PLANET_ORE_MULT_YELLOW) - if(ZONE_RED) - return round(amount * ZONE_PLANET_ORE_MULT_RED) - return amount - /** * Per-z index of the ore vents that count for a wall, grouped by the loaded interior each * vent sits in. @@ -197,14 +151,10 @@ GLOBAL_LIST_EMPTY(ore_vent_index_by_z) return distance /turf/closed/mineral/random/proximity_ore_chance() - if(!has_local_ore_vent()) - return mineralChance - return ..() + return ore_roll_chance() /turf/closed/mineral/scale_ore_to_vent() - if(!has_local_ore_vent()) - return rand(1, 5) // upstream's own off-lavaland fallback, see the base proc - return ..() + return ordinary_ore_amount(mineralType) #undef ORE_VENT_INDEX_LIFESPAN From 94f71f1b3ed0e96a2bd8e6e4b037dd4fd3d919f5 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 12:58:33 -0700 Subject: [PATCH 010/105] Mining bills and truthful redemption rates --- code/modules/mining/machine_redemption.dm | 16 +---- .../modules/mining/edits/order_consumables.dm | 5 ++ voidcrew/modules/mining/ore_redemption.dm | 14 ++++ .../modules/unit_tests/voidcrew_mining_qol.dm | 70 +++++++++++++++++++ 4 files changed, 91 insertions(+), 14 deletions(-) diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index cd902b071c3..1eaf948cdc5 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -23,19 +23,7 @@ var/ore_multiplier = 1 /// Increases the amount of points the miners gain var/point_upgrade = 1 - /// Details how many credits each smelted ore is worth - var/static/list/ore_values = list( - /datum/material/iron = 1, - /datum/material/glass = 1, - /datum/material/plasma = 15, - /datum/material/silver = 16, - /datum/material/gold = 18, - /datum/material/titanium = 30, - /datum/material/uranium = 30, - /datum/material/diamond = 50, - /datum/material/bluespace = 50, - /datum/material/bananium = 60, - ) + // VOIDCREW EDIT - ore_values removed; voidcrew/modules/mining/ore_redemption.dm quotes the actual ore payout. /// Variable that holds a timer which is used for callbacks to `send_console_message()`. Used for preventing multiple calls to this proc while the ORM is eating a stack of ores. var/console_notify_timer /// References the alloys the smelter can create @@ -267,7 +255,7 @@ "id" = REF(material), "amount" = sheet_amount, "category" = "material", - "value" = ore_values[material.type], + "value" = get_ore_points(material), // VOIDCREW EDIT - use the actual raw ore rate and point upgrade. "icon" = sheet_type::icon, "icon_state" = sheet_type::icon_state, )) diff --git a/voidcrew/modules/mining/edits/order_consumables.dm b/voidcrew/modules/mining/edits/order_consumables.dm index 884c913073c..7834622f387 100644 --- a/voidcrew/modules/mining/edits/order_consumables.dm +++ b/voidcrew/modules/mining/edits/order_consumables.dm @@ -13,3 +13,8 @@ /datum/orderable_item/consumables/rescue_hook category_index = CATEGORY_MINING cost_per_order = 350 + +/datum/orderable_item/consumables/space_cash + purchase_path = /obj/item/stack/spacecash/c500 + desc = "A 500-credit bill." + cost_per_order = 2000 diff --git a/voidcrew/modules/mining/ore_redemption.dm b/voidcrew/modules/mining/ore_redemption.dm index e5c6a09eba3..4e60fcd125f 100644 --- a/voidcrew/modules/mining/ore_redemption.dm +++ b/voidcrew/modules/mining/ore_redemption.dm @@ -1,3 +1,17 @@ // Ship ore redemption uses local storage and does not require an ore silo. /obj/machinery/mineral/ore_redemption requires_silo = FALSE + +/obj/item/stack/ore/titanium + points = 40 + +// Boulder machinery applies MINING_POINT_MACHINE_MULTIPLIER to this material rate. +/datum/material/titanium + points_per_unit = 50 / SHEET_MATERIAL_AMOUNT + +/// Quote the raw ore payout, including this ORM's point upgrade. +/obj/machinery/mineral/ore_redemption/proc/get_ore_points(datum/material/material) + var/obj/item/stack/ore/ore_type = material.ore_type + if(!ispath(ore_type, /obj/item/stack/ore)) + return 0 + return initial(ore_type.points) * point_upgrade diff --git a/voidcrew/modules/unit_tests/voidcrew_mining_qol.dm b/voidcrew/modules/unit_tests/voidcrew_mining_qol.dm index bfe702d7d6e..00a8f159f13 100644 --- a/voidcrew/modules/unit_tests/voidcrew_mining_qol.dm +++ b/voidcrew/modules/unit_tests/voidcrew_mining_qol.dm @@ -11,3 +11,73 @@ /datum/unit_test/voidcrew_mining_console_quotes_its_price/Run() var/obj/machinery/computer/order_console/mining/console_type = /obj/machinery/computer/order_console/mining TEST_ASSERT_EQUAL(initial(console_type.cargo_cost_multiplier), initial(console_type.express_cost_multiplier), "The mining console must quote the price it charges.") + +/// Exercise real material intake and its payout signal for every displayed raw ore rate. +/datum/unit_test/voidcrew_orm_quotes_actual_points + +/datum/unit_test/voidcrew_orm_quotes_actual_points/Run() + for(var/upgrade in list(1, 1.7)) + var/obj/machinery/mineral/ore_redemption/orm = allocate(/obj/machinery/mineral/ore_redemption) + orm.point_upgrade = upgrade + var/list/data = orm.ui_data(null) + var/checked_titanium = FALSE + for(var/list/entry as anything in data["materials"]) + if(entry["category"] != "material") + continue + var/datum/material/material = locate(entry["id"]) + TEST_ASSERT_NOTNULL(material, "An ORM material row must refer to a material datum.") + var/obj/item/stack/ore/ore_type = material.ore_type + if(!ispath(ore_type, /obj/item/stack/ore) || !initial(ore_type.refined_type)) + TEST_ASSERT_EQUAL(entry["value"], 0, "Materials without redeemable ore must quote zero points.") + continue + var/ore_count = 5 + var/obj/item/stack/ore/ore = allocate(ore_type, run_loc_floor_bottom_left, ore_count) + var/points_before = orm.points + TEST_ASSERT(orm.materials.insert_item(ore, orm.ore_multiplier) > 0, "The ORM must consume [ore_type] through its real intake.") + var/awarded_points = orm.points - points_before + TEST_ASSERT_EQUAL(entry["value"] * ore_count, awarded_points, "The ORM quote must match the [ore_type] payout with point_upgrade [upgrade].") + if(material.type != /datum/material/titanium) + continue + checked_titanium = TRUE + var/recovered_sheets = orm.materials.mat_container.retrieve_sheets(ore_count, material) + TEST_ASSERT_EQUAL(recovered_sheets, ore_count, "Raw titanium must retain its sheet yield.") + TEST_ASSERT_EQUAL(awarded_points, recovered_sheets * 40 * upgrade, "Raw titanium must pay 40 points per recovered sheet before point upgrades.") + TEST_ASSERT(checked_titanium, "The ORM must display titanium.") + +/datum/unit_test/voidcrew_titanium_boulder_points + +/datum/unit_test/voidcrew_titanium_boulder_points/Run() + var/datum/material/titanium = GET_MATERIAL_REF(/datum/material/titanium) + for(var/sheet_count in list(1, 5)) + var/obj/machinery/bouldertech/refinery/smelter/smelter = allocate(/obj/machinery/bouldertech/refinery/smelter) + STOP_PROCESSING(SSmachines, smelter) + var/obj/item/boulder/boulder = allocate(/obj/item/boulder, smelter) + boulder.set_custom_materials(list((titanium) = sheet_count * SHEET_MATERIAL_AMOUNT)) + boulder.durability = 0 + smelter.process() + TEST_ASSERT(QDELETED(boulder), "The smelter must consume the titanium boulder.") + var/recovered_sheets = smelter.silo_materials.mat_container.retrieve_sheets(sheet_count, titanium) + TEST_ASSERT_EQUAL(recovered_sheets, sheet_count, "Boulder titanium must retain its sheet yield.") + TEST_ASSERT_EQUAL(smelter.points_held, recovered_sheets * 40, "Boulder titanium must pay 40 points per recovered sheet after the machine multiplier.") + var/points_before = smelter.points_held + smelter.process() + TEST_ASSERT_EQUAL(smelter.points_held, points_before, "A consumed boulder must not award points twice.") + +/datum/unit_test/voidcrew_mining_cash_bill + +/datum/unit_test/voidcrew_mining_cash_bill/Run() + var/datum/orderable_item/consumables/space_cash/product = allocate(/datum/orderable_item/consumables/space_cash) + var/obj/machinery/computer/order_console/mining/console = allocate(/obj/machinery/computer/order_console/mining) + var/datum/bank_account/account = allocate(/datum/bank_account, "Mining bill test", null, 1, FALSE) + var/obj/item/card/id/card = allocate(/obj/item/card/id) + card.registered_account = account + console.grocery_list[product] = 1 + account.mining_points = 1999 + TEST_ASSERT(!console.purchase_items(card, TRUE), "A bill must not be sold for fewer than 2000 mining points.") + TEST_ASSERT_EQUAL(account.mining_points, 1999, "A refused purchase must not spend mining points.") + account.mining_points = 2000 + TEST_ASSERT(console.purchase_items(card, TRUE), "One bill must be purchasable for 2000 mining points.") + TEST_ASSERT_EQUAL(account.mining_points, 0, "One bill must spend exactly 2000 mining points.") + var/obj/item/stack/spacecash/bill = allocate(product.purchase_path) + TEST_ASSERT_EQUAL(bill.amount, 1, "One order must produce one bill.") + TEST_ASSERT_EQUAL(bill.get_item_credit_value(), 500, "The ordered bill must be worth 500 credits.") From e63180fac9b3c05a1f1812de98f040beebc2056d Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:06:53 -0700 Subject: [PATCH 011/105] Materials market prices and limits --- code/controllers/subsystem/stock_market.dm | 4 +- .../edits/modules/cargo/exports/materials.dm | 29 ++++ .../unit_tests/voidcrew_launch_cargo.dm | 127 ++++++++++++++++++ 3 files changed, 158 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/stock_market.dm b/code/controllers/subsystem/stock_market.dm index 1cce5a8c549..2481512074a 100644 --- a/code/controllers/subsystem/stock_market.dm +++ b/code/controllers/subsystem/stock_market.dm @@ -50,7 +50,7 @@ SUBSYSTEM_DEF(stock_market) var/price_minimum = round(mat.value_per_unit * SHEET_MATERIAL_AMOUNT * 0.5) if(!isnull(mat.minimum_value_override)) price_minimum = round(mat.minimum_value_override * SHEET_MATERIAL_AMOUNT) - var/price_maximum = round(mat.value_per_unit * SHEET_MATERIAL_AMOUNT * 3) + var/price_maximum = round(mat.value_per_unit * SHEET_MATERIAL_AMOUNT * 1.5) // VOIDCREW EDIT: cargo materials market ceiling. //clamp it down new_price = round(clamp(new_price, price_minimum, price_maximum)) @@ -83,7 +83,7 @@ SUBSYSTEM_DEF(stock_market) var/price_minimum = round(mat.value_per_unit * SHEET_MATERIAL_AMOUNT * 0.5) if(!isnull(mat.minimum_value_override)) price_minimum = round(mat.minimum_value_override * SHEET_MATERIAL_AMOUNT) - var/price_maximum = round(mat.value_per_unit * SHEET_MATERIAL_AMOUNT * 3) + var/price_maximum = round(mat.value_per_unit * SHEET_MATERIAL_AMOUNT * 1.5) // VOIDCREW EDIT: cargo materials market ceiling. var/price_baseline = mat.value_per_unit * SHEET_MATERIAL_AMOUNT var/quantity_baseline = mat.tradable_base_quantity diff --git a/voidcrew/edits/modules/cargo/exports/materials.dm b/voidcrew/edits/modules/cargo/exports/materials.dm index c691cbc99cf..524d8ef956b 100644 --- a/voidcrew/edits/modules/cargo/exports/materials.dm +++ b/voidcrew/edits/modules/cargo/exports/materials.dm @@ -23,3 +23,32 @@ /datum/export/material/market/plasma message = "cm3 of plasma" material_id = /datum/material/plasma + +/datum/material/diamond + value_per_unit = 120 / SHEET_MATERIAL_AMOUNT + +/datum/material/bluespace + value_per_unit = 80 / SHEET_MATERIAL_AMOUNT + +/datum/material/gold + value_per_unit = 40 / SHEET_MATERIAL_AMOUNT + +/datum/material/titanium + value_per_unit = 40 / SHEET_MATERIAL_AMOUNT + +/datum/material/uranium + value_per_unit = 30 / SHEET_MATERIAL_AMOUNT + +/datum/material/silver + value_per_unit = 15 / SHEET_MATERIAL_AMOUNT + +/datum/material/iron + value_per_unit = 2 / SHEET_MATERIAL_AMOUNT + minimum_value_override = 1 / SHEET_MATERIAL_AMOUNT + +/datum/material/glass + value_per_unit = 2 / SHEET_MATERIAL_AMOUNT + minimum_value_override = 1 / SHEET_MATERIAL_AMOUNT + +/datum/stock_market_event + price_maximum = SHEET_MATERIAL_AMOUNT * 1.5 diff --git a/voidcrew/modules/unit_tests/voidcrew_launch_cargo.dm b/voidcrew/modules/unit_tests/voidcrew_launch_cargo.dm index a0bce9de9b6..b7d69c30554 100644 --- a/voidcrew/modules/unit_tests/voidcrew_launch_cargo.dm +++ b/voidcrew/modules/unit_tests/voidcrew_launch_cargo.dm @@ -324,3 +324,130 @@ var/datum/export_report/steel_report = export_item_and_contents(plasteel, apply_elastic = FALSE, dry_run = TRUE) TEST_ASSERT_EQUAL(counterlist_sum(steel_report.total_value), 400, "Plasteel direct resale retained its former inflated material price") TEST_ASSERT(counterlist_sum(steel_report.total_value) < 630, "Repair-stock resale exceeds Barnaby's strongest special") + +/// Market tests isolate event state as well as the shared export fixture's prices. +/datum/unit_test/voidcrew_launch_cargo_fixture/material_market + abstract_type = /datum/unit_test/voidcrew_launch_cargo_fixture/material_market + var/list/base_prices = list( + /datum/material/diamond = 120, + /datum/material/bluespace = 80, + /datum/material/gold = 40, + /datum/material/titanium = 40, + /datum/material/uranium = 30, + /datum/material/silver = 15, + /datum/material/iron = 2, + /datum/material/glass = 2, + ) + var/list/saved_trends + var/list/saved_trend_life + var/list/saved_events + var/saved_news + var/list/saved_crash_sources + +/datum/unit_test/voidcrew_launch_cargo_fixture/material_market/proc/save_market() + save_economy() + saved_trends = SSstock_market.materials_trends.Copy() + saved_trend_life = SSstock_market.materials_trend_life.Copy() + saved_events = SSstock_market.active_events + SSstock_market.active_events = list() + saved_news = SSstock_market.news_string + var/list/crash_sources = GET_TRAIT_SOURCES(SSeconomy, TRAIT_MARKET_CRASHING) + saved_crash_sources = crash_sources.Copy() + REMOVE_TRAIT(SSeconomy, TRAIT_MARKET_CRASHING, saved_crash_sources) + +/datum/unit_test/voidcrew_launch_cargo_fixture/material_market/Destroy() + if(saved_trends) + QDEL_LIST(SSstock_market.active_events) + SSstock_market.active_events = saved_events + SSstock_market.materials_trends = saved_trends + SSstock_market.materials_trend_life = saved_trend_life + SSstock_market.news_string = saved_news + REMOVE_TRAIT(SSeconomy, TRAIT_MARKET_CRASHING, TRAIT_SOURCE_UNIT_TESTS) + for(var/source in saved_crash_sources) + ADD_TRAIT(SSeconomy, TRAIT_MARKET_CRASHING, source) + return ..() + +/// Trading, ordinary trends and economy-wide crashes retain their price bounds. +/datum/unit_test/voidcrew_launch_cargo_fixture/material_market/adjustments/Run() + save_market() + for(var/datum/material/material as anything in base_prices) + var/base = base_prices[material] + TEST_ASSERT_EQUAL(material.value_per_unit, base / SHEET_MATERIAL_AMOUNT, "[material] has the wrong base value per material unit") + if(material == /datum/material/iron || material == /datum/material/glass) + TEST_ASSERT_EQUAL(material.minimum_value_override * SHEET_MATERIAL_AMOUNT, 1, "[material] lost its one-credit floor") + else + TEST_ASSERT_NULL(material.minimum_value_override, "[material] must retain its half-base floor") + var/minimum = round(base * 0.5) + var/maximum = round(base * 1.5) + SSstock_market.materials_prices[material] = base + SSstock_market.adjust_material_price(material, base * 100) + TEST_ASSERT_EQUAL(SSstock_market.materials_prices[material], maximum, "[material] purchase adjustment exceeded the ceiling") + SSstock_market.adjust_material_price(material, -base * 100) + TEST_ASSERT_EQUAL(SSstock_market.materials_prices[material], minimum, "[material] sale adjustment crossed the floor") + SSstock_market.adjust_material_price(material, base - minimum) + TEST_ASSERT_EQUAL(SSstock_market.materials_prices[material], base, "[material] could not return to its base price") + + for(var/trend in list(MARKET_TREND_DOWNWARD, MARKET_TREND_STABLE, MARKET_TREND_UPWARD)) + for(var/starting_price in list(minimum, base, maximum)) + SSstock_market.materials_prices[material] = starting_price + SSstock_market.materials_trends[material] = trend + SSstock_market.materials_trend_life[material] = 1 + SSstock_market.handle_trends_and_price(material) + var/price = SSstock_market.materials_prices[material] + TEST_ASSERT(price >= minimum && price <= maximum, "[material] ordinary trend left the price bounds: [price]") + + ADD_TRAIT(SSeconomy, TRAIT_MARKET_CRASHING, TRAIT_SOURCE_UNIT_TESTS) + for(var/datum/material/material as anything in base_prices) + SSstock_market.materials_prices[material] = base_prices[material] * 1.5 + SSstock_market.handle_trends_and_price(material) + TEST_ASSERT_EQUAL(SSstock_market.materials_prices[material], round(base_prices[material] * 0.5), "[material] crash crossed its price floor") + +/// Events use their own clamp, and both reset paths restore the new base prices. +/datum/unit_test/voidcrew_launch_cargo_fixture/material_market/events/Run() + save_market() + for(var/datum/material/material as anything in base_prices) + var/base = base_prices[material] + for(var/event_type in list(/datum/stock_market_event/large_boost, /datum/stock_market_event/large_drop, /datum/stock_market_event/hotcakes, /datum/stock_market_event/market_reset)) + for(var/starting_price in list(base * 0.5, base, base * 1.5)) + SSstock_market.materials_prices[material] = starting_price + var/datum/stock_market_event/event = allocate(event_type) + TEST_ASSERT(event.start_event(material), "[event_type] failed to start for [material]") + var/price = SSstock_market.materials_prices[material] + TEST_ASSERT(price >= base * 0.5 && price <= base * 1.5, "[event_type] left [material] outside its bounds: [price]") + if(event_type == /datum/stock_market_event/hotcakes) + TEST_ASSERT_EQUAL(price, round(base * 1.5), "Hotcakes used the wrong ceiling for [material]") + if(event_type == /datum/stock_market_event/market_reset) + TEST_ASSERT_EQUAL(price, base, "Market reset restored the old base for [material]") + qdel(event) + + var/datum/stock_market_event/lockdown/lockdown = allocate(/datum/stock_market_event/lockdown) + TEST_ASSERT(lockdown.start_event(material), "Lockdown failed to start for [material]") + SSstock_market.active_events += lockdown + SSstock_market.materials_prices[material] = base * 1.5 + lockdown.handle() + TEST_ASSERT_EQUAL(SSstock_market.materials_quantity[material], 0, "Lockdown failed to suspend [material] stock") + lockdown.handle() + TEST_ASSERT_EQUAL(SSstock_market.materials_prices[material], base, "Lockdown restored the old base for [material]") + TEST_ASSERT(!(lockdown in SSstock_market.active_events), "Ended lockdown remained active") + +/// Quote the entire stack before depressing the market or its export demand. +/datum/unit_test/voidcrew_launch_cargo_fixture/material_market/diamond_stack/Run() + save_market() + SSstock_market.materials_prices[/datum/material/diamond] = 120 + SSstock_market.materials_quantity[/datum/material/diamond] = 50 + var/datum/export/material/market/diamond/exporter = locate(/datum/export/material/market/diamond) in GLOB.exports_list + TEST_ASSERT_NOTNULL(exporter, "Diamond market exporter is missing") + var/obj/item/stack/sheet/mineral/diamond/diamonds = allocate(/obj/item/stack/sheet/mineral/diamond, run_loc_floor_bottom_left, 50) + var/datum/export_report/quote = export_item_and_contents(diamonds, apply_elastic = TRUE, dry_run = TRUE) + TEST_ASSERT_EQUAL(counterlist_sum(quote.total_value), 6000, "Fifty diamonds did not quote at the full base price") + TEST_ASSERT_EQUAL(SSstock_market.materials_prices[/datum/material/diamond], 120, "Dry quote changed the market price") + TEST_ASSERT_EQUAL(SSstock_market.materials_quantity[/datum/material/diamond], 50, "Dry quote changed available stock") + TEST_ASSERT_EQUAL(exporter.cost, exporter.init_cost, "Dry quote depressed export demand") + var/datum/export_report/sale = export_item_and_contents(diamonds, apply_elastic = TRUE, dry_run = FALSE) + TEST_ASSERT_EQUAL(counterlist_sum(sale.total_value), 6000, "Market or elasticity changed before the whole-stack sale was quoted") + TEST_ASSERT_EQUAL(SSstock_market.materials_prices[/datum/material/diamond], 60, "Completed sale failed to depress the subsequent market price") + TEST_ASSERT_EQUAL(SSstock_market.materials_quantity[/datum/material/diamond], 100, "Completed sale failed to add the whole stack to stock") + TEST_ASSERT(exporter.cost < exporter.init_cost, "Completed sale failed to consume export demand") + var/depressed_cost = exporter.cost + exporter.process() + TEST_ASSERT(exporter.cost > depressed_cost && exporter.cost <= exporter.init_cost, "Export demand no longer recovers within its base limit") From 7e864735519581d33a2b28722eac5a23ca7380c5 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:13:51 -0700 Subject: [PATCH 012/105] Pay cargo-loan bonuses once --- .../modules/cargo/shipping/cargo_shuttle.dm | 14 ++- .../modules/unit_tests/voidcrew_cargo_cart.dm | 118 ++++++++++++++++++ 2 files changed, 128 insertions(+), 4 deletions(-) diff --git a/voidcrew/modules/cargo/shipping/cargo_shuttle.dm b/voidcrew/modules/cargo/shipping/cargo_shuttle.dm index 6e775ef6352..3be0a71505d 100644 --- a/voidcrew/modules/cargo/shipping/cargo_shuttle.dm +++ b/voidcrew/modules/cargo/shipping/cargo_shuttle.dm @@ -84,18 +84,24 @@ * Returns TRUE if accepted successfully */ /datum/voidcrew_cargo_shuttle/proc/accept_loan() - if(!pending_loan) + if(!pending_loan || loan_accepted) return FALSE if(state != CARGO_SHUTTLE_AWAY) return FALSE + var/datum/bank_account/receiving_account = linked_console?.bank_account_holder?.synced_bank_account + if(pending_loan.bonus_credits > 0 && QDELETED(receiving_account)) + return FALSE + loan_accepted = TRUE // Add bonus credits to the linked bank account - if(linked_console?.bank_account_holder?.synced_bank_account && pending_loan.bonus_credits > 0) - linked_console.bank_account_holder.synced_bank_account.adjust_money(pending_loan.bonus_credits) + if(pending_loan.bonus_credits > 0) + if(!receiving_account.adjust_money(pending_loan.bonus_credits)) + loan_accepted = FALSE + return FALSE record_transaction("loan", pending_loan.logging_desc, 1, pending_loan.bonus_credits) - metric_cargo_loan(pending_loan, linked_console.bank_account_holder.synced_bank_account, usr) + metric_cargo_loan(pending_loan, receiving_account, usr) // Announce acceptance if(target_ship) diff --git a/voidcrew/modules/unit_tests/voidcrew_cargo_cart.dm b/voidcrew/modules/unit_tests/voidcrew_cargo_cart.dm index bcc5cf23df7..a6b8355d79a 100644 --- a/voidcrew/modules/unit_tests/voidcrew_cargo_cart.dm +++ b/voidcrew/modules/unit_tests/voidcrew_cargo_cart.dm @@ -5,6 +5,124 @@ /obj/structure/overmap/dynamic/player_outpost/cargo_cart_test/contains_service_turf(turf/location) return location == service_turf +/// Substitute only the ship lookup; both consoles use the ship's real shared controller. +/obj/machinery/computer/voidcrew_cargo/cargo_loan_test + var/obj/structure/overmap/ship/loan_ship + +/obj/machinery/computer/voidcrew_cargo/cargo_loan_test/get_cargo_shuttle() + if(QDELETED(loan_ship)) + return null + return loan_ship.get_cargo_shuttle() + +/obj/machinery/computer/voidcrew_cargo/cargo_loan_test/Destroy() + . = ..() + loan_ship = null + +/// Exercise failed deposits without changing normal account bookkeeping. +/datum/bank_account/cargo_loan_test + var/refuse_payment = FALSE + +/datum/bank_account/cargo_loan_test/adjust_money(amount, reason) + if(refuse_payment) + return FALSE + return ..() + +/datum/unit_test/voidcrew_cargo_loan_once/Run() + var/obj/structure/overmap/ship/ship = allocate(__IMPLIED_TYPE__) + var/datum/voidcrew_cargo_shuttle/ferry = ship.get_cargo_shuttle() + var/obj/machinery/computer/voidcrew_cargo/cargo_loan_test/console = allocate(__IMPLIED_TYPE__) + var/obj/machinery/computer/voidcrew_cargo/cargo_loan_test/other_console = allocate(__IMPLIED_TYPE__) + console.loan_ship = ship + other_console.loan_ship = ship + TEST_ASSERT_EQUAL(console.get_cargo_shuttle(), ferry, "The first console must resolve the ship's shared loan offer.") + TEST_ASSERT_EQUAL(other_console.get_cargo_shuttle(), ferry, "The second console must resolve the same loan offer.") + var/obj/machinery/computer/bank_machine/bank = allocate(__IMPLIED_TYPE__) + var/datum/bank_account/account = allocate(/datum/bank_account, "Cargo loan test", null, 1, FALSE) + account.account_balance = 1000 + bank.synced_bank_account = account + console.link_ship_bank(bank) + other_console.link_ship_bank(bank) + ferry.linked_console = console + var/mob/living/carbon/human/consistent/user = allocate(__IMPLIED_TYPE__) + var/datum/tgui/ui = allocate(/datum/tgui, user, console, "Cargo") + var/datum/tgui/other_ui = allocate(/datum/tgui, user, other_console, "Cargo") + var/datum/callback/accept = CALLBACK(console, TYPE_PROC_REF(/datum, ui_act), "accept_loan", list(), ui) + var/datum/callback/other_accept = CALLBACK(other_console, TYPE_PROC_REF(/datum, ui_act), "accept_loan", list(), other_ui) + TEST_ASSERT(ferry.receive_loan_offer(/datum/voidcrew_shuttle_loan), "The idle shuttle must receive a loan offer.") + var/datum/voidcrew_shuttle_loan/first_offer = ferry.pending_loan + first_offer.bonus_credits = 100 + + for(var/repeat in 1 to 3) + world.push_usr(user, accept) + world.push_usr(user, other_accept) + TEST_ASSERT(ferry.loan_accepted, "A loan accepted through the console must latch on the shared controller.") + TEST_ASSERT(!ferry.accept_loan(), "A repeated direct acceptance must also be rejected.") + TEST_ASSERT_EQUAL(account.account_balance, 1100, "Repeated acceptance through two consoles must pay only once.") + TEST_ASSERT_EQUAL(length(ferry.transaction_history), 1, "Repeated acceptance must create one transaction.") + var/list/entry = ferry.transaction_history[1] + TEST_ASSERT_EQUAL(entry["type"], "loan", "The single transaction must be the loan bonus.") + TEST_ASSERT_EQUAL(entry["value"], 100, "The loan transaction must record exactly the paid bonus.") + + // A failed arrival runs the real cleanup path and permits delivery to be retried. + for(var/retry in 1 to 2) + ferry.state = 1 // CARGO_SHUTTLE_ARRIVING; Voidcrew defines load after unit tests. + TEST_ASSERT(!ferry.complete_arrival(), "An arrival without a destination must fail.") + TEST_ASSERT_EQUAL(ferry.state, initial(ferry.state), "Failed delivery must return the shuttle to AWAY.") + TEST_ASSERT(ferry.loan_accepted, "Failed delivery must retain the acceptance latch.") + TEST_ASSERT_EQUAL(ferry.pending_loan, first_offer, "Failed delivery must retain the accepted offer.") + world.push_usr(user, other_accept) + TEST_ASSERT_EQUAL(account.account_balance, 1100, "Retrying delivery and acceptance must not pay again.") + TEST_ASSERT_EQUAL(length(ferry.transaction_history), 1, "Delivery retries must not duplicate bonus history.") + + ferry.decline_loan() + TEST_ASSERT_NULL(ferry.pending_loan, "Clearing an offer must remove it.") + TEST_ASSERT(!ferry.loan_accepted, "Clearing an offer must release its acceptance latch.") + TEST_ASSERT(ferry.receive_loan_offer(/datum/voidcrew_shuttle_loan), "A fresh offer must be available after the previous offer is cleared.") + ferry.pending_loan.bonus_credits = 100 + world.push_usr(user, other_accept) + world.push_usr(user, accept) + TEST_ASSERT(ferry.loan_accepted, "The fresh offer must accept normally.") + TEST_ASSERT_EQUAL(account.account_balance, 1200, "A fresh offer must pay one new bonus.") + TEST_ASSERT_EQUAL(length(ferry.transaction_history), 2, "Each distinct paid offer must have one history entry.") + +/datum/unit_test/voidcrew_cargo_loan_payment/Run() + var/datum/voidcrew_cargo_shuttle/ferry = allocate(__IMPLIED_TYPE__) + var/obj/machinery/computer/voidcrew_cargo/console = allocate(__IMPLIED_TYPE__) + var/obj/machinery/computer/bank_machine/bank = allocate(__IMPLIED_TYPE__) + console.link_ship_bank(bank) + ferry.linked_console = console + TEST_ASSERT(ferry.receive_loan_offer(/datum/voidcrew_shuttle_loan), "The idle shuttle must receive a loan offer.") + var/datum/voidcrew_shuttle_loan/offer = ferry.pending_loan + offer.bonus_credits = 100 + TEST_ASSERT(!ferry.accept_loan(), "A positive bonus must require a receiving account.") + TEST_ASSERT(!ferry.loan_accepted, "A missing account must leave the offer unaccepted.") + TEST_ASSERT_EQUAL(ferry.pending_loan, offer, "A missing account must leave the offer available.") + TEST_ASSERT_EQUAL(length(ferry.transaction_history), 0, "A missing account must not record a bonus.") + + var/datum/bank_account/cargo_loan_test/account = allocate(/datum/bank_account/cargo_loan_test, "Cargo loan test", null, 1, FALSE) + account.account_balance = 1000 + account.refuse_payment = TRUE + bank.synced_bank_account = account + TEST_ASSERT(!ferry.accept_loan(), "Failed bonus payment must reject acceptance.") + TEST_ASSERT(!ferry.loan_accepted, "Failed payment must release the acceptance latch.") + TEST_ASSERT_EQUAL(ferry.pending_loan, offer, "Failed payment must leave the same offer available.") + TEST_ASSERT_EQUAL(account.account_balance, 1000, "Failed payment must leave the balance unchanged.") + TEST_ASSERT_EQUAL(length(ferry.transaction_history), 0, "Failed payment must not record a transaction.") + account.refuse_payment = FALSE + TEST_ASSERT(ferry.accept_loan(), "Restoring payment must allow the same offer to be accepted.") + TEST_ASSERT_EQUAL(account.account_balance, 1100, "The retried payment must pay exactly one bonus.") + TEST_ASSERT_EQUAL(length(ferry.transaction_history), 1, "Only the successful payment must enter history.") + + ferry.decline_loan() + TEST_ASSERT(ferry.receive_loan_offer(/datum/voidcrew_shuttle_loan), "A zero-bonus offer must be available normally.") + ferry.pending_loan.bonus_credits = 0 + bank.synced_bank_account = null + TEST_ASSERT(ferry.accept_loan(), "A zero-bonus offer must accept without a receiving account.") + TEST_ASSERT(ferry.loan_accepted, "A zero-bonus acceptance must still latch.") + TEST_ASSERT(!ferry.accept_loan(), "A zero-bonus offer must also reject repeated acceptance.") + TEST_ASSERT_EQUAL(account.account_balance, 1100, "A zero-bonus offer must leave the balance unchanged.") + TEST_ASSERT_EQUAL(length(ferry.transaction_history), 1, "A zero-bonus offer must not record a payment.") + /datum/unit_test/voidcrew_cargo_clear_cart/Run() var/obj/structure/overmap/dynamic/player_outpost/cargo_cart_test/home = allocate(__IMPLIED_TYPE__) home.service_turf = run_loc_floor_bottom_left From 7cea6c66a9557dbb8da98ae39ff9a55ad154ae31 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:20:03 -0700 Subject: [PATCH 013/105] Reduce the healthy-rescue bonus --- voidcrew/modules/missions/missions/rescue.dm | 14 +---- .../modules/missions/objectives/site_ops.dm | 6 +- .../modules/unit_tests/voidcrew_missions.dm | 58 +++++++++++++++++++ 3 files changed, 64 insertions(+), 14 deletions(-) diff --git a/voidcrew/modules/missions/missions/rescue.dm b/voidcrew/modules/missions/missions/rescue.dm index 3d711f9e9dd..3e542031045 100644 --- a/voidcrew/modules/missions/missions/rescue.dm +++ b/voidcrew/modules/missions/missions/rescue.dm @@ -1,8 +1,7 @@ /** * # Rescue & Repatriation * - * "A survivor's beacon is still pinging inside that wreck. Bring them back - * breathing - the fee doubles if they can still walk." + * "A survivor's beacon is still pinging inside that wreck. Bring them home alive." * * Recovery variant where the objective breathes: a survivor NPC spawns in * the target ruin, follows whoever asks (or rides a fireman carry), and the @@ -20,7 +19,7 @@ // The survivor cannot defend themselves, so this contract does not share a // wreck with a bounty's entourage or anybody else's spawns exclusive_site = TRUE - // Green-band pay; the unharmed bonus doubles credits at turn-in + // Green-band base pay value_min = 800 value_max = 1100 @@ -46,15 +45,8 @@ add_objective(new /datum/mission_objective/field/escort) /datum/mission/rescue/update_text() - var/datum/mission_objective/field/escort/escort = objectives[1] name = "Rescue Contract: [objective_name]" - desc = "A [objective_name]'s survival beacon is still pinging inside the signal at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - Bring them back alive, on or beside your ship's mission pad, then turn in at the mission board. \ - The credit fee doubles if they arrive with at least [escort.unharmed_threshold * 100]% health and have not needed revival. \ - They'll follow whoever offers a hand, or ride a fireman carry. \ - If their vitals stop, revive them within [DisplayTimeText(escort.revival_grace)] to save the contract, minus the bonus. \ - Payment includes [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]. \ - Tap a GPS unit on the mission board to receive the survivor's beacon ([gps_tag])." + desc = "A [objective_name]'s survival beacon is still pinging at ([target.target_x], [target.target_y]) in the [target_zone_name]. Bring them home alive." /datum/mission/rescue/waypoint_label() return "Rescue: [objective_name]" diff --git a/voidcrew/modules/missions/objectives/site_ops.dm b/voidcrew/modules/missions/objectives/site_ops.dm index ccc592049ee..c8d8e4e7b2e 100644 --- a/voidcrew/modules/missions/objectives/site_ops.dm +++ b/voidcrew/modules/missions/objectives/site_ops.dm @@ -305,7 +305,7 @@ /// Health fraction at turn-in for the "still walking" pay bonus var/unharmed_threshold = 0.8 /// Multiplier applied to mission credits when unharmed - var/unharmed_bonus = 2 + var/unharmed_bonus = 1.25 /// How long a flatlined survivor stays recoverable before the contract writes them off var/revival_grace = 3 MINUTES /// Timer id for the grace window; non-null exactly while the survivor is down @@ -439,11 +439,11 @@ if(QDELETED(survivor)) return clear_grace() - // Still walking pays double - somebody who had to be brought back doesn't count, + // Somebody who had to be brought back doesn't count toward the unharmed bonus, // however healthy the revival left them if(!was_revived && survivor.health >= survivor.maxHealth * unharmed_threshold) mission.value *= unharmed_bonus - notify_crew("Survivor recovered unharmed - fee doubled.") + notify_crew("Survivor recovered unharmed.") // Repatriation: they step onto the pad and ship out var/mob/living/leaving = survivor UnregisterSignal(leaving, list(COMSIG_LIVING_DEATH, COMSIG_LIVING_REVIVE)) diff --git a/voidcrew/modules/unit_tests/voidcrew_missions.dm b/voidcrew/modules/unit_tests/voidcrew_missions.dm index 59b49bc4b11..9fb5975818f 100644 --- a/voidcrew/modules/unit_tests/voidcrew_missions.dm +++ b/voidcrew/modules/unit_tests/voidcrew_missions.dm @@ -263,6 +263,64 @@ ruin.loaded = saved_loaded[ruin] ruin.mission_claims = saved_claims[ruin] +/// Rescue bonuses affect credits alone, once, and never return after revival. +/datum/unit_test/voidcrew_mission_rescue_reward/Run() + var/turf/pad_turf = run_loc_floor_bottom_left + var/obj/machinery/mission_pad/pad = allocate(/obj/machinery/mission_pad, pad_turf) + var/obj/structure/overmap/ship/ship = allocate(/obj/structure/overmap/ship) + ship.ship_account = allocate(/datum/bank_account/ship, "Rescue Test", null, 1, FALSE) + ship.linked_mission_pads = list(pad) + var/datum/mission/rescue/rescue_type = /datum/mission/rescue + var/expected_vouchers = 0 + var/list/delivery_cases = list( + list("healthy", 0, FALSE, 1250), + list("80% health", 12, FALSE, 1250), + list("injured", 13, FALSE, 1000), + list("revived and healed", 13, TRUE, 1000), + ) + for(var/list/delivery_case as anything in delivery_cases) + var/datum/mission/mission = allocate(/datum/mission) + mission.value = 1000 + mission.voucher_count = initial(rescue_type.voucher_count) + mission.servant = ship + var/datum/mission_objective/field/escort/escort = new + mission.add_objective(escort) + escort.spawn_field_objects(pad_turf) + var/mob/living/survivor = escort.survivor + survivor.adjustBruteLoss(delivery_case[2]) + if(delivery_case[3]) + survivor.death() + TEST_ASSERT(escort.grace_timer, "The survivor's death must start the revival window") + survivor.revive(ADMIN_HEAL_ALL) + TEST_ASSERT(survivor.stat != DEAD, "The survivor must actually revive") + TEST_ASSERT_EQUAL(survivor.health, survivor.maxHealth, "The revived survivor must be fully healed") + TEST_ASSERT(escort.was_revived, "Healing must preserve the survivor's revival history") + TEST_ASSERT_NULL(escort.grace_timer, "Revival must clear the recovery timer") + var/balance_before = ship.ship_account.account_balance + expected_vouchers += mission.voucher_count + TEST_ASSERT(mission.turn_in(pad), "The [delivery_case[1]] survivor must be accepted") + TEST_ASSERT_EQUAL(ship.ship_account.account_balance - balance_before, delivery_case[4], "The [delivery_case[1]] survivor paid the wrong credits") + TEST_ASSERT(QDELETED(survivor), "The delivered survivor must be removed") + TEST_ASSERT(QDELETED(mission), "Delivering the survivor must complete the mission") + var/vouchers_paid = 0 + for(var/obj/item/stack/trade_voucher/vouchers in pad_turf) + vouchers_paid += vouchers.amount + TEST_ASSERT_EQUAL(vouchers_paid, expected_vouchers, "The [delivery_case[1]] survivor must leave the voucher payout unchanged") + + // Exercise the finalizer twice while the mission and objective still exist. + var/datum/mission/repeated = allocate(/datum/mission) + repeated.value = 1000 + repeated.voucher_count = initial(rescue_type.voucher_count) + var/datum/mission_objective/field/escort/repeated_escort = new + repeated.add_objective(repeated_escort) + repeated_escort.survivor = allocate(/mob/living/basic/mission_survivor, pad_turf) + repeated_escort.on_turn_in_finalized(pad) + TEST_ASSERT_EQUAL(repeated.value, 1250, "A healthy survivor must add 25% to credits") + TEST_ASSERT_NULL(repeated_escort.survivor, "Finalization must clear the survivor reference") + repeated_escort.on_turn_in_finalized(pad) + TEST_ASSERT_EQUAL(repeated.value, 1250, "Repeated finalization must not stack the bonus") + TEST_ASSERT_EQUAL(repeated.voucher_count, initial(rescue_type.voucher_count), "Repeated finalization must not change vouchers") + /** * A contract that marks itself exclusive_site must get a wreck to itself. * From fcb53feedb67b3f1497be4d25fa94d30c5ec17bb Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:28:31 -0700 Subject: [PATCH 014/105] Research-only orbital surveys --- .../interfaces/SurveyComputer.tsx | 108 ++--------------- .../overmap/code/modules/overmap/_overmap.dm | 4 +- .../modules/shuttle/survey/survey_computer.dm | 86 +++---------- .../modules/shuttle/survey/survey_designs.dm | 55 ++++++--- .../unit_tests/voidcrew_launch_progression.dm | 25 ++-- .../voidcrew_survey_capabilities.dm | 114 ++++++++++++++++++ 6 files changed, 206 insertions(+), 186 deletions(-) diff --git a/tgui/packages/voidcrew_tgui/interfaces/SurveyComputer.tsx b/tgui/packages/voidcrew_tgui/interfaces/SurveyComputer.tsx index bf6e5b4eafc..d4656273a3d 100644 --- a/tgui/packages/voidcrew_tgui/interfaces/SurveyComputer.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/SurveyComputer.tsx @@ -67,7 +67,6 @@ interface SurveyTarget { atRange: number; dist: number; points: number; - cash: number; mappable: number; /** Seconds the charted surface stays generated, or null when it is not counting down. */ holdSeconds: number | null; @@ -86,7 +85,6 @@ function formatHold(seconds: number): string { interface Data { archiveMode: number; researchLinked: number; - bankedCash: number; bankedPoints: number; currentCelestialRef: string; currentCelestialType: string; @@ -94,11 +92,9 @@ interface Data { mappingEnabled?: number; shipMoving: number; surveyAtRange?: number; - rangeSurveyDistance?: number; - rangeSurveyPercent?: number; surveyStatus?: 'unsurveyed' | 'complete' | 'in-progress' | 'no-orbit'; surveyTargets?: SurveyTarget[]; - surveyValue: { cash: number; points: number }; + surveyValue: { points: number }; surveyDataDisk: number; theme?: string; } @@ -219,18 +215,6 @@ export const SurveyComputer = () => { > Surveying - { - setTab(8); - }} - > - Banking - { ) : tab === 7 ? ( - ) : tab === 8 ? ( - ) : tab === 9 ? ( ) : ( @@ -423,8 +405,8 @@ const SurveyArchive = () => { {data.researchLinked - ? 'Completed records are synchronized with the linked local research server.' - : 'Link a local research server with a multitool to use completed survey records for research.'} + ? 'Research server connected.' + : 'No research server connected.'}
@@ -464,15 +446,7 @@ const SurveyArchive = () => { const Surveying = () => { const { act, data } = useBackend(); - const { - bankedCash, - theme, - bankedPoints, - shipMoving, - surveyTargets = [], - rangeSurveyDistance = 3, - rangeSurveyPercent = 60, - } = data; + const { theme, bankedPoints, shipMoving, surveyTargets = [] } = data; interface Option { content: string; @@ -509,40 +483,24 @@ const Surveying = () => { : { content: 'Start survey', action: 'survey', - tooltip: - selectedTarget.points && selectedTarget.cash - ? `Value: ${selectedTarget.points} points | ${selectedTarget.cash} credits` - : undefined, }; const notices: string[] = []; if (shipMoving === 0) { - notices.push('Ship is currently moving, surveying disabled'); - } - - if ( - selectedTarget && - selectedTarget.atRange === 1 && - selectedTarget.status === 'unsurveyed' - ) { - notices.push('Storm targeted at range: reduced survey yield'); + notices.push('Ship in motion'); } if (selectedTarget && selectedTarget.holdSeconds !== null) { notices.push( `Charted surface of ${selectedTarget.name} holds for ${formatHold( selectedTarget.holdSeconds, - )} — land within that window or it drifts to another sector`, + )}`, ); } if (bankedPoints && bankedPoints !== 0) { - notices.push(`You have ${bankedPoints} research points to print`); - } - - if (bankedCash && bankedCash !== 0) { - notices.push(`You have ${bankedCash} credits to cash out`); + notices.push(`Research awaiting print: ${bankedPoints}`); } const currentThemeColors = theme ? getThemeColors(theme) : undefined; @@ -578,12 +536,6 @@ const Surveying = () => {
- - Surveying needs the ship stationary on the same overmap tile as the - target — no docking or landing required. Electric and EMP storms can - also be scanned from up to {rangeSurveyDistance} tiles away at{' '} - {rangeSurveyPercent}% yield. - {surveyTargets.length > 0 ? ( {surveyTargets.map((target) => { @@ -616,6 +568,9 @@ const Surveying = () => {
+ {selectedTarget?.status === 'unsurveyed' ? ( + Research: {selectedTarget.points} + ) : null} - - - - You currently have ${bankedCash} to withdrawal - - - - ); -}; - const Research = () => { const { act, data } = useBackend(); const { bankedPoints, surveyStatus, theme } = data; @@ -1449,7 +1363,7 @@ const Research = () => { textColor={currentThemeColors?.noticeText} textAlign="center" > - You currently have {bankedPoints} research points to print + Research awaiting print: {bankedPoints} diff --git a/voidcrew/modules/overmap/code/modules/overmap/_overmap.dm b/voidcrew/modules/overmap/code/modules/overmap/_overmap.dm index 81adfc4bcfb..1ad6965e29c 100644 --- a/voidcrew/modules/overmap/code/modules/overmap/_overmap.dm +++ b/voidcrew/modules/overmap/code/modules/overmap/_overmap.dm @@ -18,8 +18,8 @@ GLOBAL_LIST_EMPTY(overmap_objects) ///List of other overmap objects in the same tile var/list/close_overmap_objects var/surveyed = FALSE - /// Research points (and credits) an orbital survey of this object banks, before the - /// first-survey bonus and console tier multipliers (see survey_computer.dm + /// Research points an orbital survey of this object banks, before console tier, + /// target zone and remote-storm multipliers (see survey_computer.dm /// get_survey_value). Set it on the family's base type and every subtype inherits it, /// so storm severities, planet terrains and star classes are all worth what their /// family is worth. 0 is "nothing to learn here" - the default for everything that diff --git a/voidcrew/modules/shuttle/survey/survey_computer.dm b/voidcrew/modules/shuttle/survey/survey_computer.dm index fb691d57832..c567c3a1e43 100644 --- a/voidcrew/modules/shuttle/survey/survey_computer.dm +++ b/voidcrew/modules/shuttle/survey/survey_computer.dm @@ -5,7 +5,7 @@ /obj/machinery/computer/camera_advanced/shuttle_docker/survey name = "Orbital survey console" - desc = "Gather data, earn research points, and control how your ship docks on celestial objects around the void. Surveys only need the ship parked on the same overmap tile as the target, not docked or landed; storms can also be scanned from a few tiles away at reduced yield. On outpost ground, it imports and exports completed survey records for local research." + desc = "An orbital cartography and survey terminal." view_range = 10 x_offset = 0 y_offset = -5 @@ -37,8 +37,6 @@ var/range_survey_distance = 3 var/survey_timer var/banked_points = 0 - var/banked_cash = 0 - var/list/banking = list() var/datum/techweb/linked_techweb var/theme var/attached_to_ship = FALSE @@ -231,8 +229,7 @@ if(linked_techweb) . += span_notice("It is feeding survey data to the R&D server network of [linked_techweb.organization].") return - . += span_warning("It is not linked to an R&D server, so surveys will not unlock survey-gated research.") - . += span_notice("Build an R&D server on this ship, or copy a techweb from one with a [EXAMINE_HINT("multitool")] and use it on this.") + . += span_warning("It is not linked to an R&D server.") /obj/machinery/computer/camera_advanced/shuttle_docker/survey/proc/update_survey_data() sync_research_surveys() @@ -371,12 +368,9 @@ tgui_data["archiveMode"] = !attached_to_ship tgui_data["researchLinked"] = !!linked_techweb tgui_data["bankedPoints"] = banked_points - tgui_data["bankedCash"] = banked_cash - tgui_data["surveyValue"] = get_survey_value(celestial_object) + var/list/quote = get_survey_value(celestial_object) + tgui_data["surveyValue"] = list("points" = quote ? quote["points"] : 0) tgui_data["surveyAtRange"] = is_survey_at_range(celestial_object) - // So the UI can state the range rule with the real numbers instead of folklore - tgui_data["rangeSurveyDistance"] = range_survey_distance - tgui_data["rangeSurveyPercent"] = round(range_survey_value_mult * 100) tgui_data["theme"] = theme tgui_data["surveyDataDisk"] = validate_survey_disk() tgui_data["mappingEnabled"] = (istype(celestial_object, /obj/structure/overmap/planet) || istype(celestial_object, /obj/structure/overmap/space_ruin) || istype(celestial_object, /obj/structure/overmap/event/meteor)) ? mapping_enabled : FALSE @@ -394,7 +388,6 @@ "atRange" = at_range, "dist" = (at_range && ship_turf) ? get_dist(ship_turf, get_turf(candidate)) : 0, "points" = values ? values["points"] : 0, - "cash" = values ? values["cash"] : 0, "holdSeconds" = get_interior_hold_seconds(candidate), "mappable" = (istype(candidate, /obj/structure/overmap/planet) || istype(candidate, /obj/structure/overmap/space_ruin) || istype(candidate, /obj/structure/overmap/event/meteor)) ? mapping_enabled : FALSE, )) @@ -408,6 +401,9 @@ .["surveyData"] = data?.tgui_serialize() /obj/machinery/computer/camera_advanced/shuttle_docker/survey/ui_act(action, list/params, datum/tgui/ui) + // Old windows and forged actions cannot redeem survey currency. + if(action == "cashOut") + return FALSE if(!validate_ship_binding()) if(!get_outpost_from_atom(src) || !(action in list("saveData", "downloadData", "eject", "setTheme", "refresh", "error"))) return TRUE @@ -422,8 +418,6 @@ activate_survey_map(ui.user) if("printResearch") print_survey_notes(ui.user) - if("cashOut") - cash_out(ui.user) if("setTheme") theme = params["theme"] if("saveData") @@ -594,7 +588,6 @@ has_empty_space = TRUE if(has_ship_contact) balloon_alert(user, "can't survey ships") - to_chat(user, span_warning("Vessels are not valid survey targets. The console only surveys celestial objects: planets, signals, storms, and stars.")) else if(has_empty_space) balloon_alert(user, "empty space, nothing to survey") else @@ -644,21 +637,17 @@ var/list/values = get_survey_value(object) if(values) banked_points += values["points"] - banked_cash += values["cash"] record_metric_survey(object, values) // round metrics, voidcrew/modules/metrics/research_metrics.dm data.update_survey_data(object) sync_research_surveys() object.surveyed = TRUE update_static_data_for_all_viewers() - // A surface charted from orbit is on a cleanup clock the crew has no other way to - // see: nothing docked, so no arrival and no departure ever told them the planet is - // only held for a while. Say it once, with the real number. var/obj/structure/overmap/planet/charted = astype(object, /obj/structure/overmap/planet) var/hold_remaining = charted?.get_interior_hold_remaining() if(hold_remaining && ship_port?.current_ship) ship_port.current_ship.ship_notify( - "Surface chart of [charted.display_name || charted.name] holds for [DisplayTimeText(hold_remaining)]. Land within that window or the planet drifts and has to be charted again.", + "Surface chart of [charted.display_name || charted.name] recorded.", "SURVEY", SHIP_NOTIFY_NOTICE, 'voidcrew/sound/notify.ogg', @@ -674,41 +663,35 @@ if(!object) return - var/point_list = list() + // Refresh the physical research link for quotes and completion alike. + survey_research_tiers = get_survey_research_tiers() + var/point_list = list("cash" = 0, "points" = 0) // The payout lives on the overmap object (survey_value, see _overmap.dm) rather than // in a table keyed by type name here - almost nothing spawns as its family's base // type, so storm severities, planet terrains, fixed-gas nebulas and star classes all // used to fall through to nothing. 0 is anything that isn't a celestial body. var/points = object.survey_value - var/cash = object.survey_value if(!points) - point_list["cash"] = 0 - point_list["points"] = 0 return point_list - // Extra rewards for being the first to survey an object - if (!object.surveyed) - cash *= 1.2 - points *= 1.2 - if("elite" in survey_research_tiers) - cash *= 2 - points *= 2 + points *= 1.25 else if("superior" in survey_research_tiers) - cash *= 1.5 - points *= 1.5 - else if("advanced" in survey_research_tiers) - cash *= 1.2 - points *= 1.2 + points *= 1.1 + + // A remote storm can be across a zone boundary from the ship. + switch(SSovermap_zones.get_zone_type(get_turf(object))) + if(ZONE_YELLOW) + points *= 1.25 + if(ZONE_RED) + points *= 1.5 // Scanning a storm from a neighbouring tile is safe, so it pays less if(is_survey_at_range(object)) - cash *= range_survey_value_mult points *= range_survey_value_mult - point_list["cash"] = cash point_list["points"] = points return point_list @@ -818,35 +801,6 @@ record_metric_notes_printed(user, banked_points) // round metrics, voidcrew/modules/metrics/research_metrics.dm banked_points = 0 -/obj/machinery/computer/camera_advanced/shuttle_docker/survey/proc/cash_out(mob/user) - if(banked_cash <= 0) - return - - var/remaining_amount = banked_cash - banked_cash = 0 - record_metric_cash_out(user, remaining_amount) // round metrics, voidcrew/modules/metrics/research_metrics.dm - - var/static/list/bill_denominations = list( - /obj/item/stack/spacecash/c10000 = 10000, - /obj/item/stack/spacecash/c1000 = 1000, - /obj/item/stack/spacecash/c500 = 500, - /obj/item/stack/spacecash/c200 = 200, - /obj/item/stack/spacecash/c100 = 100, - /obj/item/stack/spacecash/c50 = 50, - /obj/item/stack/spacecash/c20 = 20, - /obj/item/stack/spacecash/c10 = 10, - /obj/item/stack/spacecash/c1 = 1, - ) - - playsound(src, 'sound/items/taperecorder/taperecorder_print.ogg', 60) - playsound(src, 'sound/items/handling/paper_drop.ogg', 60) - - for(var/bill_type in bill_denominations) - var/bill_value = bill_denominations[bill_type] - while(remaining_amount >= bill_value) - remaining_amount -= bill_value - new bill_type(loc) - /obj/machinery/computer/camera_advanced/shuttle_docker/survey/checkLandingTurf(turf/T, list/overlappers) . = ..() diff --git a/voidcrew/modules/shuttle/survey/survey_designs.dm b/voidcrew/modules/shuttle/survey/survey_designs.dm index 802dc4bc177..8e27ad9ba4b 100644 --- a/voidcrew/modules/shuttle/survey/survey_designs.dm +++ b/voidcrew/modules/shuttle/survey/survey_designs.dm @@ -1,6 +1,6 @@ /datum/design/survey_data_disk name = "Survey data storage disk" - desc = "Unlocks the survey data storage disk." + desc = "A disk for celestial survey records." id = "survey_data_disk" build_type = PROTOLATHE materials = list(/datum/material/iron =SMALL_MATERIAL_AMOUNT * 3, /datum/material/glass =SMALL_MATERIAL_AMOUNT) @@ -22,7 +22,7 @@ // Allows shuttle docking /datum/design/survey_ship_docking name = "Orbital survey mapping" - desc = "Upgrades your survey console to allow you to view a map of the planet and control where your ship docks" + desc = "Orbital cartography software." id = "survey_ship_docking" research_icon = 'voidcrew/icons/effects/overmap.dmi' research_icon_state = "globe" @@ -30,28 +30,28 @@ // Sight capabilities - Can we view mobs, objects, turfs, etc /datum/design/survey_map_obj_sight name = "Survey mapping upgrade - Visible objects" - desc = "Upgrades your survey console capabilities to show flora and objects when using the map" + desc = "Surface imaging software." id = "survey_map_obj_sight" research_icon = 'voidcrew/icons/effects/overmap.dmi' research_icon_state = "globe" /datum/design/survey_map_mob_sight name = "Survey mapping upgrade - Visible lifeforms" - desc = "Upgrades your survey mapping system to show lifeforms when using the map" + desc = "Biosignature imaging software." id = "survey_map_mob_sight" research_icon = 'voidcrew/icons/effects/overmap.dmi' research_icon_state = "globe" /datum/design/survey_map_range_upg_superior name = "Survey mapping upgrade - Superior view range" - desc = "Upgrades your survey mapping system to have a larger field of view" + desc = "Wide-field cartography software." id = "survey_map_range_upg_superior" research_icon = 'voidcrew/icons/effects/overmap.dmi' research_icon_state = "globe" /datum/design/survey_map_range_upg_elite name = "Survey mapping upgrade - Elite view range" - desc = "Upgrades your survey mapping system to have a larger field of view" + desc = "Panoramic cartography software." id = "survey_map_range_upg_elite" research_icon = 'voidcrew/icons/effects/overmap.dmi' research_icon_state = "globe" @@ -59,28 +59,28 @@ // Rewards upgrades /datum/design/survey_console_rewards_upgrade_basic name = "Survey basic rewards" - desc = "Your survey console will produce a small amount of research points and money per survey" + desc = "Standard survey analysis software." id = "survey_console_rewards_upgrade_basic" research_icon = 'icons/obj/economy.dmi' research_icon_state = "spacecash1" /datum/design/survey_console_rewards_upgrade_advanced name = "Survey rewards advanced upgrade" - desc = "Upgrades your survey console to produce more research points and money" + desc = "Refined survey analysis software." id = "survey_console_rewards_upgrade_advanced" research_icon = 'icons/obj/economy.dmi' research_icon_state = "spacecash1_2" /datum/design/survey_console_rewards_upgrade_superior name = "Survey rewards superior upgrade" - desc = "Upgrades your survey console to produce a large amount of research points and money" + desc = "Precision survey analysis software." id = "survey_console_rewards_upgrade_superior" research_icon = 'icons/obj/economy.dmi' research_icon_state = "spacecash1_3" /datum/design/survey_console_rewards_upgrade_elite name = "Survey rewards elite upgrade" - desc = "Upgrades your survey console to produce a ton of research points and money" + desc = "Advanced survey analysis software." id = "survey_console_rewards_upgrade_elite" research_icon = 'icons/obj/economy.dmi' research_icon_state = "spacecash1_4" @@ -88,28 +88,55 @@ // Information upgrades /datum/design/survey_console_information_upgrade_basic name = "Survey basic information upgrade" - desc = "Grants you basic planetary information about a planet" + desc = "Planetary cataloguing software." id = "survey_console_information_upgrade_basic" research_icon = 'icons/obj/service/bureaucracy.dmi' research_icon_state = "paperslip_words" /datum/design/survey_console_information_upgrade_advanced name = "Survey advanced information upgrade" - desc = "Grants you access to the hostility level of a planet" + desc = "Planetary hazard analysis software." id = "survey_console_information_upgrade_advanced" research_icon = 'icons/obj/service/bureaucracy.dmi' research_icon_state = "paper_stack_words" /datum/design/survey_console_information_upgrade_superior name = "Survey superior information upgrade" - desc = "Grants you information about the life forms and structures found on a planet" + desc = "Planetary biosignature analysis software." id = "survey_console_information_upgrade_superior" research_icon = 'icons/obj/service/bureaucracy.dmi' research_icon_state = "docs_part" /datum/design/survey_console_information_upgrade_elite name = "Survey elite information upgrade" - desc = "Grants you even more information about things found on a planet" + desc = "Comprehensive planetary analysis software." id = "survey_console_information_upgrade_elite" research_icon = 'icons/obj/service/bureaucracy.dmi' research_icon_state = "docs_red" + +// Research-only survey bases. All variants inherit their family's value. +/obj/structure/overmap/star + survey_value = 250 + +/obj/structure/overmap/planet + survey_value = 150 + +/obj/structure/overmap/space_ruin + survey_value = 75 + +/obj/structure/overmap/event/emp + survey_value = 100 + +/obj/structure/overmap/event/electric + survey_value = 75 + +/obj/structure/overmap/event/meteor + survey_value = 50 + +// Dangerous nebulae share this base pending the owner's balance decision. +#define SURVEY_NEBULA_BASE 25 + +/obj/structure/overmap/event/nebula + survey_value = SURVEY_NEBULA_BASE + +#undef SURVEY_NEBULA_BASE diff --git a/voidcrew/modules/unit_tests/voidcrew_launch_progression.dm b/voidcrew/modules/unit_tests/voidcrew_launch_progression.dm index e8663e763fe..8b955637b10 100644 --- a/voidcrew/modules/unit_tests/voidcrew_launch_progression.dm +++ b/voidcrew/modules/unit_tests/voidcrew_launch_progression.dm @@ -9,18 +9,19 @@ console.data = new console.test_candidates = list(star) console.survey_research_tiers = list("basic") + var/list/quote = console.get_survey_value(star) + TEST_ASSERT_EQUAL(quote["cash"], 0, "Survey reward results must contain zero cash for metrics") console.survey_celestial_object(user, ref(star)) TEST_ASSERT(console.survey_in_progress, "A fresh in-range star must be surveyable") // Advance only this timer, not the world's economy or restock clocks. deltimer(console.survey_timer) console.complete_survey(star) - var/first_cash = console.banked_cash var/first_points = console.banked_points - TEST_ASSERT(first_cash > 0 && first_points > 0, "The first survey must pay cash and research") + TEST_ASSERT_EQUAL(first_points, 250, "The first survey must pay only the base research, without a first-surveyor bonus") + TEST_ASSERT_EQUAL(first_points, quote["points"], "The research quote must match the award") TEST_ASSERT(console.is_object_surveyed(star), "Completion must record the target") - TEST_ASSERT(star.surveyed, "The first-surveyor premium must be consumed globally") + TEST_ASSERT(star.surveyed, "Completion must preserve the global surveyed marker") console.complete_survey(star) - TEST_ASSERT_EQUAL(console.banked_cash, first_cash, "A repeated completion must not pay cash again") TEST_ASSERT_EQUAL(console.banked_points, first_points, "A repeated completion must not pay research again") console.survey_celestial_object(user, ref(star)) TEST_ASSERT(!console.survey_in_progress, "A forged survey action must not restart a completed target") @@ -31,16 +32,17 @@ second.survey_celestial_object(user, ref(star)) deltimer(second.survey_timer) second.complete_survey(star) - TEST_ASSERT_EQUAL(second.banked_cash, star.survey_value, "Another crew's first scan earns the ordinary reward") + TEST_ASSERT_EQUAL(second.banked_points, first_points, "First and subsequent crews must earn equal research") var/obj/structure/overmap/star/other_star = allocate(/obj/structure/overmap/star) second.test_candidates = list(other_star) second.survey_celestial_object(user, ref(other_star)) second.complete_survey(star) TEST_ASSERT(second.survey_in_progress, "An old callback must not cancel a newer scan") + TEST_ASSERT_EQUAL(second.banked_points, first_points, "An old callback must not award research") deltimer(second.survey_timer) second.test_candidates.Cut() second.complete_survey(other_star) - TEST_ASSERT_EQUAL(second.banked_cash, star.survey_value, "An out-of-range completion must not pay") + TEST_ASSERT_EQUAL(second.banked_points, first_points, "An out-of-range completion must not pay") TEST_ASSERT(!second.is_object_surveyed(other_star), "An out-of-range completion must not unlock research") second.test_candidates = list(other_star) second.update_survey_data() @@ -50,11 +52,20 @@ console.data.update_survey_data(other_star) console.transfer_survey_data(console.data, second.data) second.complete_survey(other_star) - TEST_ASSERT_EQUAL(second.banked_cash, star.survey_value, "Importing a target during its scan must prevent duplicate payment") + TEST_ASSERT_EQUAL(second.banked_points, first_points, "Importing a target during its scan must prevent duplicate payment") second.survey_celestial_object(user, ref(other_star)) TEST_ASSERT(!second.survey_in_progress, "An imported record must not start another paid scan") console.transfer_survey_data(second.data, console.data) QDEL_NULL(second.data) + var/turf/output = get_turf(console) + var/list/currency_before = list() + for(var/obj/item/stack/spacecash/currency in output) + currency_before += currency + var/datum/tgui/ui = allocate(/datum/tgui, user, console, "SurveyComputer") + TEST_ASSERT(!console.ui_act("cashOut", list(), ui), "A stale cash-out action must be explicitly rejected") + TEST_ASSERT_EQUAL(console.banked_points, first_points, "A cash-out action must not consume research") + for(var/obj/item/stack/spacecash/currency in output) + TEST_ASSERT(currency in currency_before, "A forged cash-out action spawned currency") // Clean up the timer even on the unfixed baseline. if(console.survey_timer) deltimer(console.survey_timer) diff --git a/voidcrew/modules/unit_tests/voidcrew_survey_capabilities.dm b/voidcrew/modules/unit_tests/voidcrew_survey_capabilities.dm index 48a3d1de328..c549ce58e2f 100644 --- a/voidcrew/modules/unit_tests/voidcrew_survey_capabilities.dm +++ b/voidcrew/modules/unit_tests/voidcrew_survey_capabilities.dm @@ -115,3 +115,117 @@ TEST_ASSERT(console.mapping_enabled && console.obj_sight && console.mob_sight, "Explicit debug override lost its sight capabilities") console.activate_survey_map(user) TEST_ASSERT_EQUAL(console.map_refreshes, 1, "Explicit debug override could not reach map loading without a disk") + +/// Real overmap tiles and disk research drive the quote and completion paths. +/datum/unit_test/voidcrew_research_movement/survey_capabilities/rewards + var/list/overmap_turfs = list() + +/datum/unit_test/voidcrew_research_movement/survey_capabilities/rewards/Destroy() + for(var/turf/open/overmap/tile as anything in overmap_turfs) + tile.current_zone = null + tile.ChangeTurf(overmap_turfs[tile]) + return ..() + +/datum/unit_test/voidcrew_research_movement/survey_capabilities/rewards/proc/zone_tile(turf/location, zone_type) + var/old_type = location.type + var/turf/open/overmap/tile = location.ChangeTurf(/turf/open/overmap) + overmap_turfs[tile] = old_type + tile.current_zone = allocate(/datum/overmap_zone, zone_type) + return tile + +/datum/unit_test/voidcrew_research_movement/survey_capabilities/rewards/Run() + TEST_ASSERT(setup_links(), "No local research disk exists for survey reward testing") + var/obj/machinery/computer/camera_advanced/shuttle_docker/survey/launch_test/map_gate_test/console = map_console() + // Voidcrew zone defines are included later: green = 1, yellow = 2, red = 3. + var/turf/green = zone_tile(get_step(run_loc_floor_bottom_left, NORTH), 1) + var/turf/open/overmap/target_tile = zone_tile(get_step(green, EAST), 1) + var/list/bases = list( + /obj/structure/overmap/star = 250, + /obj/structure/overmap/planet = 150, + /obj/structure/overmap/space_ruin = 75, + /obj/structure/overmap/event/emp = 100, + /obj/structure/overmap/event/electric = 75, + /obj/structure/overmap/event/meteor = 50, + /obj/structure/overmap/event/nebula = 25, // SURVEY_NEBULA_BASE, including dangerous variants. + ) + for(var/family in bases) + for(var/variant_type in typesof(family)) + var/obj/structure/overmap/variant = variant_type + var/expected = ispath(variant_type, /obj/structure/overmap/planet/empty) ? 0 : bases[family] + TEST_ASSERT_EQUAL(initial(variant.survey_value), expected, "[variant_type] has an incorrect survey base") + var/list/tier_multipliers = list(1, 1, 1.1, 1.25) + var/list/zone_multipliers = list(1, 1.25, 1.5) + for(var/tier in 1 to 4) + learn_tiers(web, tier) + for(var/zone in 1 to 3) + target_tile.current_zone = allocate(/datum/overmap_zone, zone) + for(var/family in bases) + var/obj/structure/overmap/target = allocate(family, target_tile) + if(istype(target, /obj/structure/overmap/planet)) + // Substitute surface generation only; record and reward code still runs. + var/obj/structure/overmap/planet/planet = target + planet.loaded = TRUE + console.ship_port.current_ship.forceMove(target_tile) + check_award(console, target, bases[family] * tier_multipliers[tier] * zone_multipliers[zone]) + // The ship stays in green while each remote storm is in the target's zone. + console.ship_port.current_ship.forceMove(green) + for(var/family in list(/obj/structure/overmap/event/emp, /obj/structure/overmap/event/electric)) + var/obj/structure/overmap/target = allocate(family, target_tile) + TEST_ASSERT(console.is_survey_at_range(target), "Remote-storm fixture shares the ship's tile") + check_award(console, target, bases[family] * tier_multipliers[tier] * zone_multipliers[zone] * 0.6) + // Removing the disk must revoke its multiplier even without another UI refresh. + var/obj/structure/overmap/star/star = allocate(/obj/structure/overmap/star, green) + console.ship_port.current_ship.forceMove(green) + server.source_code_hdd.forceMove(run_loc_floor_bottom_left) + check_award(console, star, 250) + // Printing is the boundary: fractional awards must survive both banking and notes. + var/points_before = console.banked_points + var/list/old_notes = list() + for(var/obj/item/research_notes/notes in get_turf(console)) + old_notes += notes + console.print_survey_notes(user) + var/obj/item/research_notes/printed + for(var/obj/item/research_notes/notes in get_turf(console)) + if(!(notes in old_notes)) + printed = notes + allocated += notes + TEST_ASSERT(printed, "Survey notes were not printed") + TEST_ASSERT_EQUAL(printed.value, points_before, "Printing changed the banked research value") + TEST_ASSERT_EQUAL(console.banked_points, 0, "Printing did not empty the banked research") + +/datum/unit_test/voidcrew_research_movement/survey_capabilities/rewards/proc/check_award(obj/machinery/computer/camera_advanced/shuttle_docker/survey/launch_test/console, obj/structure/overmap/target, expected) + console.test_candidates = list(target) + var/list/quote = console.get_survey_value(target) + TEST_ASSERT_EQUAL(quote["cash"], 0, "[target.type] quoted currency") + TEST_ASSERT(abs(quote["points"] - expected) < 0.001, "[target.type] quoted [quote["points"]] research instead of [expected]") + var/list/ui_data = console.ui_data(user) + TEST_ASSERT(!("bankedCash" in ui_data), "Survey UI still exposes a cash balance") + var/list/targets = ui_data["surveyTargets"] + var/list/target_quote = targets[1] + TEST_ASSERT(!("cash" in target_quote), "Survey target UI still exposes currency") + TEST_ASSERT_EQUAL(target_quote["points"], quote["points"], "Target UI disagrees with the reward quote") + var/points_before = console.banked_points + console.survey_celestial_object(user, ref(target)) + TEST_ASSERT(console.survey_in_progress, "[target.type] could not start a survey") + deltimer(console.survey_timer) + console.complete_survey(target) + TEST_ASSERT(abs(console.banked_points - points_before - expected) < 0.01, "[target.type] awarded different research from its quote") + TEST_ASSERT(console.is_object_surveyed(target), "[target.type] completion did not retain the survey record") + +/// Checkpoint snapshots preserve fittings, never a console's accumulated research. +/datum/unit_test/voidcrew_survey_checkpoint_points/Run() + var/obj/machinery/computer/camera_advanced/shuttle_docker/survey/console = allocate(/obj/machinery/computer/camera_advanced/shuttle_docker/survey) + console.banked_points = 123.75 + var/datum/ship_checkpoint/snapshot = allocate(/datum/ship_checkpoint) + var/serialized = snapshot.atom_text(console) + TEST_ASSERT(!findtext(serialized, "banked_points"), "Checkpoint serialized banked survey research") + var/map_text = "//[DMM2TGM_MESSAGE]\n\"a\" = (\n[serialized],\n/turf/template_noop,\n/area/template_noop)\n\n(1,1,1) = {\"\na\n\"}\n" + var/datum/parsed_map/parsed = allocate(/datum/parsed_map, map_text) + var/turf/destination = run_loc_floor_top_right + TEST_ASSERT(parsed.load(destination.x, destination.y, destination.z, crop_map = TRUE), "Checkpoint survey fitting could not be reconstructed") + var/obj/machinery/computer/camera_advanced/shuttle_docker/survey/rebuilt = locate() in destination + TEST_ASSERT(rebuilt && rebuilt != console, "Checkpoint did not create a new survey console") + allocated += rebuilt + SSatoms.InitializeAtoms(list(rebuilt)) + TEST_ASSERT_EQUAL(rebuilt.banked_points, 0, "Checkpoint reconstruction duplicated banked research") + TEST_ASSERT_EQUAL(console.banked_points, 123.75, "Snapshot changed the original console's research") From ea1caa777ae04e4936977a7ae62d9cb60455dc76 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:37:39 -0700 Subject: [PATCH 015/105] Finite scanner output tied to persistent sites --- voidcrew/modules/research/survey_scanner.dm | 95 +++---- .../unit_tests/voidcrew_survey_identity.dm | 263 ++++++++++++++++++ 2 files changed, 311 insertions(+), 47 deletions(-) diff --git a/voidcrew/modules/research/survey_scanner.dm b/voidcrew/modules/research/survey_scanner.dm index 4ad5cb9d534..4dd643891cc 100644 --- a/voidcrew/modules/research/survey_scanner.dm +++ b/voidcrew/modules/research/survey_scanner.dm @@ -6,8 +6,10 @@ #define SURVEY_SCAN_DECAY 0.04 /// Once a site is worth less than this fraction, it is tapped out for the rest of the round. #define SURVEY_MIN_PENALTY 0.20 -/// Points per scan per servo rating, before the decay multiplier. 9/18/27/36. -#define SURVEY_GAIN_PER_SERVO 9 + +/obj/structure/overmap + /// Successful ground scans at this site, retained when its interior is unloaded. + var/survey_scans_completed = 0 /** * Survey scanner @@ -24,7 +26,7 @@ */ /obj/machinery/survey_scanner name = "survey scanner" - desc = "A machine that scans whatever it is bolted to and refines the readings into research data. It runs off an internal power cell, so it works anywhere you can carry it." + desc = "A rugged, battery-powered survey instrument." icon = 'voidcrew/modules/research/icons/objects.dmi' icon_state = "hivebot_fab" density = TRUE @@ -53,15 +55,6 @@ var/next_scan = 0 ///Amount of research points we've generated from processing. var/stored_points - ///How many times each SITE has been scanned, keyed by get_scan_history_key(). - /// - ///Was keyed by z-level, which meant "this site" only while a site owned a z-level of its - ///own. Sites share levels now: crew B scanning at the encounter next door burned down - ///crew A's payout, and could push the shared counter past SURVEY_MIN_PENALTY so that A's - ///scanner reported "unable to locate valuable information" at ground nobody had touched. - ///`static` also meant the count outlived the z-level itself, so a recycled level handed - ///its next occupant a used-up site. - var/static/list/site_scan_history = list() /obj/machinery/survey_scanner/Initialize(mapload) . = ..() @@ -79,16 +72,16 @@ /obj/machinery/survey_scanner/examine(mob/user) . = ..() if(cell) - . += span_notice("It has \a [cell] installed, at [round(cell.percent())]% charge.") + . += span_notice("It has \a [cell] installed.") else - . += span_warning("It has no power cell. Open the maintenance panel with a screwdriver to fit one.") + . += span_warning("Its cell compartment is empty.") if(stored_points) - . += "It currently has [round(stored_points, 1)] points. You can Right-Click to print it." + . += "Its data spool is ready." /obj/machinery/survey_scanner/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() if(istype(held_item, /obj/item/stock_parts/power_store)) - context[SCREENTIP_CONTEXT_LMB] = panel_open ? "Install cell" : "Open panel first" + context[SCREENTIP_CONTEXT_LMB] = panel_open ? "Install cell" : "Panel closed" return CONTEXTUAL_SCREENTIP_SET if(!isnull(held_item)) @@ -125,7 +118,7 @@ /obj/machinery/survey_scanner/RefreshParts() . = ..() research_power = max(total_part_rating(/datum/stock_part/matter_bin), 1) - research_gain = max(total_part_rating(/datum/stock_part/servo), 1) * SURVEY_GAIN_PER_SERVO //9, 18, 27, 36 + research_gain = 6 + 3 * clamp(total_part_rating(/datum/stock_part/servo), 1, 4) //cell drain is cut, not increased - better lasers mean one cell lasts longer. active_power_usage = initial(active_power_usage) / (1 + total_part_rating(/datum/stock_part/micro_laser)) @@ -167,7 +160,7 @@ return ..() if(!panel_open) - balloon_alert(user, "open the panel first!") + balloon_alert(user, "panel closed!") return ITEM_INTERACT_BLOCKING if(cell) balloon_alert(user, "already has a cell!") @@ -177,7 +170,7 @@ cell = tool balloon_alert(user, "cell installed") - to_chat(user, span_notice("You slot [tool] into [src]. Close the maintenance panel to run it.")) + to_chat(user, span_notice("You slot [tool] into [src].")) playsound(src, 'sound/machines/click.ogg', 50, TRUE) return ITEM_INTERACT_SUCCESS @@ -206,7 +199,7 @@ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) return if(!stored_points) - say("No research points found, nothing to dispense.") + say("Data spool empty.") return //accumulator is fractional (gain * decay), so only round at the point it becomes an item @@ -225,6 +218,12 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/machinery/survey_scanner/process(seconds_per_tick) + var/obj/structure/overmap/site = get_scan_site() + if(!site) + say("No survey target. Scanning stopped.") + disable() + return + // Bill the internal cell, not the area - see the type comment. if(!cell?.use(active_power_usage * seconds_per_tick, force = TRUE)) say("Power cell depleted, scanning stopped.") @@ -241,33 +240,37 @@ // the decay, so a better matter bin keeps a site productive for longer - it does NOT // scale the payout. (It used to be applied as a raw multiplier, which stacked with the // longer run and made a maxed scanner worth ~9x the entire techweb from one planet.) - var/scan_key = get_scan_history_key() - var/penalty = 1 - ((site_scan_history[scan_key] - 1) * SURVEY_SCAN_DECAY / max(research_power, 1)) + var/penalty = 1 - site.survey_scans_completed * SURVEY_SCAN_DECAY / max(research_power, 1) if(penalty < SURVEY_MIN_PENALTY) // tapped out, and it stays that way for the round - say("Unable to locate valuable information in current sector, scanning stopped.") + say("Survey complete. Scanning stopped.") playsound(src, 'sound/machines/buzz/buzz-sigh.ogg', 20) disable() return playsound(src, 'sound/machines/ding.ogg', 20) - site_scan_history[scan_key]++ stored_points += (research_gain * penalty) + site.survey_scans_completed++ tally_metric_scan(research_gain * penalty) // round metrics, voidcrew/modules/metrics/research_metrics.dm -/** - * The history key for wherever this scanner is standing. - * - * A map region (see map_region_for_turf) is the site: the planet or encounter footprint on a - * packed level, or the turf reservation for a ruin or asteroid field. Ground that belongs to - * no region - a roundstart level, a ship in deep space - falls back to the z-level, which is - * exactly what the whole list used to be. - */ -/obj/machinery/survey_scanner/proc/get_scan_history_key() +/// Resolve natural ground to its persistent contact, never to a reusable interior slot. +/obj/machinery/survey_scanner/proc/get_scan_site() var/turf/here = get_turf(src) - if(!here) - return "z_[z]" - var/datum/region = map_region_for_turf(here) - return region ? "site_[REF(region)]" : "z_[here.z]" + if(!here || SSshuttle.get_containing_shuttle(here) || get_voidcrew_ship_for_turf(here)) + return null + var/obj/structure/overmap/site = SSovermap_zones.get_overmap_object_for_turf(here) + if(QDELETED(site)) + return null + // The resolver also supports legacy whole-level tenants. Surveying requires owned ground. + var/datum/map_footprint/footprint = site.get_interior_footprint() + if(!footprint?.contains_turf(here)) + return null + if(istype(site, /obj/structure/overmap/space_ruin) || istype(site, /obj/structure/overmap/event/meteor)) + return site + if(istype(site, /obj/structure/overmap/planet) && !istype(site, /obj/structure/overmap/planet/empty)) + var/obj/structure/overmap/planet/planet = site + if(planet.is_terrain_planet()) + return planet + return null /obj/machinery/survey_scanner/wrench_act(mob/living/user, obj/item/tool) if(enabled) @@ -295,21 +298,20 @@ */ /obj/machinery/survey_scanner/proc/enable() if(!anchored) - say("Unable to operate, not anchored properly to the floor!") + say("Anchor unsecured.") return if(panel_open) - say("Unable to operate, maintenance panel is open!") + say("Maintenance panel open.") return if(!cell) - say("Unable to operate, no power cell installed!") + say("Power cell missing.") return if(!cell.charge) - say("Unable to operate, power cell is depleted!") + say("Power cell depleted.") + return + if(!get_scan_site()) + say("No survey target.") return - //don't have a history here, create one. - var/scan_key = get_scan_history_key() - if(!site_scan_history[scan_key]) - site_scan_history[scan_key] = 1 next_scan = world.time //first scan lands on the next tick, so it visibly does something enabled = TRUE note_metric_operator() // round metrics, voidcrew/modules/metrics/research_metrics.dm @@ -348,7 +350,7 @@ */ /datum/design/board/survey_scanner name = "Survey Scanner Machine Board" - desc = "The Machine Circuit board for a Survey scanner which allows research generation through power." + desc = "A circuit board for a survey scanner." id = "surveyscanner" build_path = /obj/item/circuitboard/machine/survey_scanner category = list( @@ -373,4 +375,3 @@ #undef SURVEY_SCAN_INTERVAL #undef SURVEY_SCAN_DECAY #undef SURVEY_MIN_PENALTY -#undef SURVEY_GAIN_PER_SERVO diff --git a/voidcrew/modules/unit_tests/voidcrew_survey_identity.dm b/voidcrew/modules/unit_tests/voidcrew_survey_identity.dm index 982c569d280..9168efb6fc4 100644 --- a/voidcrew/modules/unit_tests/voidcrew_survey_identity.dm +++ b/voidcrew/modules/unit_tests/voidcrew_survey_identity.dm @@ -36,3 +36,266 @@ . = ..() if(force_reference_reuse) return QDEL_HINT_HARDDEL_NOW + +/// Small physical interiors exercise the real site resolver without generating whole maps. +/datum/unit_test/voidcrew_survey_scanner + abstract_type = /datum/unit_test/voidcrew_survey_scanner + var/list/test_sites = list() + var/list/test_ports = list() + +/datum/unit_test/voidcrew_survey_scanner/Destroy() + for(var/obj/structure/overmap/site as anything in test_sites) + if(QDELETED(site)) + continue + // These synthetic rectangles own no terrain to tear down. + site.vars["footprint"] = null + site.vars["mapzone"] = null + test_sites = null + for(var/obj/docking_port/mobile/voidcrew/port as anything in test_ports) + port.current_ship = null + port.shuttle_areas = list() + qdel(port, force = TRUE) + test_ports = null + return ..() + +/datum/unit_test/voidcrew_survey_scanner/proc/make_footprint(obj/structure/overmap/site, turf/tile) + var/datum/map_footprint/footprint = allocate(/datum/map_footprint) + footprint.z_value = tile.z + footprint.set_rect(tile.x, tile.y, 1, 1) + footprint.set_owner(site) + return footprint + +/datum/unit_test/voidcrew_survey_scanner/proc/make_site(site_type, turf/tile) + var/obj/structure/overmap/site = allocate(site_type) + site.vars["footprint"] = make_footprint(site, tile) + site.vars["mapzone"] = allocate(/datum/map_zone) + test_sites += site + return site + +/datum/unit_test/voidcrew_survey_scanner/proc/make_scanner(turf/tile) + var/obj/machinery/survey_scanner/scanner = allocate(/obj/machinery/survey_scanner, tile) + scanner.set_anchored(TRUE) + scanner.cell = allocate(/obj/item/stock_parts/power_store/cell/bluespace, scanner) + return scanner + +/datum/unit_test/voidcrew_survey_scanner/proc/make_ship_turf(turf/tile) + var/obj/docking_port/mobile/voidcrew/port = new(tile) + port.width = 1 + port.height = 1 + port.dwidth = 0 + port.dheight = 0 + port.shuttle_areas = list() + port.shuttle_areas[get_area(tile)] = TRUE + port.current_ship = allocate(/obj/structure/overmap/ship) + port.register() + test_ports += port + return port + +/// Drive a paid scan without waiting for the cadence; process() itself is unchanged. +/datum/unit_test/voidcrew_survey_scanner/proc/scan_now(obj/machinery/survey_scanner/scanner) + scanner.next_scan = world.time + scanner.process(2) + +/datum/unit_test/voidcrew_survey_scanner/servo_outputs/Run() + var/turf/tile = run_loc_floor_bottom_left + var/obj/structure/overmap/site = make_site(/obj/structure/overmap/planet/lava, tile) + var/obj/machinery/survey_scanner/scanner = make_scanner(tile) + var/list/servo_objects = list(/obj/item/stock_parts/servo, /obj/item/stock_parts/servo/nano, /obj/item/stock_parts/servo/pico, /obj/item/stock_parts/servo/femto) + var/list/servo_datums = list(/datum/stock_part/servo, /datum/stock_part/servo/tier2, /datum/stock_part/servo/tier3, /datum/stock_part/servo/tier4) + var/list/expected_outputs = list(9, 12, 15, 18) + for(var/datum/part as anything in scanner.component_parts.Copy()) + if(istype(part, /obj/item/stock_parts/servo) || istype(part, /datum/stock_part/servo)) + scanner.component_parts -= part + if(isitem(part)) + qdel(part) + for(var/use_datums in list(FALSE, TRUE)) + for(var/tier in 1 to 4) + var/datum/servo + if(use_datums) + servo = GLOB.stock_part_datums[servo_datums[tier]] + else + servo = allocate(servo_objects[tier], scanner) + scanner.component_parts += servo + scanner.RefreshParts() + TEST_ASSERT_EQUAL(scanner.research_gain, expected_outputs[tier], "Incorrect servo output at tier [tier] (datum: [use_datums])") + var/points_before = scanner.stored_points + var/scans_before = site.survey_scans_completed + scan_now(scanner) + var/expected_gain = expected_outputs[tier] * (1 - scans_before * 0.04) + TEST_ASSERT(abs(scanner.stored_points - points_before - expected_gain) < 0.001, "A paid scan did not use the tier [tier] output and existing depletion") + scanner.component_parts -= servo + if(isitem(servo)) + qdel(servo) + // A tick before the next scan still consumes power, but cannot pay or deplete the site. + var/points_before = scanner.stored_points + var/scans_before = site.survey_scans_completed + var/charge_before = scanner.cell.charge + scanner.process(2) + TEST_ASSERT_EQUAL(scanner.next_scan, world.time + 10 SECONDS, "The scan cadence changed") + TEST_ASSERT_EQUAL(scanner.stored_points, points_before, "A scan paid before its ten-second interval") + TEST_ASSERT_EQUAL(site.survey_scans_completed, scans_before, "An idle tick depleted the site") + TEST_ASSERT_EQUAL(scanner.cell.charge, charge_before - scanner.active_power_usage * 2, "Idle scanning stopped billing its cell") + +/datum/unit_test/voidcrew_survey_scanner/parts_and_power/Run() + var/turf/tile = run_loc_floor_bottom_left + var/obj/structure/overmap/site = make_site(/obj/structure/overmap/planet/lava, tile) + var/obj/machinery/survey_scanner/scanner = make_scanner(tile) + for(var/datum/part as anything in scanner.component_parts.Copy()) + if(istype(part, /obj/item/stock_parts/matter_bin) || istype(part, /datum/stock_part/matter_bin) || istype(part, /obj/item/stock_parts/micro_laser) || istype(part, /datum/stock_part/micro_laser)) + scanner.component_parts -= part + if(isitem(part)) + qdel(part) + scanner.component_parts += GLOB.stock_part_datums[/datum/stock_part/matter_bin/tier4] + scanner.component_parts += GLOB.stock_part_datums[/datum/stock_part/micro_laser/tier4] + scanner.RefreshParts() + TEST_ASSERT_EQUAL(scanner.research_power, 4, "An upgraded matter bin lost its decay effect") + TEST_ASSERT_EQUAL(scanner.active_power_usage, initial(scanner.active_power_usage) / 5, "An upgraded laser changed its power effect") + scanner.enable() + scan_now(scanner) + TEST_ASSERT_EQUAL(scanner.stored_points, 9, "A matter bin multiplied the first scan's payout") + scan_now(scanner) + TEST_ASSERT(abs(scanner.stored_points - 17.91) < 0.001, "A matter bin did not divide depletion") + var/points_before = scanner.stored_points + scanner.cell.charge = 0 + scan_now(scanner) + TEST_ASSERT(!scanner.enabled, "An empty cell did not stop scanning") + TEST_ASSERT_EQUAL(scanner.stored_points, points_before, "An unpaid scan generated research") + TEST_ASSERT_EQUAL(site.survey_scans_completed, 2, "An unpaid scan depleted the site") + +/datum/unit_test/voidcrew_survey_scanner/shared_depletion/Run() + var/turf/tile = run_loc_floor_bottom_left + var/turf/neighbor = get_step(tile, EAST) + var/obj/structure/overmap/site = make_site(/obj/structure/overmap/planet/lava, tile) + var/obj/structure/overmap/other_site = make_site(/obj/structure/overmap/planet/ice, neighbor) + var/obj/machinery/survey_scanner/first = make_scanner(tile) + var/obj/machinery/survey_scanner/second = make_scanner(tile) + first.enable() + second.enable() + TEST_ASSERT(first.enabled && second.enabled, "Scanners could not start on natural ground") + TEST_ASSERT_EQUAL(site.survey_scans_completed, 0, "Enabling a scanner depleted the site") + scan_now(first) + scan_now(second) + TEST_ASSERT_EQUAL(first.stored_points, 9, "The first scan did not start at full value") + TEST_ASSERT(abs(second.stored_points - 8.64) < 0.001, "A second scanner did not share the first scanner's depletion") + TEST_ASSERT_EQUAL(site.survey_scans_completed, 2, "Successful scanners did not increment one shared counter") + second.forceMove(neighbor) + var/points_before = second.stored_points + scan_now(second) + TEST_ASSERT(abs(second.stored_points - points_before - 9) < 0.001, "A neighboring site on the same level inherited depletion") + TEST_ASSERT_EQUAL(other_site.survey_scans_completed, 1, "The neighboring site did not retain its own counter") + first.disable() + qdel(first) + var/obj/machinery/survey_scanner/replacement = make_scanner(tile) + replacement.enable() + scan_now(replacement) + TEST_ASSERT(abs(replacement.stored_points - 8.28) < 0.001, "Replacing the machine refreshed its site") + // Replace the temporary interior while retaining the persistent overmap contact. + var/obj/structure/overmap/planet/planet = site + QDEL_NULL(planet.footprint) + QDEL_NULL(planet.mapzone) + planet.mapzone = allocate(/datum/map_zone) + planet.footprint = make_footprint(planet, tile) + points_before = replacement.stored_points + scan_now(replacement) + TEST_ASSERT(abs(replacement.stored_points - points_before - 7.92) < 0.001, "Reloading the interior refreshed depletion") + TEST_ASSERT_EQUAL(site.survey_scans_completed, 4, "Replacing the interior lost completed scans") + // Exhaust the site with the replacement machine, then try another fresh machine. + for(var/attempt in 1 to 30) + if(!replacement.enabled) + break + scan_now(replacement) + TEST_ASSERT(!replacement.enabled, "A depleted site never stopped producing") + TEST_ASSERT_EQUAL(site.survey_scans_completed, 21, "The existing 0.20 cutoff changed") + var/obj/machinery/survey_scanner/fresh = make_scanner(tile) + fresh.enable() + scan_now(fresh) + TEST_ASSERT(!fresh.enabled && !fresh.stored_points, "A fresh scanner produced from an exhausted site") + TEST_ASSERT_EQUAL(site.survey_scans_completed, 21, "A failed scan incremented the site counter") + // Reuse the old rectangle for a different contact: it starts with its own history. + planet.footprint = null + planet.mapzone = null + var/obj/structure/overmap/new_site = make_site(/obj/structure/overmap/planet/lava, tile) + fresh.enable() + scan_now(fresh) + TEST_ASSERT_EQUAL(fresh.stored_points, 9, "Recycled ground inherited another contact's exhaustion") + TEST_ASSERT_EQUAL(new_site.survey_scans_completed, 1, "Recycled ground did not update its new contact") + +/datum/unit_test/voidcrew_survey_scanner/site_validation/Run() + var/turf/tile = run_loc_floor_bottom_left + var/obj/machinery/survey_scanner/scanner = make_scanner(tile) + scanner.enable() + TEST_ASSERT(!scanner.enabled, "Unowned ground accepted a scanner") + TEST_ASSERT_NULL(scanner.get_scan_site(), "Unowned ground resolved through a z-level fallback") + scan_now(scanner) + TEST_ASSERT(!scanner.stored_points, "Unowned ground produced research") + // The shared resolver can identify legacy tenants by z; scanners must not accept that. + var/obj/structure/overmap/planet/legacy = make_site(/obj/structure/overmap/planet/lava, tile) + QDEL_NULL(legacy.footprint) + legacy.mapzone.z_levels += reservation + TEST_ASSERT_EQUAL(SSovermap_zones.get_overmap_object_for_turf(tile), legacy, "The legacy z-level fallback fixture did not resolve") + TEST_ASSERT_NULL(scanner.get_scan_site(), "A planet without a physical footprint accepted unowned ground") + scanner.enable() + TEST_ASSERT(!scanner.enabled, "A z-level fallback enabled scanning") + scan_now(scanner) + TEST_ASSERT(!scanner.stored_points && !legacy.survey_scans_completed, "A z-level fallback produced a paid scan") + legacy.mapzone.z_levels.Cut() + var/list/accepted = list(/obj/structure/overmap/planet/lava, /obj/structure/overmap/space_ruin, /obj/structure/overmap/event/meteor) + var/list/rejected = list(/obj/structure/overmap/dynamic/player_outpost, /obj/structure/overmap/planet/empty, /obj/structure/overmap/planet/empty/crashed_ship, /obj/structure/overmap/planet/energy_signal) + for(var/site_type in accepted + rejected) + var/obj/structure/overmap/site = make_site(site_type, tile) + var/should_scan = (site_type in accepted) + TEST_ASSERT_EQUAL(scanner.get_scan_site(), should_scan ? site : null, "Incorrect survey eligibility for [site_type]") + scanner.enable() + TEST_ASSERT_EQUAL(scanner.enabled, should_scan, "Incorrect startup eligibility for [site_type]") + if(should_scan) + scanner.disable() + // A scanner already running must also reject a move onto ineligible ground. + scanner.enabled = TRUE + var/points_before = scanner.stored_points + scan_now(scanner) + TEST_ASSERT_EQUAL(site.survey_scans_completed, should_scan ? 1 : 0, "Incorrect paid-scan eligibility for [site_type]") + if(!should_scan) + TEST_ASSERT(!scanner.enabled, "A running scanner did not stop at [site_type]") + TEST_ASSERT_EQUAL(scanner.stored_points, points_before, "An ineligible site produced research") + scanner.disable() + site.vars["footprint"] = null + site.vars["mapzone"] = null + // The site's rectangle includes a docked hull; hull ownership must win. + var/obj/structure/overmap/site = make_site(/obj/structure/overmap/planet/lava, tile) + var/datum/map_footprint/footprint = site.get_interior_footprint() + footprint.set_rect(tile.x, tile.y, 2, 1) + scanner.enable() + TEST_ASSERT(scanner.enabled, "The natural site did not start before boarding") + var/turf/ship_tile = get_step(tile, EAST) + make_ship_turf(ship_tile) + scanner.forceMove(ship_tile) + TEST_ASSERT_NULL(scanner.get_scan_site(), "A docked hull was accepted as planetary ground") + var/points_before = scanner.stored_points + var/charge_before = scanner.cell.charge + scan_now(scanner) + TEST_ASSERT(!scanner.enabled, "A scanner moved aboard a docked ship kept running") + TEST_ASSERT_EQUAL(scanner.stored_points, points_before, "A scanner paid aboard a docked ship") + TEST_ASSERT_EQUAL(scanner.cell.charge, charge_before, "An invalid site consumed scan power") + TEST_ASSERT_EQUAL(site.survey_scans_completed, 0, "A shipboard scan depleted the ground below it") + scanner.enable() + TEST_ASSERT(!scanner.enabled, "A shipboard scanner could be enabled") + +/datum/unit_test/voidcrew_survey_scanner/checkpoint_defaults/Run() + var/turf/tile = run_loc_floor_bottom_left + var/obj/machinery/survey_scanner/source = make_scanner(tile) + source.enabled = TRUE + source.stored_points = 100 + var/datum/ship_checkpoint/snapshot = allocate(/datum/ship_checkpoint) + var/saved_text = snapshot.atom_text(source) + TEST_ASSERT(!findtext(saved_text, "enabled") && !findtext(saved_text, "stored_points") && !findtext(saved_text, "cell"), "Checkpoint serialized live scanner stock or running state") + var/obj/machinery/survey_scanner/rebuilt = allocate(source.checkpoint_type(), tile) + TEST_ASSERT(!rebuilt.enabled, "A checkpoint-built scanner started enabled") + TEST_ASSERT_NULL(rebuilt.cell, "A checkpoint-built scanner supplied a charged cell") + TEST_ASSERT(!rebuilt.stored_points, "A checkpoint-built scanner supplied research") + make_site(/obj/structure/overmap/planet/lava, tile) + make_ship_turf(tile) + rebuilt.cell = allocate(/obj/item/stock_parts/power_store/cell/bluespace, rebuilt) + rebuilt.enable() + TEST_ASSERT(!rebuilt.enabled, "A refueled checkpoint-built scanner started aboard its hull") + scan_now(rebuilt) + TEST_ASSERT(!rebuilt.stored_points, "A checkpoint-built scanner generated research aboard its hull") From 6e4606385cbfca79a2373ef1c9ceba2aa1db1f2e Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:30:50 -0700 Subject: [PATCH 016/105] Make the outpost gun checkpoints fit their maps --- .../outposts/trader_outpost_black_market.dmm | 145 +++++------ .../outposts/trader_outpost_general.dmm | 226 ++++++++++++------ .../outposts/trader_outpost_outfitter.dmm | 114 +++++---- voidcrew/modules/trade/outpost_security.dm | 13 + .../unit_tests/voidcrew_outpost_safe_hubs.dm | 48 ++++ 5 files changed, 352 insertions(+), 194 deletions(-) diff --git a/voidcrew/_maps/map_files/outposts/trader_outpost_black_market.dmm b/voidcrew/_maps/map_files/outposts/trader_outpost_black_market.dmm index 81318a9005a..da0ce8a856a 100644 --- a/voidcrew/_maps/map_files/outposts/trader_outpost_black_market.dmm +++ b/voidcrew/_maps/map_files/outposts/trader_outpost_black_market.dmm @@ -479,13 +479,6 @@ /obj/machinery/newscaster/directional/east, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) -"aX" = ( -/obj/machinery/door/airlock/outpost/checkpoint{ - checkpoint_id = "undertow_elevator"; - dir = 4 - }, -/turf/open/indestructible/dark/smooth_large, -/area/voidcrew/trader_outpost) "aY" = ( /obj/machinery/sleeper/outpost{ dir = 4 @@ -653,28 +646,6 @@ /obj/structure/extinguisher_cabinet/directional/west, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) -"bo" = ( -/obj/machinery/door/airlock/outpost/checkpoint{ - checkpoint_id = "undertow_bar"; - dir = 4; - name = "Bar Gate" - }, -/obj/effect/turf_decal/bot, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/effect/turf_decal/siding/wideplating_new/dark/corner{ - dir = 1 - }, -/obj/effect/turf_decal/siding/wideplating_new/dark/corner{ - dir = 8 - }, -/obj/effect/turf_decal/stripes{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt/dust, -/turf/open/indestructible/plating, -/area/voidcrew/trader_outpost) "bp" = ( /obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ checkpoint_id = "undertow_bar"; @@ -1061,9 +1032,6 @@ }, /turf/open/indestructible/dark/smooth_large, /area/voidcrew/trader_outpost) -"gE" = ( -/turf/open/floor/carpet/neon/simple/red/nodots, -/area/voidcrew/trader_outpost) "gK" = ( /obj/effect/turf_decal/siding/wideplating_new/dark{ dir = 4 @@ -1414,6 +1382,18 @@ /obj/structure/extinguisher_cabinet/directional/north, /turf/open/floor/carpet/neon/simple/red/nodots, /area/voidcrew/trader_outpost) +"mv" = ( +/obj/machinery/newscaster/directional/north, +/obj/machinery/light/red/directional/north, +/obj/effect/turf_decal/tile/dark_red/half/contrasted{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 1 + }, +/obj/structure/extinguisher_cabinet/directional/north, +/turf/open/indestructible/dark, +/area/voidcrew/trader_outpost) "mx" = ( /obj/effect/turf_decal/trimline/dark_red/filled/corner{ dir = 4 @@ -1948,6 +1928,28 @@ }, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) +"vJ" = ( +/obj/machinery/door/airlock/outpost/checkpoint/grunge{ + checkpoint_id = "undertow_bar"; + dir = 4; + name = "Bar Gate" + }, +/obj/effect/turf_decal/bot, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wideplating_new/dark/corner{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wideplating_new/dark/corner{ + dir = 8 + }, +/obj/effect/turf_decal/stripes{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/plating, +/area/voidcrew/trader_outpost) "vK" = ( /obj/structure/sign/warning/vacuum/external/directional/north, /obj/effect/decal/cleanable/dirt/dust, @@ -2303,6 +2305,14 @@ /obj/effect/turf_decal/tile/dark_red/opposingcorners, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) +"zW" = ( +/obj/machinery/light/red/directional/south, +/obj/item/radio/intercom/directional/south, +/obj/effect/turf_decal/tile/dark_red/half/contrasted, +/obj/effect/turf_decal/siding/wideplating_new/dark, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/dark, +/area/voidcrew/trader_outpost) "Av" = ( /obj/structure/chair/sofa/corp/corner{ dir = 4 @@ -2477,6 +2487,13 @@ /obj/effect/decal/cleanable/dirt, /turf/open/indestructible/dark/textured, /area/voidcrew/trader_outpost) +"Ds" = ( +/obj/machinery/door/airlock/outpost/checkpoint/grunge{ + checkpoint_id = "undertow_elevator"; + dir = 4 + }, +/turf/open/indestructible/dark/smooth_large, +/area/voidcrew/trader_outpost) "DM" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/siding/thinplating_new/dark{ @@ -3275,9 +3292,6 @@ /obj/effect/turf_decal/tile/dark_red/opposingcorners, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) -"Qf" = ( -/turf/open/floor/carpet/neon/simple/red/nodots, -/area/voidcrew/trader_outpost) "Ql" = ( /turf/open/indestructible{ base_icon_state = "stairs-r"; @@ -3411,9 +3425,6 @@ /obj/machinery/light/floor, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) -"SI" = ( -/turf/open/indestructible/light, -/area/voidcrew/trader_outpost) "SS" = ( /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 1 @@ -4465,11 +4476,11 @@ aV Vr Sp bL -SI -SI -SI -SI -SI +Jy +Jy +Jy +Jy +Jy ae VR KU @@ -4499,11 +4510,11 @@ aV MG aG bL -SI -SI -SI -SI -SI +Jy +Jy +Jy +Jy +Jy KQ aj Kc @@ -4533,11 +4544,11 @@ aV MG Sp uB -SI -SI +Jy +Jy ve Jy -SI +Jy ae aj Kc @@ -4560,18 +4571,18 @@ Gq kF KQ bL -gE -Qf +ai +ai ck aV MG Sp bL -SI -SI -SI -SI -SI +Jy +Jy +Jy +Jy +Jy KQ aj Kc @@ -4601,11 +4612,11 @@ aV Vr MP bL -SI -SI -SI -SI -SI +Jy +Jy +Jy +Jy +Jy KQ jx NP @@ -4745,9 +4756,9 @@ we we aa aa -aq +mv ay -Eu +zW aV vn aC @@ -4780,7 +4791,7 @@ Si aa aa aa -aX +Ds aa aa vn @@ -4939,7 +4950,7 @@ dW BL aa aa -bo +vJ aa vn vn diff --git a/voidcrew/_maps/map_files/outposts/trader_outpost_general.dmm b/voidcrew/_maps/map_files/outposts/trader_outpost_general.dmm index 4d3818bc19e..d7dc71a02ad 100644 --- a/voidcrew/_maps/map_files/outposts/trader_outpost_general.dmm +++ b/voidcrew/_maps/map_files/outposts/trader_outpost_general.dmm @@ -363,15 +363,6 @@ /obj/structure/sign/departments/medbay/alt/directional/east, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) -"aP" = ( -/obj/machinery/door/airlock/outpost/checkpoint{ - checkpoint_id = "halcyon_elevator"; - dir = 2 - }, -/obj/effect/turf_decal/siding/thinplating_new, -/obj/effect/turf_decal/tile/neutral/full, -/turf/open/indestructible/large, -/area/voidcrew/trader_outpost) "aQ" = ( /obj/structure/railing/unbreakable{ dir = 5 @@ -1022,6 +1013,12 @@ }, /turf/open/indestructible/stone, /area/voidcrew/trader_outpost) +"fW" = ( +/obj/structure/table/reinforced, +/obj/effect/turf_decal/tile/dark/full, +/obj/effect/invisible_wall, +/turf/open/indestructible/dark/smooth_large, +/area/voidcrew/trader_outpost) "gh" = ( /obj/effect/turf_decal/siding/wideplating_new/dark{ dir = 9 @@ -1265,6 +1262,12 @@ }, /turf/open/indestructible/dark/smooth_large, /area/voidcrew/trader_outpost) +"ix" = ( +/obj/structure/window/reinforced/shuttle/indestructible, +/obj/effect/turf_decal/siding/thinplating_new, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "iF" = ( /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -1556,6 +1559,14 @@ }, /turf/open/water/outpost_pond, /area/voidcrew/trader_outpost) +"mm" = ( +/obj/structure/window/reinforced/shuttle/indestructible, +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "mo" = ( /obj/structure/closet/crate/freezer{ name = "cold-crate" @@ -1588,6 +1599,17 @@ }, /turf/open/water/outpost_pond, /area/voidcrew/trader_outpost) +"mv" = ( +/obj/machinery/light/floor, +/obj/structure/railing/unbreakable{ + dir = 10 + }, +/obj/effect/turf_decal/siding/wideplating_new{ + dir = 10 + }, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "mA" = ( /obj/machinery/hydroponics/soil, /obj/item/seeds/wheat, @@ -1779,6 +1801,15 @@ /obj/structure/extinguisher_cabinet/directional/south, /turf/open/indestructible, /area/voidcrew/trader_outpost) +"oH" = ( +/obj/structure/window/reinforced/shuttle/indestructible, +/obj/effect/turf_decal/siding/wideplating_new/corner, +/obj/effect/turf_decal/siding/thinplating_new/corner{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "oI" = ( /obj/machinery/hydroponics/constructable, /obj/effect/turf_decal/weather/dirt{ @@ -1869,10 +1900,6 @@ }, /turf/open/indestructible/hotelwood, /area/voidcrew/trader_outpost) -"qw" = ( -/obj/structure/flora/bush/ferny/style_random, -/turf/open/floor/grass, -/area/voidcrew/trader_outpost) "qy" = ( /obj/effect/turf_decal/tile/neutral{ dir = 8 @@ -2078,6 +2105,17 @@ }, /turf/open/indestructible/dark/smooth_large, /area/voidcrew/trader_outpost) +"sZ" = ( +/obj/machinery/light/floor, +/obj/structure/railing/unbreakable{ + dir = 6 + }, +/obj/effect/turf_decal/siding/wideplating_new{ + dir = 6 + }, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "ta" = ( /obj/effect/turf_decal/siding/wideplating_new{ dir = 4 @@ -2193,19 +2231,6 @@ /obj/machinery/light/directional/north, /turf/open/indestructible/kitchen, /area/voidcrew/trader_outpost) -"tR" = ( -/obj/structure/chair/stool/directional/south, -/obj/effect/turf_decal/trimline/neutral/filled/line{ - dir = 1 - }, -/obj/effect/turf_decal/siding/thinplating_new/dark{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/neutral/filled/mid_joiner{ - dir = 1 - }, -/turf/open/indestructible/dark/smooth_large, -/area/voidcrew/trader_outpost) "tS" = ( /obj/structure/reagent_dispensers/watertank/high, /obj/item/reagent_containers/cup/bucket, @@ -2466,6 +2491,14 @@ }, /turf/open/indestructible/hotelwood, /area/voidcrew/trader_outpost) +"wz" = ( +/obj/structure/window/reinforced/shuttle/indestructible, +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "wA" = ( /obj/effect/turf_decal/siding/wideplating_new{ dir = 8 @@ -2479,6 +2512,17 @@ }, /turf/open/indestructible, /area/voidcrew/trader_outpost) +"wD" = ( +/obj/machinery/light/floor, +/obj/structure/railing/unbreakable{ + dir = 5 + }, +/obj/effect/turf_decal/siding/wideplating_new{ + dir = 5 + }, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "wE" = ( /obj/structure/railing/unbreakable{ dir = 4 @@ -2523,10 +2567,6 @@ /obj/machinery/light/floor, /turf/open/indestructible/grass, /area/voidcrew/trader_outpost) -"xf" = ( -/obj/structure/beebox/premade, -/turf/open/misc/dirt/station, -/area/voidcrew/trader_outpost) "xh" = ( /obj/effect/turf_decal/tile/blue/opposingcorners, /obj/effect/turf_decal/siding/thinplating_new/light{ @@ -2868,6 +2908,17 @@ /obj/effect/turf_decal/tile/neutral/full, /turf/open/indestructible/large, /area/voidcrew/trader_outpost) +"Af" = ( +/obj/structure/window/reinforced/shuttle/indestructible, +/obj/effect/turf_decal/siding/wideplating_new/corner{ + dir = 8 + }, +/obj/effect/turf_decal/siding/thinplating_new/corner{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "Al" = ( /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 6 @@ -3547,6 +3598,25 @@ /obj/effect/turf_decal/tile/neutral/full, /turf/open/indestructible/large, /area/voidcrew/trader_outpost) +"GZ" = ( +/obj/machinery/light/floor, +/obj/structure/railing/unbreakable{ + dir = 9 + }, +/obj/effect/turf_decal/siding/wideplating_new{ + dir = 9 + }, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) +"Hc" = ( +/obj/structure/window/reinforced/shuttle/indestructible, +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "Hn" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -4603,6 +4673,17 @@ }, /turf/open/indestructible/hoteltile, /area/voidcrew/trader_outpost) +"RK" = ( +/obj/structure/window/reinforced/shuttle/indestructible, +/obj/effect/turf_decal/siding/wideplating_new/corner{ + dir = 4 + }, +/obj/effect/turf_decal/siding/thinplating_new/corner{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "RP" = ( /obj/machinery/sleeper/outpost{ dir = 8 @@ -4725,15 +4806,6 @@ }, /turf/open/indestructible/hotelwood, /area/voidcrew/trader_outpost) -"Tc" = ( -/obj/structure/chair/sofa/corp{ - dir = 4 - }, -/obj/effect/turf_decal/siding/thinplating_new/dark{ - dir = 8 - }, -/turf/open/indestructible/dark/smooth_large, -/area/voidcrew/trader_outpost) "Tf" = ( /obj/effect/decal/cleanable/cobweb/cobweb2, /turf/open/indestructible/hoteltile, @@ -5273,6 +5345,15 @@ }, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) +"XY" = ( +/obj/structure/window/reinforced/shuttle/indestructible, +/obj/effect/turf_decal/siding/wideplating_new/corner{ + dir = 1 + }, +/obj/effect/turf_decal/siding/thinplating_new/corner, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "Ya" = ( /obj/structure/flora/bush/sparsegrass/style_random, /turf/open/floor/grass, @@ -5337,6 +5418,15 @@ "Yz" = ( /turf/open/indestructible/light, /area/voidcrew/trader_outpost) +"YC" = ( +/obj/machinery/door/airlock/outpost/checkpoint/glass{ + checkpoint_id = "halcyon_elevator"; + dir = 2 + }, +/obj/effect/turf_decal/siding/thinplating_new, +/obj/effect/turf_decal/tile/neutral/full, +/turf/open/indestructible/large, +/area/voidcrew/trader_outpost) "YJ" = ( /obj/structure/flora/rock/style_3, /turf/open/water/outpost_pond, @@ -5839,13 +5929,13 @@ Ya Uv Uv aj -xf +wU UF Uv uX aj UF -xf +wU Uv aj Uv @@ -5906,7 +5996,7 @@ rh Uv pe Uv -qw +mH Ya TD Pa @@ -6038,11 +6128,11 @@ NF Ya uX PG -xf +wU Uv UF aj -xf +wU Uv Uv mA @@ -7468,7 +7558,7 @@ as ak ak Qq -Tc +ci sX Ij tl @@ -7819,13 +7909,13 @@ Tg aZ aY aY -lf -ak -ak -ak -ak -ak -dp +GZ +XY +wz +wz +wz +Af +mv WP aY aY @@ -7841,7 +7931,7 @@ ak VP QJ ae -tR +nq cM im Ke @@ -7886,11 +7976,11 @@ ac aY aY GQ -ak +ix al ah aa -ak +Hc eK ac aY @@ -7907,7 +7997,7 @@ ZG ao JN ae -tR +nq id im Ke @@ -7952,11 +8042,11 @@ kE Or kE aM -aP +YC aR aq an -ak +fW dk kE Or @@ -8018,11 +8108,11 @@ WP aY aY GQ -ak +ix aA ax av -ak +Hc eK WP aY @@ -8039,7 +8129,7 @@ nR Ki HZ ae -tR +nq id im Ke @@ -8083,13 +8173,13 @@ Tg aZ aY aY -aQ -ak -ak -ak -ak -ak -Md +wD +RK +mm +mm +mm +oH +sZ ac aY aY diff --git a/voidcrew/_maps/map_files/outposts/trader_outpost_outfitter.dmm b/voidcrew/_maps/map_files/outposts/trader_outpost_outfitter.dmm index f8e4c5436b0..fd11dd179ee 100644 --- a/voidcrew/_maps/map_files/outposts/trader_outpost_outfitter.dmm +++ b/voidcrew/_maps/map_files/outposts/trader_outpost_outfitter.dmm @@ -114,10 +114,6 @@ "ao" = ( /turf/template_noop, /area/template_noop) -"ap" = ( -/obj/effect/turf_decal/siding/thinplating_new/dark, -/turf/open/indestructible/dark, -/area/voidcrew/trader_outpost) "aq" = ( /obj/structure/railing/unbreakable{ dir = 4 @@ -260,19 +256,6 @@ /obj/structure/closet/crate, /turf/open/indestructible/dark/smooth_large, /area/voidcrew/trader_outpost) -"aI" = ( -/obj/machinery/door/airlock/outpost/checkpoint{ - checkpoint_id = "quartermain_west_yard"; - dir = 4; - name = "West Yard Gate" - }, -/obj/effect/turf_decal/bot, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt/dust, -/turf/open/indestructible/plating, -/area/voidcrew/trader_outpost) "aJ" = ( /obj/effect/turf_decal/tile/yellow/half/contrasted{ dir = 1 @@ -445,15 +428,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/indestructible/white, /area/voidcrew/trader_outpost) -"ba" = ( -/obj/effect/turf_decal/bot, -/obj/machinery/door/airlock/outpost/checkpoint{ - checkpoint_id = "quartermain_elevator"; - dir = 2; - name = "Hangar Elevator" - }, -/turf/open/indestructible/dark/textured, -/area/voidcrew/trader_outpost) "bb" = ( /obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ checkpoint_id = "quartermain_elevator"; @@ -476,19 +450,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) -"bd" = ( -/obj/effect/turf_decal/bot, -/obj/machinery/door/airlock/outpost/checkpoint{ - checkpoint_id = "quartermain_east_yard"; - dir = 4; - name = "East Yard Gate" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt/dust, -/turf/open/indestructible/plating, -/area/voidcrew/trader_outpost) "be" = ( /obj/machinery/scanner_gate/preset_guns/outpost_checkpoint{ checkpoint_id = "quartermain_east_yard"; @@ -1469,6 +1430,19 @@ /obj/effect/decal/cleanable/dirt/dust, /turf/open/indestructible/dark/textured, /area/voidcrew/trader_outpost) +"oH" = ( +/obj/effect/turf_decal/bot, +/obj/machinery/door/airlock/outpost/checkpoint/glass{ + checkpoint_id = "quartermain_east_yard"; + dir = 4; + name = "East Yard Gate" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/plating, +/area/voidcrew/trader_outpost) "oU" = ( /obj/effect/turf_decal/siding/wideplating_new/dark{ dir = 8 @@ -2361,6 +2335,19 @@ icon_state = "stairs-l" }, /area/voidcrew/trader_outpost) +"Af" = ( +/obj/machinery/door/airlock/outpost/checkpoint/glass{ + checkpoint_id = "quartermain_west_yard"; + dir = 4; + name = "West Yard Gate" + }, +/obj/effect/turf_decal/bot, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/plating, +/area/voidcrew/trader_outpost) "Ah" = ( /obj/effect/turf_decal/trimline/yellow/corner{ dir = 8 @@ -3823,6 +3810,15 @@ }, /turf/open/indestructible/dark, /area/voidcrew/trader_outpost) +"XY" = ( +/obj/effect/turf_decal/bot, +/obj/machinery/door/airlock/outpost/checkpoint/glass{ + checkpoint_id = "quartermain_elevator"; + dir = 2; + name = "Hangar Elevator" + }, +/turf/open/indestructible/dark/textured, +/area/voidcrew/trader_outpost) "XZ" = ( /obj/effect/decal/cleanable/dirt, /turf/open/indestructible/dark, @@ -4426,7 +4422,7 @@ dU dU dU dU -aI +Af dU lE lE @@ -4530,7 +4526,7 @@ KA ly ly aS -ba +XY bb at as @@ -4939,11 +4935,11 @@ WK Gw Gw pp -ap +ah aH aD qk -ap +ah aH aD qk @@ -4977,11 +4973,11 @@ au cg Ky ly -ap +ah aA aD qk -ap +ah IF fc qk @@ -5019,7 +5015,7 @@ au cg BD ly -ap +ah aD aH qk @@ -5027,7 +5023,7 @@ gT aD aH qk -ap +ah aD IF qk @@ -5061,15 +5057,15 @@ au Jt JH ly -ap +ah aD su qk -ap +ah aD aD qk -ap +ah aH aD qk @@ -5145,11 +5141,11 @@ au cg fC ly -ap +ah aD fc qk -ap +ah aD su qk @@ -5187,15 +5183,15 @@ au tQ Yg vb -ap +ah fc vQ qk -ap +ah aH aA qk -ap +ah aD aH qk @@ -5237,7 +5233,7 @@ gT aD aH qk -ap +ah aA aD cA @@ -5275,11 +5271,11 @@ Ob Ei ly ly -ap +ah aD aH qk -ap +ah aD aA qk @@ -5414,7 +5410,7 @@ dU dU dU dU -bd +oH dU dU aV diff --git a/voidcrew/modules/trade/outpost_security.dm b/voidcrew/modules/trade/outpost_security.dm index 766141d126c..9d703991c26 100644 --- a/voidcrew/modules/trade/outpost_security.dm +++ b/voidcrew/modules/trade/outpost_security.dm @@ -370,6 +370,19 @@ GLOBAL_DATUM_INIT(outpost_pvp_enforcement, /datum/outpost_pvp_enforcement, new) var/checkpoint_id var/list/obj/machinery/scanner_gate/preset_guns/outpost_checkpoint/checkpoint_scanners = list() +// Match the public concourses without losing the checkpoint's scan gate. +/obj/machinery/door/airlock/outpost/checkpoint/glass + icon = 'icons/obj/doors/airlocks/public/glass.dmi' + overlays_file = 'icons/obj/doors/airlocks/public/overlays.dmi' + opacity = FALSE + glass = TRUE + +// Undertow uses the same interior plating as its bar access door. +/obj/machinery/door/airlock/outpost/checkpoint/grunge + icon = 'icons/obj/doors/airlocks/centcom/centcom.dmi' + overlays_file = 'icons/obj/doors/airlocks/centcom/overlays.dmi' + can_be_glass = FALSE + /obj/machinery/door/airlock/outpost/checkpoint/Initialize(mapload) . = ..() AddElement(/datum/element/outpost_property) diff --git a/voidcrew/modules/unit_tests/voidcrew_outpost_safe_hubs.dm b/voidcrew/modules/unit_tests/voidcrew_outpost_safe_hubs.dm index 6d74b72c017..fc362c84ace 100644 --- a/voidcrew/modules/unit_tests/voidcrew_outpost_safe_hubs.dm +++ b/voidcrew/modules/unit_tests/voidcrew_outpost_safe_hubs.dm @@ -339,11 +339,38 @@ var/obj/structure/overmap/trader_outpost/market = allocate(host_type) TEST_ASSERT(market.load_level(), "Could not load [host_type]") var/turf/origin = market.template_bottom_left + var/list/restored_fixtures = list() + var/expected_door_type = /obj/machinery/door/airlock/outpost/checkpoint/glass + var/obj/machinery/door/airlock/style_type = /obj/machinery/door/airlock/public/glass + if(host_type == /obj/structure/overmap/trader_outpost/general) + restored_fixtures = list( + list(36, 29, /obj/machinery/light/floor), + list(40, 29, /obj/machinery/light/floor), + list(36, 35, /obj/machinery/light/floor), + list(40, 35, /obj/machinery/light/floor), + list(38, 30, /obj/structure/table/reinforced), + ) + else if(host_type == /obj/structure/overmap/trader_outpost/black_market) + expected_door_type = /obj/machinery/door/airlock/outpost/checkpoint/grunge + style_type = /obj/machinery/door/airlock/centcom + restored_fixtures = list( + list(28, 6, /obj/item/radio/intercom/directional/south), + list(28, 6, /obj/machinery/light/red/directional/south), + list(28, 8, /obj/machinery/newscaster/directional/north), + ) + for(var/list/fixture as anything in restored_fixtures) + var/turf/fixture_turf = locate(origin.x + fixture[1] - 1, origin.y + fixture[2] - 1, origin.z) + var/obj/restored = locate(fixture[3]) in fixture_turf + TEST_ASSERT_NOTNULL(restored, "[host_type] lost [fixture[3]] beside its elevator") var/list/entries = circuits[host_type] for(var/list/entry as anything in entries) var/turf/door_turf = locate(origin.x + entry[1] - 1, origin.y + entry[2] - 1, origin.z) var/obj/machinery/door/airlock/outpost/checkpoint/checkpoint = locate() in door_turf TEST_ASSERT_NOTNULL(checkpoint, "[host_type] is missing its checkpoint at [entry[1]],[entry[2]]") + TEST_ASSERT_EQUAL(checkpoint.type, expected_door_type, "Mapped checkpoint lost its interior door style") + TEST_ASSERT_EQUAL(checkpoint.icon, initial(style_type.icon), "Mapped checkpoint has the wrong door sprite") + TEST_ASSERT_EQUAL(checkpoint.overlays_file, initial(style_type.overlays_file), "Mapped checkpoint has the wrong door overlays") + TEST_ASSERT_EQUAL(checkpoint.glass, initial(style_type.glass), "Mapped checkpoint has the wrong glazing") TEST_ASSERT_EQUAL(checkpoint.outpost, market, "Mapped checkpoint linked to the wrong host") TEST_ASSERT_EQUAL(length(checkpoint.checkpoint_scanners), 2, "Mapped checkpoint does not have two scanners") TEST_ASSERT(HAS_TRAIT(checkpoint, "outpost_property"), "Mapped checkpoint lost property protection") @@ -355,9 +382,18 @@ TEST_ASSERT(gate in checkpoint.checkpoint_scanners, "Mapped approach scanner is not in the circuit") TEST_ASSERT_EQUAL(gate.checkpoint_door?.resolve(), checkpoint, "Mapped scanner points at the wrong door") TEST_ASSERT(HAS_TRAIT(gate, "outpost_property"), "Mapped scanner lost property protection") + TEST_ASSERT(gate.anchored, "Mapped scanner can travel with the elevator") for(var/atom/movable/blocker in approach) TEST_ASSERT(!blocker.density, "[blocker] blocks a checkpoint approach") + // Equip the rider before permitting the automatic turf-entry scan. + var/old_stat = gate.machine_stat + gate.set_machine_stat(NOPOWER) var/mob/living/carbon/human/rider = allocate(/mob/living/carbon/human, approach) + var/obj/item/gun/weapon = allocate(/obj/item/gun/ballistic/automatic/pistol, rider) + gate.set_machine_stat(old_stat) + gate.perform_scan(rider) + TEST_ASSERT(checkpoint.density && !checkpoint.operating, "A styled checkpoint admitted an armed rider") + qdel(weapon) gate.perform_scan(rider) sleep(2 SECONDS) TEST_ASSERT(!checkpoint.density, "A mapped circuit did not open from direction [direction]") @@ -372,9 +408,12 @@ var/turf/landing = locate(origin.x + entry[4] + x_offset - 1, origin.y + entry[5] + y_offset - 1, origin.z) TEST_ASSERT_EQUAL(market.lobby_alcove_turfs[++index], landing, "Elevator landing order changed") TEST_ASSERT(isopenturf(landing), "Elevator landing was walled over") + for(var/atom/movable/blocker in landing) + TEST_ASSERT(!blocker.density, "[blocker] blocks an elevator landing") TEST_ASSERT_EQUAL(length(market.lobby_panels), 1, "Elevator panel disappeared") var/obj/machinery/outpost_elevator/panel = market.lobby_panels[1] TEST_ASSERT_EQUAL(panel.get_own_alcove(), market.lobby_alcove_turfs, "Elevator panel lost its ordered landing") + TEST_ASSERT(get_turf(panel) in market.lobby_alcove_turfs, "Elevator panel cannot be reached from its landing") check_elevator_travel(market, panel) checked++ TEST_ASSERT_EQUAL(checked, 6, "Did not check all six trader entrances") @@ -391,14 +430,23 @@ berth.panel.outpost = market berth.panel.berth = berth var/list/obj/item/coin/passengers = list() + var/list/stationary_fixtures = list() for(var/turf/landing as anything in market.lobby_alcove_turfs) passengers += allocate(/obj/item/coin, landing) + for(var/obj/machinery/fixture in landing) + if(fixture.anchored) + stationary_fixtures[fixture] = landing var/mob/living/carbon/human/rider = allocate(/mob/living/carbon/human, market.lobby_alcove_turfs[5]) + TEST_ASSERT(get_dist(rider, lobby_panel) <= 1, "Elevator controls are out of reach of a standing rider") lobby_panel.complete_ride(1, WEAKREF(rider)) + for(var/obj/machinery/fixture as anything in stationary_fixtures) + TEST_ASSERT_EQUAL(get_turf(fixture), stationary_fixtures[fixture], "Elevator carried an anchored fixture downstairs") for(var/i in 1 to 9) TEST_ASSERT_EQUAL(get_turf(passengers[i]), berth.alcove_turfs[i], "Elevator changed the outgoing tile order") TEST_ASSERT_EQUAL(get_turf(rider), berth.alcove_turfs[5], "Elevator did not carry the rider down") berth.panel.complete_ride(0, WEAKREF(rider)) + for(var/obj/machinery/fixture as anything in stationary_fixtures) + TEST_ASSERT_EQUAL(get_turf(fixture), stationary_fixtures[fixture], "Elevator moved an anchored fixture on return") for(var/i in 1 to 9) TEST_ASSERT_EQUAL(get_turf(passengers[i]), market.lobby_alcove_turfs[i], "Elevator changed the returning tile order") TEST_ASSERT_EQUAL(get_turf(rider), market.lobby_alcove_turfs[5], "Elevator did not return the rider") From 0e200c5b3c9750d7e6403f8aeae1217c72f4d812 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:45:00 -0700 Subject: [PATCH 017/105] Validate nanite backups against receiving research --- .../code/machines/nanite_cloud_control.dm | 25 ++- .../unit_tests/voidcrew_nanite_research.dm | 181 ++++++++++++++++++ 2 files changed, 204 insertions(+), 2 deletions(-) diff --git a/voidcrew/modules/nanites/code/machines/nanite_cloud_control.dm b/voidcrew/modules/nanites/code/machines/nanite_cloud_control.dm index 54a4ace922d..cdc4a5bb254 100644 --- a/voidcrew/modules/nanites/code/machines/nanite_cloud_control.dm +++ b/voidcrew/modules/nanites/code/machines/nanite_cloud_control.dm @@ -1,6 +1,6 @@ /obj/machinery/computer/nanite_cloud_controller name = "nanite programmer" - desc = "Downloads nanite programs from the techweb servers, edits them, and stores and controls nanite cloud backups. Cloud networks are local to the ship this console is aboard: nanites can only join one by having their cloud ID set in a nanite chamber on the same ship, and cloud IDs on other ships are separate networks even if the numbers match." + desc = "A console for programming nanites and storing cloud backups." icon = 'voidcrew/modules/nanites/icons/research.dmi' icon_state = "nanite_cloud_controller" circuit = /obj/item/circuitboard/computer/nanite_cloud_controller @@ -223,6 +223,25 @@ data["cloud_backups"] = backup_list return data +/// Check the whole backup against the receiver's live research before replacing any programs. +/obj/machinery/computer/nanite_cloud_controller/proc/can_import_backup(list/programs) + if(QDELETED(linked_techweb)) + unsync_research_servers() + return FALSE + if(!validate_research_site(linked_techweb) || !islist(programs)) + return FALSE + var/list/researched_program_types = list() + for(var/design_id in linked_techweb.researched_designs) + var/datum/design/nanites/design = linked_techweb.isDesignResearchedID(design_id) + if(!istype(design) || QDELETED(design) || !(design.build_type & NANITE_PROGRAM) || !ispath(design.program_type, /datum/nanite_program)) + continue + researched_program_types[design.program_type] = TRUE + // Do not filter this loop: an invalid entry must reject the entire backup. + for(var/datum/nanite_program/program as anything in programs) + if(!istype(program) || QDELETED(program) || !researched_program_types[program.type]) + return FALSE + return TRUE + /obj/machinery/computer/nanite_cloud_controller/ui_static_data(mob/user) var/list/data = list() if(!validate_research_site(linked_techweb)) @@ -352,9 +371,11 @@ disk.backup += program.copy() . = TRUE if("load_backup") - if(disk) + if(!QDELETED(disk) && disk.loc == src) var/datum/nanite_cloud_backup/backup = get_backup(current_view) if(backup) + if(!can_import_backup(disk.backup)) + return TRUE playsound(src, 'sound/machines/terminal/terminal_prompt.ogg', 25, FALSE) var/datum/component/nanites/nanites = backup.nanites QDEL_LIST(nanites.programs) diff --git a/voidcrew/modules/unit_tests/voidcrew_nanite_research.dm b/voidcrew/modules/unit_tests/voidcrew_nanite_research.dm index d97425efefa..4b198eabab0 100644 --- a/voidcrew/modules/unit_tests/voidcrew_nanite_research.dm +++ b/voidcrew/modules/unit_tests/voidcrew_nanite_research.dm @@ -74,6 +74,187 @@ TEST_ASSERT_NULL(programmer.linked_techweb, "Programmer UI refresh retained a separated research link") TEST_ASSERT(istype(programmer.current_program, /datum/nanite_program/monitoring), "Programmer UI refresh erased the program being edited") +/// Imports must use the receiving controller's current research, never the disk or cloud's history. +/datum/unit_test/voidcrew_nanite_research/backup_import + abstract_type = /datum/unit_test/voidcrew_nanite_research/backup_import + var/obj/machinery/computer/nanite_cloud_controller/controller + var/obj/item/disk/nanite_program/backup_disk + var/datum/nanite_cloud_backup/cloud + var/datum/nanite_program/cloud_program + var/datum/nanite_program/cloud_settings + var/datum/nanite_program/disk_program + var/datum/nanite_program/disk_settings + var/datum/tgui/ui + +/datum/unit_test/voidcrew_nanite_research/backup_import/proc/setup_import() + if(!setup_links()) + return FALSE + web.add_design_by_id("selfscan_nanites") + web.researched_designs -= "monitoring_nanites" + controller = allocate(/obj/machinery/computer/nanite_cloud_controller) + controller.multitool_act(user, tool) + controller.current_view = 95 + controller.generate_backup(controller.current_view, user) + cloud = controller.get_backup(controller.current_view) + if(!cloud) + return FALSE + cloud_program = allocate(/datum/nanite_program/self_scan) + cloud_program.activation_code = 1234 + cloud_program.timer_restart = 120 + cloud_program.set_extra_setting("Scan Type", "Chemical") // NES_SCAN_TYPE + cloud.nanites.add_program(null, cloud_program) + cloud_settings = allocate(/datum/nanite_program/self_scan) + cloud_program.copy_programming(cloud_settings) + backup_disk = allocate(/obj/item/disk/nanite_program, controller) + controller.disk = backup_disk + disk_program = allocate(/datum/nanite_program/self_scan) + disk_program.activated = FALSE + disk_program.activation_code = 4321 + disk_program.deactivation_code = 2345 + disk_program.kill_code = 3456 + disk_program.trigger_code = 4567 + disk_program.timer_restart = 230 + disk_program.timer_shutdown = 340 + disk_program.timer_trigger = 450 + disk_program.timer_trigger_delay = 560 + disk_program.all_rules_required = FALSE + disk_program.set_extra_setting("Scan Type", "Nanite") // NES_SCAN_TYPE + allocate(/datum/nanite_rule/health, disk_program) + backup_disk.backup += disk_program + disk_settings = allocate(/datum/nanite_program/self_scan) + disk_program.copy_programming(disk_settings) + allocated += disk_settings.rules + ui = allocate(/datum/tgui, user, controller, "NaniteCloudControl") + return TRUE + +/datum/unit_test/voidcrew_nanite_research/backup_import/proc/assert_rejected(reason) + var/list/contents_before = backup_disk.backup.Copy() + controller.ui_act("load_backup", list(), ui) + TEST_ASSERT_EQUAL(length(cloud.nanites.programs), 1, "[reason]: rejection changed the cloud's program count") + TEST_ASSERT(cloud_program in cloud.nanites.programs, "[reason]: rejection replaced the existing cloud program") + TEST_ASSERT(!QDELETED(cloud_program), "[reason]: rejection deleted the existing cloud program") + TEST_ASSERT(!cloud_settings.programming_differs(cloud_program), "[reason]: rejection changed existing cloud settings") + TEST_ASSERT_EQUAL(controller.disk, backup_disk, "[reason]: rejection discarded the source disk") + TEST_ASSERT(!QDELETED(backup_disk), "[reason]: rejection deleted the source disk") + TEST_ASSERT_EQUAL(length(backup_disk.backup), length(contents_before), "[reason]: rejection changed the disk's program count") + for(var/index in 1 to length(contents_before)) + TEST_ASSERT_EQUAL(backup_disk.backup[index], contents_before[index], "[reason]: rejection changed a disk entry") + TEST_ASSERT(!QDELETED(disk_program), "[reason]: rejection deleted the disk's permitted program") + TEST_ASSERT(!disk_settings.programming_differs(disk_program), "[reason]: rejection changed disk settings") + +/datum/unit_test/voidcrew_nanite_research/backup_import/permitted/Run() + TEST_ASSERT(setup_import(), "Could not prepare backup import testing") + web.add_design_by_id("monitoring_nanites") + var/datum/nanite_program/second_program = allocate(/datum/nanite_program/monitoring) + backup_disk.backup += second_program + controller.ui_act("load_backup", list(), ui) + TEST_ASSERT(QDELETED(cloud_program), "A permitted import did not replace the old cloud program") + TEST_ASSERT_EQUAL(length(cloud.nanites.programs), 2, "A permitted import did not load the entire disk") + var/datum/nanite_program/imported = cloud.nanites.programs[1] + TEST_ASSERT_EQUAL(imported.type, disk_program.type, "A permitted import changed the program type") + TEST_ASSERT(imported != disk_program, "A permitted import installed the source datum instead of a copy") + TEST_ASSERT(!disk_settings.programming_differs(imported), "A permitted import lost codes, timers, rules or extra settings") + allocated += imported.rules + var/datum/nanite_program/second_imported = cloud.nanites.programs[2] + TEST_ASSERT_EQUAL(second_imported.type, second_program.type, "A permitted import lost its second program") + TEST_ASSERT(second_imported != second_program, "A permitted import took its second program from the disk") + TEST_ASSERT_EQUAL(controller.disk, backup_disk, "A permitted import discarded its disk") + TEST_ASSERT_EQUAL(backup_disk.backup[1], disk_program, "A permitted import replaced the first disk program") + TEST_ASSERT_EQUAL(backup_disk.backup[2], second_program, "A permitted import replaced the second disk program") + TEST_ASSERT(!disk_settings.programming_differs(disk_program), "A permitted import changed the disk's settings") + backup_disk.backup.Cut() + controller.ui_act("load_backup", list(), ui) + TEST_ASSERT_EQUAL(length(cloud.nanites.programs), 0, "A valid local research link could not import an empty backup") + +/datum/unit_test/voidcrew_nanite_research/backup_import/forbidden/Run() + TEST_ASSERT(setup_import(), "Could not prepare backup rejection testing") + var/datum/nanite_program/forbidden = allocate(/datum/nanite_program/monitoring) + backup_disk.backup += forbidden + assert_rejected("Permitted program followed by an unresearched program") + TEST_ASSERT(!QDELETED(forbidden), "Rejection deleted the disk's unresearched program") + backup_disk.backup.Swap(1, 2) + assert_rejected("Unresearched program followed by a permitted program") + backup_disk.backup = list(disk_program) + var/datum/nanite_program/unknown = allocate(/datum/nanite_program/sensor) + unknown.name = disk_program.name + backup_disk.backup += unknown + web.add_design_by_id("repeater_nanites") + assert_rejected("Unknown actual type with a permitted display name and researched sensor subtype") + backup_disk.backup = list(disk_program) + var/datum/nanite_program/deleted = allocate(/datum/nanite_program/self_scan) + qdel(deleted) + for(var/invalid in list(null, "invalid program", /datum/nanite_program/self_scan, deleted)) + backup_disk.backup += list(invalid) + assert_rejected("Invalid disk entry [invalid]") + backup_disk.backup.Cut(2) + // An open catalog must confer no authority after research changes. + controller.ui_static_data(user) + web.researched_designs["selfscan_nanites"] = FALSE + assert_rejected("Research removed after catalog generation") + +/datum/unit_test/voidcrew_nanite_research/backup_import/research_link/Run() + TEST_ASSERT(setup_import(), "Could not prepare backup research-link testing") + controller.unsync_research_servers() + assert_rejected("Missing receiver research, despite the cloud's old research attribution") + backup_disk.backup.Cut() + assert_rejected("Empty backup without receiver research") + var/datum/techweb/deleted_web = allocate(/datum/techweb) + qdel(deleted_web) + controller.linked_techweb = deleted_web + assert_rejected("Empty backup with a deleted receiver techweb") + TEST_ASSERT_NULL(controller.linked_techweb, "A rejected import retained a deleted research link") + backup_disk.backup += disk_program + for(var/move_server in list(FALSE, TRUE)) + controller.multitool_act(user, tool) + move_apart(controller, move_server) + assert_rejected("Separated research endpoints (server moved: [move_server])") + TEST_ASSERT_NULL(controller.linked_techweb, "A rejected import retained a foreign research link") + TEST_ASSERT(!(controller in web.connected_machines), "A rejected import retained a foreign research registration") + server.forceMove(run_loc_floor_bottom_left) + controller.forceMove(run_loc_floor_bottom_left) + controller.multitool_act(user, tool) + var/obj/item/computer_disk/ship_disk/source_disk = server.source_code_hdd + source_disk.forceMove(run_loc_floor_bottom_left) + // Even a stale reference to the removed disk must not authorize an import. + controller.linked_techweb = web + web.connected_machines |= controller + assert_rejected("Removed research source disk") + TEST_ASSERT_NULL(controller.linked_techweb, "A rejected import retained a removed research disk's link") + server.attacked_by(source_disk, user) + controller.multitool_act(user, tool) + backup_disk.forceMove(run_loc_floor_bottom_left) + assert_rejected("Removed backup disk with a stale controller reference") + backup_disk.forceMove(controller) + server.forceMove(remote_turf) + controller.forceMove(remote_turf) + controller.ui_act("load_backup", list(), ui) + TEST_ASSERT(QDELETED(cloud_program), "Moving both endpoints together prevented a permitted import") + TEST_ASSERT_EQUAL(length(cloud.nanites.programs), 1, "Moving both endpoints together lost the imported program") + var/datum/nanite_program/imported = cloud.nanites.programs[1] + allocated += imported.rules + TEST_ASSERT(!disk_settings.programming_differs(imported), "Import after movement lost its settings") + +/datum/unit_test/voidcrew_nanite_research/backup_import/checkpoint/Run() + TEST_ASSERT(setup_import(), "Could not prepare nanite checkpoint testing") + controller.current_program = allocate(/datum/nanite_program/monitoring) + var/datum/ship_checkpoint/snapshot = allocate(/datum/ship_checkpoint) + var/machine_text = snapshot.atom_text(controller) + var/datum/parsed_map/parsed = allocate(/datum/parsed_map, "\"a\" = ([machine_text],/turf/template_noop,/area/template_noop)\n(1,1,1) = {\"\na\n\"}\n") + var/datum/map_template/template = allocate(/datum/map_template) + template.cached_map = parsed + template.width = 1 + template.height = 1 + TEST_ASSERT(template.load(run_loc_floor_top_right), "Could not load the checkpoint controller") + var/obj/machinery/computer/nanite_cloud_controller/rebuilt = locate() in run_loc_floor_top_right + TEST_ASSERT_NOTNULL(rebuilt, "The checkpoint omitted its nanite controller") + TEST_ASSERT_EQUAL(length(rebuilt.cloud_backups), 0, "The checkpoint retained cloud backup contents") + TEST_ASSERT_NULL(rebuilt.disk, "The checkpoint retained its source disk") + TEST_ASSERT_NULL(locate(/obj/item/disk/nanite_program) in rebuilt, "The checkpoint copied a program disk into the controller") + TEST_ASSERT_NULL(rebuilt.current_program, "The checkpoint retained the program being edited") + TEST_ASSERT_NULL(rebuilt.linked_techweb, "The checkpoint retained the original research link") + TEST_ASSERT_EQUAL(controller.get_backup(controller.current_view), cloud, "The checkpoint changed the original controller's cloud") + TEST_ASSERT_EQUAL(controller.disk, backup_disk, "The checkpoint changed the original controller's disk") + /datum/unit_test/voidcrew_nanite_research/chambers/Run() TEST_ASSERT(setup_links(), "No separate site exists for nanite chamber testing") for(var/move_server in list(FALSE, TRUE)) From 70ba3c8e508f1f4683c1820b187171f73a9b72a6 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:42:38 -0700 Subject: [PATCH 018/105] Remove fixed equipment from hulls and ruins --- .../RandomRuins/JungleRuins/jungle_botany.dmm | 22 ++++-- .../RandomRuins/JungleRuins/jungle_demon.dmm | 15 ++-- .../jungle_surface_loggingcamp.dmm | 26 +++---- .../lavaland_surface_elephant_graveyard.dmm | 14 ++-- .../lavaland_surface_syndicate_base1.dmm | 19 ++--- .../SpaceRuins/atmosasteroidruin.dmm | 24 ++++--- .../RandomRuins/SpaceRuins/bigderelict1.dmm | 26 ++++--- .../RandomRuins/SpaceRuins/crashedship.dmm | 18 ++--- .../SpaceRuins/dangerous_research.dmm | 16 +++-- .../RandomRuins/SpaceRuins/deepstorage.dmm | 14 ++-- .../RandomRuins/SpaceRuins/forgottenship.dmm | 43 ++++++----- .../SpaceRuins/hilbertresearchfacility.dmm | 18 ++--- .../RandomRuins/SpaceRuins/meatderelict.dmm | 15 ++-- .../RandomRuins/SpaceRuins/mimesvsclowns.dmm | 12 ++-- .../SpaceRuins/old_infiltrator.dmm | 12 ++-- .../RandomRuins/SpaceRuins/oldstation.dmm | 44 ++++++------ .../RandomRuins/SpaceRuins/rare_blacksite.dmm | 31 ++++++-- .../RandomRuins/SpaceRuins/thelizardsgas.dmm | 20 +++--- .../RandomRuins/SpaceRuins/vestige_comb.dmm | 20 ++++-- .../RandomRuins/SpaceRuins/waystation.dmm | 16 +++-- .../SpaceRuins/whiteshipruin_box.dmm | 32 ++++++--- .../WastelandRuins/wasteland_crash_cult.dmm | 68 ++++++++++-------- .../wasteland_miningexpedition.dmm | 20 ++++-- .../WastelandRuins/wasteland_moth.dmm | 38 ++++++---- .../wasteland_surface_starfurycrash.dmm | 31 ++++---- .../WastelandRuins/wasteland_tradepost.dmm | 16 +++-- .../captain_s_quarters_pink.dmm | 20 +++--- .../captain_s_quarters_standard.dmm | 20 +++--- .../captain_s_quarters_syndicate.dmm | 6 +- .../ship_modules/squab/security_director.dmm | 27 +++---- _maps/voidcrew/ships/ship_nano_phalanx_a.dmm | 53 +++++++------- _maps/voidcrew/ships/ship_nano_phalanx_b.dmm | 53 +++++++------- _maps/voidcrew/ships/ship_nano_phalanx_c.dmm | 65 +++++++++-------- _maps/voidcrew/ships/ship_nano_phalanx_d.dmm | 53 +++++++------- ..._class_carrier_captain_s_quarters_pink.png | Bin 11975 -> 12082 bytes ...ss_carrier_captain_s_quarters_standard.png | Bin 11928 -> 12405 bytes ...s_carrier_captain_s_quarters_syndicate.png | Bin 12388 -> 12148 bytes .../hulls/nano_phalanx_a.preview.json | 2 +- .../hulls/nano_phalanx_b.preview.json | 2 +- .../hulls/nano_phalanx_c.preview.json | 2 +- .../hulls/nano_phalanx_d.preview.json | 2 +- .../captain_s_quarters.preview.json | 6 +- .../squab/security_director.preview.json | 2 +- .../previews/ship_nano_phalanx_a.png | Bin 377156 -> 379473 bytes .../previews/ship_nano_phalanx_b.png | Bin 473932 -> 475452 bytes .../previews/ship_nano_phalanx_c.png | Bin 452617 -> 452641 bytes .../previews/ship_nano_phalanx_d.png | Bin 420668 -> 420709 bytes 47 files changed, 532 insertions(+), 411 deletions(-) diff --git a/_maps/voidcrew/RandomRuins/JungleRuins/jungle_botany.dmm b/_maps/voidcrew/RandomRuins/JungleRuins/jungle_botany.dmm index 73bfd039a0d..aa9e644a329 100644 --- a/_maps/voidcrew/RandomRuins/JungleRuins/jungle_botany.dmm +++ b/_maps/voidcrew/RandomRuins/JungleRuins/jungle_botany.dmm @@ -1,4 +1,11 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/atmos/centcom; + storage_type = /obj/item/tank/jetpack/oxygen/captain + }, +/turf/open/floor/iron, +/area/overmap_encounter/planet_ruin) "aM" = ( /obj/structure/table, /obj/item/disk/data, @@ -438,6 +445,13 @@ /obj/item/stack/sheet/mineral/plasma/thirty, /turf/open/floor/iron, /area/overmap_encounter/planet_ruin) +"RO" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/atmos/centcom; + storage_type = /obj/item/tank/jetpack/oxygen/captain + }, +/turf/open/floor/iron, +/area/overmap_encounter/planet_ruin) "Se" = ( /obj/structure/closet/secure_closet/personal, /turf/open/floor/iron, @@ -509,10 +523,6 @@ /obj/item/toy/cards/deck/tarot, /turf/open/floor/iron, /area/overmap_encounter/planet_ruin) -"Zq" = ( -/obj/machinery/suit_storage_unit/ert/engineer, -/turf/open/floor/iron, -/area/overmap_encounter/planet_ruin) "ZO" = ( /obj/structure/bed, /obj/item/bedsheet/green, @@ -547,10 +557,10 @@ Sh "} (2,1,1) = {" nF -Zq +aa Hu Hu -Zq +RO XO aM Vn diff --git a/_maps/voidcrew/RandomRuins/JungleRuins/jungle_demon.dmm b/_maps/voidcrew/RandomRuins/JungleRuins/jungle_demon.dmm index 425306a89c9..4afe9da773d 100644 --- a/_maps/voidcrew/RandomRuins/JungleRuins/jungle_demon.dmm +++ b/_maps/voidcrew/RandomRuins/JungleRuins/jungle_demon.dmm @@ -403,6 +403,14 @@ /obj/structure/flora/junglebush, /turf/open/misc/dirt/jungle, /area/ruin/unpowered) +"KM" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/syndicate; + storage_type = /obj/item/tank/jetpack/oxygen/harness + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/dark, +/area/ruin/powered) "KV" = ( /obj/machinery/light/floor, /obj/effect/decal/cleanable/dirt, @@ -487,11 +495,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark, /area/ruin/powered) -"PA" = ( -/obj/machinery/suit_storage_unit/syndicate, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/dark, -/area/ruin/powered) "QI" = ( /obj/structure/rack, /obj/item/stack/spacecash/c1000, @@ -737,7 +740,7 @@ iB (6,1,1) = {" iB Ed -PA +KM KV Wi Lu diff --git a/_maps/voidcrew/RandomRuins/JungleRuins/jungle_surface_loggingcamp.dmm b/_maps/voidcrew/RandomRuins/JungleRuins/jungle_surface_loggingcamp.dmm index 4054a52f2ec..f28fadb9b08 100644 --- a/_maps/voidcrew/RandomRuins/JungleRuins/jungle_surface_loggingcamp.dmm +++ b/_maps/voidcrew/RandomRuins/JungleRuins/jungle_surface_loggingcamp.dmm @@ -78,20 +78,6 @@ }, /turf/open/floor/plating, /area/ruin/unpowered) -"iS" = ( -/obj/machinery/light/dim, -/obj/item/chainsaw/doomslayer{ - force_on = 35; - name = "THE GREAT TREEFELLER" - }, -/obj/item/clothing/suit/space/syndicate/black{ - name = "Lumberjack Powersuit" - }, -/obj/structure/safe/floor, -/obj/item/grenade/frag, -/obj/item/grenade/frag, -/turf/open/floor/plating, -/area/ruin/powered) "jz" = ( /obj/structure/flora/rock/jungle, /turf/open/misc/grass/jungle, @@ -263,6 +249,16 @@ /obj/structure/mecha_wreckage/ripley, /turf/open/floor/plating, /area/ruin/powered) +"zq" = ( +/obj/machinery/light/dim, +/obj/item/clothing/suit/space/syndicate/black{ + name = "Lumberjack Powersuit" + }, +/obj/structure/safe/floor, +/obj/item/grenade/frag, +/obj/item/grenade/frag, +/turf/open/floor/plating, +/area/ruin/powered) "zu" = ( /obj/structure/railing, /turf/open/floor/carpet/royalblack, @@ -1077,7 +1073,7 @@ Yo AR wP Nr -iS +zq wP Ds Ta diff --git a/_maps/voidcrew/RandomRuins/LavaRuins/lavaland_surface_elephant_graveyard.dmm b/_maps/voidcrew/RandomRuins/LavaRuins/lavaland_surface_elephant_graveyard.dmm index 80908cf0881..98db01097de 100644 --- a/_maps/voidcrew/RandomRuins/LavaRuins/lavaland_surface_elephant_graveyard.dmm +++ b/_maps/voidcrew/RandomRuins/LavaRuins/lavaland_surface_elephant_graveyard.dmm @@ -64,11 +64,6 @@ /obj/effect/turf_decal/box/white, /turf/open/floor/mineral/titanium/purple, /area/ruin/powered/graveyard_shuttle) -"bA" = ( -/obj/machinery/suit_storage_unit/mining/eva, -/obj/effect/turf_decal/box/white, -/turf/open/floor/mineral/titanium/purple, -/area/ruin/powered/graveyard_shuttle) "bE" = ( /obj/machinery/power/shuttle_engine/heater, /obj/structure/window/spawner/directional/north, @@ -278,6 +273,13 @@ icon_state = "wasteland_dug" }, /area/ruin/unpowered/elephant_graveyard) +"tC" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/obj/effect/turf_decal/box/white, +/turf/open/floor/mineral/titanium/purple, +/area/ruin/powered/graveyard_shuttle) "uj" = ( /obj/structure/bed, /obj/item/flashlight/lantern, @@ -1619,7 +1621,7 @@ aW cm bq bS -bA +tC aH aH jx diff --git a/_maps/voidcrew/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm b/_maps/voidcrew/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm index 3505f0c3a99..a115bd1c0c2 100644 --- a/_maps/voidcrew/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm +++ b/_maps/voidcrew/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm @@ -2336,6 +2336,16 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/ruin/syndicate_lava_base/bar) +"vd" = ( +/obj/effect/turf_decal/bot, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/syndicate; + storage_type = /obj/item/tank/jetpack/oxygen/harness + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/ruin/syndicate_lava_base/engineering) "vo" = ( /obj/machinery/light/small/directional/east, /obj/machinery/duct, @@ -3714,13 +3724,6 @@ /obj/structure/tank_dispenser/oxygen, /turf/open/floor/mineral/plastitanium, /area/ruin/syndicate_lava_base/arrivals) -"OZ" = ( -/obj/effect/turf_decal/bot, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/suit_storage_unit/syndicate/lavaland, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/ruin/syndicate_lava_base/engineering) "Pn" = ( /obj/structure/extinguisher_cabinet/directional/east, /obj/structure/cable, @@ -6378,7 +6381,7 @@ vV Gm yv XV -OZ +vd yq CV ju diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/atmosasteroidruin.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/atmosasteroidruin.dmm index 9c2b4c35bc8..a199b42dee5 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/atmosasteroidruin.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/atmosasteroidruin.dmm @@ -282,16 +282,6 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/engine/air, /area/ruin/space/has_grav/atmosasteroid) -"rg" = ( -/obj/machinery/suit_storage_unit/standard_unit, -/obj/effect/turf_decal/tile/yellow/anticorner{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/turf/open/floor/iron/co2_pressurized, -/area/ruin/space/has_grav/atmosasteroid) "rp" = ( /obj/machinery/atmospherics/components/unary/vent_pump/siphon{ dir = 8 @@ -675,6 +665,18 @@ /obj/machinery/light/small/broken/directional/east, /turf/open/floor/engine/co2/equalized_with_regular_air, /area/ruin/space/has_grav/atmosasteroid) +"SS" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/obj/effect/turf_decal/tile/yellow/anticorner{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/turf/open/floor/iron/co2_pressurized, +/area/ruin/space/has_grav/atmosasteroid) "TP" = ( /obj/machinery/atmospherics/components/unary/vent_pump/siphon{ dir = 8 @@ -856,7 +858,7 @@ pU hN fm gG -rg +SS gU kJ Uz diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/bigderelict1.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/bigderelict1.dmm index 65e0788a702..aee63a258f5 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/bigderelict1.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/bigderelict1.dmm @@ -883,15 +883,6 @@ }, /turf/open/floor/iron, /area/ruin/space/has_grav/derelictoutpost/cargobay) -"dT" = ( -/obj/machinery/suit_storage_unit/standard_unit, -/turf/open/floor/iron, -/area/ruin/space/has_grav/derelictoutpost/cargostorage) -"dU" = ( -/obj/machinery/suit_storage_unit/standard_unit, -/obj/machinery/light/directional/north, -/turf/open/floor/iron, -/area/ruin/space/has_grav/derelictoutpost/cargostorage) "dV" = ( /obj/structure/closet/crate, /obj/item/stack/sheet/glass/fifty, @@ -1285,6 +1276,12 @@ /obj/structure/alien/weeds/creature, /turf/closed/wall/mineral/iron, /area/ruin/space/has_grav/derelictoutpost/dockedship) +"BB" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/turf/open/floor/iron, +/area/ruin/space/has_grav/derelictoutpost/cargostorage) "BI" = ( /obj/structure/closet/crate/medical, /obj/item/storage/medkit/brute, @@ -1292,6 +1289,13 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/ruin/space/has_grav/derelictoutpost/cargostorage) +"BZ" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/obj/machinery/light/directional/north, +/turf/open/floor/iron, +/area/ruin/space/has_grav/derelictoutpost/cargostorage) "Cr" = ( /obj/structure/alien/weeds/creature, /obj/structure/alien/weeds/creature, @@ -1787,7 +1791,7 @@ ab ZN dm dL -dT +BB dW dW ex @@ -1823,7 +1827,7 @@ ab Hc Cr dL -dU +BZ dW dW ex diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/crashedship.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/crashedship.dmm index b808f812038..9b1fef0bba8 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/crashedship.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/crashedship.dmm @@ -96,6 +96,15 @@ }, /turf/open/floor/pod/light, /area/ruin/space/has_grav/crashedship/aft) +"et" = ( +/obj/effect/turf_decal/siding/thinplating_new/light{ + dir = 8 + }, +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/turf/open/floor/engine, +/area/ruin/space/has_grav/crashedship/midship) "eC" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -837,13 +846,6 @@ /obj/structure/door_assembly/door_assembly_mhatch, /turf/open/floor/plating/airless, /area/ruin/space/has_grav/crashedship/aft) -"EO" = ( -/obj/effect/turf_decal/siding/thinplating_new/light{ - dir = 8 - }, -/obj/machinery/suit_storage_unit/standard_unit, -/turf/open/floor/engine, -/area/ruin/space/has_grav/crashedship/midship) "EW" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible/layer2, @@ -2205,7 +2207,7 @@ Jv gH fp uf -EO +et fp xa uz diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/dangerous_research.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/dangerous_research.dmm index b8737a3af21..e5d1078c71b 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/dangerous_research.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/dangerous_research.dmm @@ -300,6 +300,14 @@ /obj/effect/decal/cleanable/blood/gibs/robot_debris/up, /turf/open/floor/iron/white, /area/ruin/space/has_grav/dangerous_research/medical) +"ei" = ( +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/turf_decal/tile/purple/diagonal_edge, +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/turf/open/floor/iron/diagonal, +/area/ruin/space/has_grav/dangerous_research) "eq" = ( /obj/effect/turf_decal/tile/purple/anticorner/contrasted{ dir = 4 @@ -3199,12 +3207,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark/diagonal, /area/ruin/space/has_grav/dangerous_research/dorms) -"PL" = ( -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/tile/purple/diagonal_edge, -/obj/machinery/suit_storage_unit/standard_unit, -/turf/open/floor/iron/diagonal, -/area/ruin/space/has_grav/dangerous_research) "PM" = ( /obj/item/stack/rods/ten, /obj/effect/decal/cleanable/blood/bubblegum, @@ -4650,7 +4652,7 @@ Hq Hq RD pk -PL +ei ax Cq Bq diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/deepstorage.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/deepstorage.dmm index c65a6f3d683..faa21fddb37 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/deepstorage.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/deepstorage.dmm @@ -989,11 +989,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible, /turf/open/floor/iron, /area/ruin/space/has_grav/deepstorage/power) -"fo" = ( -/obj/machinery/suit_storage_unit/standard_unit, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/ruin/space/has_grav/deepstorage/power) "fp" = ( /turf/closed/wall/mineral/iron, /area/ruin/space/has_grav/deepstorage/power) @@ -1699,6 +1694,13 @@ /obj/item/storage/box/drinkingglasses, /turf/open/floor/iron/cafeteria, /area/ruin/space/has_grav/deepstorage/kitchen) +"ty" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron, +/area/ruin/space/has_grav/deepstorage/power) "tG" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable, @@ -4414,7 +4416,7 @@ pq ev xY fb -fo +ty fA fJ gb diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/forgottenship.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/forgottenship.dmm index af406d83afb..bbb32320954 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/forgottenship.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/forgottenship.dmm @@ -127,6 +127,13 @@ /obj/structure/cable, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/syndicate_forgotten_ship) +"aA" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/syndicate; + storage_type = /obj/item/tank/jetpack/oxygen/harness + }, +/turf/open/floor/mineral/plastitanium, +/area/ruin/space/has_grav/syndicate_forgotten_ship) "aB" = ( /obj/structure/chair/comfy/black, /turf/open/floor/carpet/royalblack, @@ -434,13 +441,6 @@ "bI" = ( /turf/open/floor/iron/dark, /area/ruin/space/has_grav/syndicate_forgotten_ship) -"bJ" = ( -/obj/machinery/suit_storage_unit/syndicate{ - helmet_type = /obj/item/clothing/head/helmet/space/syndicate/black; - suit_type = /obj/item/clothing/suit/space/syndicate/black - }, -/turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/syndicate_forgotten_ship) "bL" = ( /obj/structure/tank_dispenser/oxygen, /turf/open/floor/mineral/plastitanium, @@ -1030,19 +1030,19 @@ /obj/effect/spawner/random/contraband/armory, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/syndicate_forgotten_ship) +"ly" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/syndicate; + storage_type = /obj/item/tank/jetpack/oxygen/harness + }, +/obj/machinery/light/small/directional/south, +/turf/open/floor/mineral/plastitanium, +/area/ruin/space/has_grav/syndicate_forgotten_ship) "lQ" = ( /obj/machinery/ore_silo, /obj/machinery/light/directional/west, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/syndicate_forgotten_cargopod) -"ml" = ( -/obj/machinery/suit_storage_unit/syndicate{ - helmet_type = /obj/item/clothing/head/helmet/space/syndicate/black; - suit_type = /obj/item/clothing/suit/space/syndicate/black - }, -/obj/machinery/light/small/directional/south, -/turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/syndicate_forgotten_ship) "mm" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -1198,6 +1198,13 @@ /obj/machinery/light/small/directional/north, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/syndicate_forgotten_ship) +"PW" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/syndicate; + storage_type = /obj/item/tank/jetpack/oxygen/harness + }, +/turf/open/floor/mineral/plastitanium, +/area/ruin/space/has_grav/syndicate_forgotten_ship) "VF" = ( /obj/structure/table/reinforced, /obj/machinery/button/door{ @@ -2366,7 +2373,7 @@ aP al bZ al -bJ +PW bZ aa aa @@ -2413,7 +2420,7 @@ aP al bZ al -ml +ly bZ aa aa @@ -2507,7 +2514,7 @@ aL al an al -bJ +aA bZ aa aa diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm index 635181d4256..121c927b843 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/hilbertresearchfacility.dmm @@ -48,6 +48,15 @@ "az" = ( /turf/open/floor/carpet/black, /area/ruin/space/has_grav/powered/hilbertresearchfacility) +"aN" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/obj/effect/turf_decal/stripes/end{ + dir = 1 + }, +/turf/open/floor/mineral/plastitanium, +/area/ruin/space/has_grav/powered/hilbertresearchfacility) "ba" = ( /obj/structure/table/wood, /obj/item/plate, @@ -471,13 +480,6 @@ }, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/hilbertresearchfacility) -"lL" = ( -/obj/machinery/suit_storage_unit/standard_unit, -/obj/effect/turf_decal/stripes/end{ - dir = 1 - }, -/turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/powered/hilbertresearchfacility) "lY" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/mineral/titanium/tiled/purple, @@ -3088,7 +3090,7 @@ PG Bo wG ko -lL +aN Ej rE Gl diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/meatderelict.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/meatderelict.dmm index 633f77b9b30..e40e2a219b5 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/meatderelict.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/meatderelict.dmm @@ -356,6 +356,14 @@ /obj/structure/sign/warning, /turf/closed/indestructible/reinforced, /area/ruin/space/has_grav/powered/biooutpost/vault) +"hS" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath; + storage_type = /obj/item/tank/internals/oxygen + }, +/obj/machinery/light/small/dim/directional/south, +/turf/open/floor/plating, +/area/ruin/space/has_grav/powered/biooutpost) "hW" = ( /obj/effect/turf_decal/siding/purple, /obj/effect/decal/cleanable/blood/splatter, @@ -1083,11 +1091,6 @@ /obj/effect/decal/cleanable/blood/tracks, /turf/open/floor/plating, /area/ruin/space/has_grav/powered/biooutpost) -"us" = ( -/obj/machinery/suit_storage_unit/spaceruin, -/obj/machinery/light/small/dim/directional/south, -/turf/open/floor/plating, -/area/ruin/space/has_grav/powered/biooutpost) "uC" = ( /obj/effect/decal/cleanable/blood/tracks, /turf/open/indestructible/white, @@ -3550,7 +3553,7 @@ YD lm mU Jh -us +hS ij cQ tS diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/mimesvsclowns.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/mimesvsclowns.dmm index 666c323065d..f05fe768d35 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/mimesvsclowns.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/mimesvsclowns.dmm @@ -47,6 +47,12 @@ /obj/structure/tank_dispenser, /turf/open/floor/iron/checker/airless, /area/ruin) +"kC" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/turf/open/floor/iron/checker/airless, +/area/ruin) "lS" = ( /obj/structure/door_assembly, /turf/open/floor/iron/checker/airless, @@ -103,10 +109,6 @@ /obj/effect/decal/cleanable/blood/gibs/core, /turf/open/floor/iron/checker/airless, /area/ruin) -"vj" = ( -/obj/machinery/suit_storage_unit/standard_unit, -/turf/open/floor/iron/checker/airless, -/area/ruin) "vs" = ( /obj/structure/table, /obj/item/reagent_containers/cup/glass/bottle/bottleofnothing, @@ -526,7 +528,7 @@ Qb Pq Ln aa -vj +kC gZ gZ gZ diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/old_infiltrator.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/old_infiltrator.dmm index 93ac362b2cc..c3a1d24b52c 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/old_infiltrator.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/old_infiltrator.dmm @@ -238,11 +238,6 @@ }, /turf/open/floor/mineral/plastitanium/red/airless, /area/ruin/space/unpowered) -"pv" = ( -/obj/effect/turf_decal/bot_red, -/obj/machinery/suit_storage_unit/nuke_med, -/turf/open/floor/iron/dark/airless, -/area/ruin/space/unpowered) "qL" = ( /obj/machinery/door/window/brigdoor/left/directional/west{ req_access = list("syndicate"); @@ -424,6 +419,11 @@ }, /turf/open/floor/mineral/plastitanium/red/airless, /area/ruin/space/unpowered) +"Cj" = ( +/obj/effect/turf_decal/bot_red, +/obj/machinery/suit_storage_unit/ruin_zone, +/turf/open/floor/iron/dark/airless, +/area/ruin/space/unpowered) "Cv" = ( /obj/item/ammo_casing/c357/match, /turf/open/floor/mineral/plastitanium/red, @@ -942,7 +942,7 @@ la Da LP Nv -pv +Cj Pq uE vK diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/oldstation.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/oldstation.dmm index 67f30c57b23..a716f9f73c9 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/oldstation.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/oldstation.dmm @@ -68,6 +68,16 @@ /obj/effect/zone_mobs/bug/boss, /turf/open/floor/engine/airless, /area/ruin/space/ancientstation/beta/supermatter) +"an" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/suit_storage_unit/ruin_zone{ + storage_type = /obj/item/tank/internals/oxygen/yellow + }, +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ + dir = 4 + }, +/turf/open/floor/iron, +/area/ruin/space/ancientstation/charlie/engie) "ao" = ( /obj/structure/alien/weeds, /mob/living/basic/alien/drone, @@ -803,6 +813,18 @@ }, /turf/open/floor/iron/airless, /area/ruin/space/ancientstation/beta/medbay) +"dG" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/suit_storage_unit/ruin_zone{ + storage_type = /obj/item/tank/jetpack/void + }, +/obj/effect/turf_decal/tile/brown/half/contrasted{ + dir = 8 + }, +/obj/machinery/airalarm/directional/west, +/obj/effect/mapping_helpers/airalarm/away_general_access, +/turf/open/floor/iron, +/area/ruin/space/ancientstation/beta/mining) "dH" = ( /obj/structure/lattice/catwalk, /turf/template_noop, @@ -2645,14 +2667,6 @@ /obj/item/shard/plasma, /turf/open/floor/engine/airless, /area/ruin/space/ancientstation/beta/supermatter) -"lJ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/suit_storage_unit/void_old, -/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ - dir = 4 - }, -/turf/open/floor/iron, -/area/ruin/space/ancientstation/charlie/engie) "lO" = ( /obj/machinery/door/poddoor{ id = "proto" @@ -4039,16 +4053,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/ruin/space/ancientstation/charlie/hall) -"ur" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/suit_storage_unit/void_old/jetpack, -/obj/effect/turf_decal/tile/brown/half/contrasted{ - dir = 8 - }, -/obj/machinery/airalarm/directional/west, -/obj/effect/mapping_helpers/airalarm/away_general_access, -/turf/open/floor/iron, -/area/ruin/space/ancientstation/beta/mining) "uv" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -11113,7 +11117,7 @@ aa Hf jV ci -ur +dG pP WI mW @@ -12043,7 +12047,7 @@ jE zJ mY kQ -lJ +an oP en zZ diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/rare_blacksite.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/rare_blacksite.dmm index c179511f69b..54413aeba60 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/rare_blacksite.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/rare_blacksite.dmm @@ -277,6 +277,20 @@ }, /turf/open/floor/plating, /area/ruin/space/has_grav/powered) +"ba" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/syndicate; + storage_type = /obj/item/tank/jetpack/oxygen/harness + }, +/turf/open/floor/mineral/plastitanium, +/area/ruin/space/has_grav/powered) +"bb" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/syndicate; + storage_type = /obj/item/tank/jetpack/oxygen/harness + }, +/turf/open/floor/mineral/plastitanium, +/area/ruin/space/has_grav/powered) "bo" = ( /obj/machinery/light/small/red/directional/south, /turf/open/floor/iron/dark, @@ -628,6 +642,13 @@ }, /turf/open/floor/plating, /area/ruin/space/has_grav/powered) +"KR" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/syndicate; + storage_type = /obj/item/tank/jetpack/oxygen/harness + }, +/turf/open/floor/mineral/plastitanium, +/area/ruin/space/has_grav/powered) "KV" = ( /obj/effect/spawner/random/maintenance, /turf/open/floor/plating, @@ -702,10 +723,6 @@ }, /turf/open/floor/carpet, /area/ruin/space/has_grav/powered) -"ST" = ( -/obj/machinery/suit_storage_unit/syndicate, -/turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/powered) "TB" = ( /obj/structure/rack, /obj/item/target{ @@ -1107,7 +1124,7 @@ aE aP aF aE -ST +KR Bc FE ov @@ -1135,7 +1152,7 @@ ag ax ae aE -ST +ba Bc cy ap @@ -1478,7 +1495,7 @@ aS ap BR ap -ST +bb ap ah aC diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/thelizardsgas.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/thelizardsgas.dmm index 5a667e2bcf3..08982a5378f 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/thelizardsgas.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/thelizardsgas.dmm @@ -399,14 +399,6 @@ "LA" = ( /turf/closed/wall/r_wall, /area/ruin/space/has_grav/thelizardsgas) -"LT" = ( -/obj/structure/sign/warning/electric_shock/directional/north, -/obj/machinery/suit_storage_unit/standard_unit, -/obj/machinery/power/terminal{ - dir = 4 - }, -/turf/open/floor/plating, -/area/ruin/space/has_grav/thelizardsgas) "MB" = ( /obj/structure/lattice/catwalk, /obj/machinery/atmospherics/pipe/smart/simple/yellow/hidden{ @@ -513,6 +505,16 @@ }, /turf/open/floor/plating, /area/ruin/space/has_grav/thelizardsgas) +"VL" = ( +/obj/structure/sign/warning/electric_shock/directional/north, +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/obj/machinery/power/terminal{ + dir = 4 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/thelizardsgas) "VP" = ( /obj/structure/table/reinforced, /obj/item/gps/spaceruin, @@ -948,7 +950,7 @@ CA CA Qg mR -LT +VL xy Kw mR diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/vestige_comb.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/vestige_comb.dmm index e0b55189297..ea230518cc3 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/vestige_comb.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/vestige_comb.dmm @@ -284,6 +284,12 @@ /obj/structure/sign/warning/vacuum, /turf/closed/wall, /area/ruin/space/has_grav/vestige/comb) +"ba" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/explorer + }, +/turf/open/floor/plating/airless, +/area/ruin/space/has_grav/vestige/comb) "bp" = ( /obj/structure/table, /obj/item/storage/toolbox/mechanical{ @@ -620,6 +626,12 @@ }, /turf/open/floor/plating/airless, /area/ruin/space/has_grav/vestige/comb) +"TJ" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/explorer + }, +/turf/open/floor/plating/airless, +/area/ruin/space/has_grav/vestige/comb) "Va" = ( /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/plating/airless, @@ -665,10 +677,6 @@ /obj/effect/decal/cleanable/shreds, /turf/open/floor/iron, /area/ruin/space/has_grav/vestige/comb) -"YC" = ( -/obj/machinery/suit_storage_unit/mining, -/turf/open/floor/plating/airless, -/area/ruin/space/has_grav/vestige/comb) "Zl" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -1046,8 +1054,8 @@ aV ae Va ar -YC -YC +ba +TJ fo Bx Va diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/waystation.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/waystation.dmm index 1eced19e892..c09c221baa5 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/waystation.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/waystation.dmm @@ -38,6 +38,14 @@ /obj/effect/mapping_helpers/airlock/access/all/away/security, /turf/open/floor/iron/dark, /area/ruin/space/has_grav/waystation/securestorage) +"aQ" = ( +/obj/effect/turf_decal/bot, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/waystation) "be" = ( /obj/structure/toilet{ dir = 8 @@ -2906,12 +2914,6 @@ /obj/item/multitool, /turf/open/floor/plating, /area/ruin/space/has_grav/waystation/power) -"YD" = ( -/obj/effect/turf_decal/bot, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/suit_storage_unit/standard_unit, -/turf/open/floor/plating, -/area/ruin/space/has_grav/waystation) "YX" = ( /obj/effect/turf_decal/tile/brown/half/contrasted{ dir = 8 @@ -4278,7 +4280,7 @@ dm QN QN TT -YD +aQ ym bN TT diff --git a/_maps/voidcrew/RandomRuins/SpaceRuins/whiteshipruin_box.dmm b/_maps/voidcrew/RandomRuins/SpaceRuins/whiteshipruin_box.dmm index f85380196da..57bcb478fcb 100644 --- a/_maps/voidcrew/RandomRuins/SpaceRuins/whiteshipruin_box.dmm +++ b/_maps/voidcrew/RandomRuins/SpaceRuins/whiteshipruin_box.dmm @@ -1,4 +1,16 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"ab" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/turf/open/floor/mineral/titanium/tiled/white, +/area/ruin/space/has_grav/whiteship/box) +"ac" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/turf/open/floor/mineral/titanium/tiled/white, +/area/ruin/space/has_grav/whiteship/box) "ag" = ( /obj/machinery/power/shuttle_engine/huge{ dir = 8; @@ -42,10 +54,6 @@ /obj/structure/extinguisher_cabinet/directional/west, /turf/open/floor/carpet, /area/ruin/space/has_grav/whiteship/box) -"bN" = ( -/obj/machinery/suit_storage_unit/mining/eva, -/turf/open/floor/mineral/titanium/tiled/white, -/area/ruin/space/has_grav/whiteship/box) "bT" = ( /obj/effect/turf_decal/trimline/yellow/arrow_ccw{ dir = 1 @@ -958,6 +966,12 @@ /obj/machinery/atmospherics/components/unary/portables_connector/visible, /turf/open/floor/engine, /area/ruin/space/has_grav/whiteship/box) +"Ez" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/turf/open/floor/mineral/titanium/tiled/white, +/area/ruin/space/has_grav/whiteship/box) "EA" = ( /obj/effect/decal/cleanable/glass, /obj/structure/lattice, @@ -1044,10 +1058,6 @@ "HR" = ( /turf/closed/wall/mineral/titanium/nodiagonal, /area/ruin/space/has_grav/whiteship/box) -"HT" = ( -/obj/machinery/suit_storage_unit/standard_unit, -/turf/open/floor/mineral/titanium/tiled/white, -/area/ruin/space/has_grav/whiteship/box) "HW" = ( /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 1 @@ -2061,7 +2071,7 @@ HR Dl Ay HR -bN +Ez IA Ud kX @@ -2083,7 +2093,7 @@ kK Ay Xk HR -HT +ab IA Qx Gp @@ -2105,7 +2115,7 @@ kK sX kd HR -HT +ac IA Qx BG diff --git a/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_crash_cult.dmm b/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_crash_cult.dmm index 045d859678a..fa5c5788d25 100644 --- a/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_crash_cult.dmm +++ b/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_crash_cult.dmm @@ -117,6 +117,24 @@ }, /turf/open/floor/plating, /area/ruin/unpowered) +"dC" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/atmos; + storage_type = /obj/item/watertank/atmos + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/turf_decal/tile/brown/anticorner{ + dir = 8 + }, +/obj/effect/turf_decal/tile/brown/anticorner{ + dir = 1 + }, +/obj/effect/turf_decal/tile/brown/anticorner{ + dir = 4 + }, +/obj/effect/turf_decal/tile/brown/anticorner, +/turf/open/floor/plating, +/area/ruin/unpowered) "ej" = ( /obj/effect/decal/cleanable/dirt/dust, /obj/effect/turf_decal/tile/green{ @@ -803,21 +821,6 @@ /obj/machinery/atmospherics/components/unary/vent_pump, /turf/open/floor/plating, /area/ruin/unpowered) -"BC" = ( -/obj/machinery/suit_storage_unit/atmos, -/obj/effect/decal/cleanable/dirt/dust, -/obj/effect/turf_decal/tile/brown/anticorner{ - dir = 8 - }, -/obj/effect/turf_decal/tile/brown/anticorner{ - dir = 1 - }, -/obj/effect/turf_decal/tile/brown/anticorner{ - dir = 4 - }, -/obj/effect/turf_decal/tile/brown/anticorner, -/turf/open/floor/plating, -/area/ruin/unpowered) "BV" = ( /obj/effect/decal/cleanable/blood, /obj/effect/decal/cleanable/blood/gibs/body, @@ -1054,20 +1057,6 @@ }, /turf/open/floor/cult, /area/ruin/unpowered) -"IU" = ( -/obj/machinery/suit_storage_unit/atmos, -/obj/effect/turf_decal/tile/brown/anticorner{ - dir = 8 - }, -/obj/effect/turf_decal/tile/brown/anticorner{ - dir = 1 - }, -/obj/effect/turf_decal/tile/brown/anticorner{ - dir = 4 - }, -/obj/effect/turf_decal/tile/brown/anticorner, -/turf/open/floor/cult, -/area/ruin/unpowered) "Jh" = ( /turf/open/floor/cult, /area/ruin/unpowered) @@ -1363,6 +1352,23 @@ /obj/effect/decal/cleanable/blood, /turf/open/floor/plating, /area/ruin/unpowered) +"XS" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/atmos; + storage_type = /obj/item/watertank/atmos + }, +/obj/effect/turf_decal/tile/brown/anticorner{ + dir = 8 + }, +/obj/effect/turf_decal/tile/brown/anticorner{ + dir = 1 + }, +/obj/effect/turf_decal/tile/brown/anticorner{ + dir = 4 + }, +/obj/effect/turf_decal/tile/brown/anticorner, +/turf/open/floor/cult, +/area/ruin/unpowered) "XV" = ( /obj/machinery/atmospherics/pipe/smart/simple/supply/hidden, /obj/effect/decal/cleanable/dirt/dust, @@ -1662,7 +1668,7 @@ xD "} (14,1,1) = {" xD -IU +XS II mx qS @@ -1742,7 +1748,7 @@ nv "} (18,1,1) = {" Nt -BC +dC my Fe cD diff --git a/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_miningexpedition.dmm b/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_miningexpedition.dmm index e3f2f954f84..3120e6a09ad 100644 --- a/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_miningexpedition.dmm +++ b/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_miningexpedition.dmm @@ -1,4 +1,16 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/explorer + }, +/turf/open/floor/iron/smooth_large, +/area/ruin/unpowered) +"jC" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/explorer + }, +/turf/open/floor/iron/smooth_large, +/area/ruin/unpowered) "AA" = ( /obj/structure/closet/crate/zone_loot/expedition, /turf/open/floor/iron/smooth_half{ @@ -118,10 +130,6 @@ }, /turf/open/floor/iron/smooth_large, /area/ruin/unpowered) -"ug" = ( -/obj/machinery/suit_storage_unit/mining, -/turf/open/floor/iron/smooth_large, -/area/ruin/unpowered) "uq" = ( /obj/machinery/suit_storage_unit/open, /turf/open/floor/iron/smooth_large, @@ -408,9 +416,9 @@ mk mk LZ Vw -ug +aa uq -ug +jC rr Wv oj diff --git a/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_moth.dmm b/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_moth.dmm index e94537a4b44..0face58bec0 100644 --- a/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_moth.dmm +++ b/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_moth.dmm @@ -89,10 +89,6 @@ /obj/item/storage/toolbox/electrical, /turf/open/floor/iron, /area/ruin/unpowered) -"w" = ( -/obj/machinery/suit_storage_unit/mining/eva, -/turf/open/floor/plating/rust, -/area/ruin/unpowered) "x" = ( /obj/machinery/computer/order_console/mining, /turf/open/floor/iron, @@ -125,6 +121,12 @@ /obj/item/stack/sheet/mineral/plasma, /turf/open/floor/plating/rust, /area/ruin/unpowered) +"E" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/turf/open/floor/plating/rust, +/area/ruin/unpowered) "F" = ( /turf/closed/wall/rust, /area/ruin/unpowered) @@ -145,6 +147,12 @@ /obj/structure/cable, /turf/open/floor/iron, /area/ruin/unpowered) +"J" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/turf/open/floor/plating/rust, +/area/ruin/unpowered) "K" = ( /obj/machinery/door/airlock, /turf/open/floor/iron, @@ -160,6 +168,15 @@ }, /turf/open/floor/plating/rust, /area/overmap_encounter/planetoid/wasteland) +"N" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/turf/open/floor/iron, +/area/ruin/unpowered) "O" = ( /obj/effect/turf_decal/caution{ dir = 1 @@ -172,13 +189,6 @@ }, /turf/open/floor/iron, /area/ruin/unpowered) -"Q" = ( -/obj/machinery/light/small{ - dir = 4 - }, -/obj/machinery/suit_storage_unit/mining/eva, -/turf/open/floor/iron, -/area/ruin/unpowered) "R" = ( /obj/structure/girder/displaced, /turf/open/floor/plating/rust, @@ -385,7 +395,7 @@ t s s l -w +E F "} (13,1,1) = {" @@ -398,7 +408,7 @@ v l l t -w +J F "} (14,1,1) = {" @@ -411,7 +421,7 @@ L L l l -Q +N F "} (15,1,1) = {" diff --git a/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_surface_starfurycrash.dmm b/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_surface_starfurycrash.dmm index 89d949b1623..f7a8d0b333d 100644 --- a/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_surface_starfurycrash.dmm +++ b/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_surface_starfurycrash.dmm @@ -130,13 +130,6 @@ }, /turf/open/floor/engine, /area/ruin/unpowered) -"rp" = ( -/obj/machinery/suit_storage_unit{ - mask_type = /obj/item/clothing/mask/gas/syndicate; - suit_type = /obj/item/clothing/suit/space/syndicate - }, -/turf/open/floor/plating, -/area/ruin/unpowered) "rE" = ( /obj/machinery/power/smes, /turf/open/floor/plating, @@ -158,6 +151,12 @@ /obj/machinery/portable_atmospherics/canister/oxygen, /turf/open/floor/plating, /area/ruin/unpowered) +"xD" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/syndicate + }, +/turf/open/floor/mineral/plastitanium/red, +/area/ruin/unpowered) "yj" = ( /obj/machinery/door/airlock/hatch, /turf/open/floor/iron/dark, @@ -287,6 +286,12 @@ "Sx" = ( /turf/open/misc/wasteland/lit, /area/ruin/unpowered) +"SQ" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/gas/syndicate + }, +/turf/open/floor/plating, +/area/ruin/unpowered) "Ts" = ( /obj/effect/decal/cleanable/ash, /obj/effect/decal/cleanable/ash{ @@ -336,14 +341,6 @@ /obj/machinery/portable_atmospherics/scrubber, /turf/open/misc/wasteland/lit, /area/overmap_encounter/planetoid/wasteland) -"ZX" = ( -/obj/machinery/suit_storage_unit{ - helmet_type = /obj/item/clothing/head/helmet/space/syndicate; - mask_type = /obj/item/clothing/mask/gas/syndicate; - suit_type = /obj/item/clothing/suit/armor/vest - }, -/turf/open/floor/mineral/plastitanium/red, -/area/ruin/unpowered) (1,1,1) = {" RJ @@ -705,8 +702,8 @@ RJ RJ af kZ -ZX -rp +xD +SQ fw CM CM diff --git a/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_tradepost.dmm b/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_tradepost.dmm index 7ba3e1c1ce7..947418f7dec 100644 --- a/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_tradepost.dmm +++ b/_maps/voidcrew/RandomRuins/WastelandRuins/wasteland_tradepost.dmm @@ -34,12 +34,6 @@ /obj/effect/decal/cleanable/cobweb, /turf/open/floor/plating/rust, /area/ruin/unpowered) -"gy" = ( -/obj/machinery/suit_storage_unit/mining/eva, -/obj/effect/decal/cleanable/cobweb, -/obj/effect/decal/cleanable/dirt/dust, -/turf/open/floor/plating/rust, -/area/ruin/unpowered) "gA" = ( /obj/effect/decal/cleanable/glass, /turf/open/misc/wasteland/lit, @@ -56,6 +50,14 @@ /obj/structure/statue/sandstone/assistant, /turf/open/misc/wasteland/lit, /area/overmap_encounter/planetoid/wasteland) +"ke" = ( +/obj/machinery/suit_storage_unit/ruin_zone{ + mask_type = /obj/item/clothing/mask/breath + }, +/obj/effect/decal/cleanable/cobweb, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating/rust, +/area/ruin/unpowered) "kf" = ( /obj/structure/ore_box, /obj/effect/decal/cleanable/dirt/dust, @@ -573,7 +575,7 @@ De "} (11,1,1) = {" Ue -gy +ke Sn RE en diff --git a/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_pink.dmm b/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_pink.dmm index eeb5a5d0194..834d1216b51 100644 --- a/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_pink.dmm +++ b/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_pink.dmm @@ -1,4 +1,13 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"bkb" = ( +/obj/structure/displaycase/captain{ + start_showpiece_type = null + }, +/obj/structure/plaque/static_plaque/golden/captain{ + pixel_y = 29 + }, +/turf/open/floor/wood/mahogany, +/area/template_noop) "buH" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/machinery/computer/bank_machine{ @@ -93,15 +102,6 @@ /obj/modular_map_connector, /turf/open/floor/iron/dollhouse, /area/template_noop) -"xfu" = ( -/obj/structure/displaycase/captain{ - start_showpiece_type = /obj/item/katana - }, -/obj/structure/plaque/static_plaque/golden/captain{ - pixel_y = 29 - }, -/turf/open/floor/wood/mahogany, -/area/template_noop) (1,1,1) = {" sJk @@ -132,7 +132,7 @@ uhQ "} (4,1,1) = {" nXX -xfu +bkb vTp ssU buH diff --git a/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_standard.dmm b/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_standard.dmm index 3df857dc0f3..4b5bb715fe3 100644 --- a/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_standard.dmm +++ b/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_standard.dmm @@ -1,4 +1,13 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"dfb" = ( +/obj/structure/displaycase/captain{ + start_showpiece_type = null + }, +/obj/structure/plaque/static_plaque/golden/captain{ + pixel_y = 29 + }, +/turf/open/floor/wood, +/area/template_noop) "drI" = ( /obj/structure/chair/comfy/shuttle{ dir = 4 @@ -20,15 +29,6 @@ }, /turf/open/floor/carpet/blue, /area/template_noop) -"qNH" = ( -/obj/structure/displaycase/captain{ - start_showpiece_type = /obj/item/katana - }, -/obj/structure/plaque/static_plaque/golden/captain{ - pixel_y = 29 - }, -/turf/open/floor/wood, -/area/template_noop) "rbk" = ( /obj/structure/window/reinforced/spawner/directional/north, /obj/structure/closet/secure_closet/captains, @@ -129,7 +129,7 @@ sxf "} (4,1,1) = {" yjK -qNH +dfb vmU vbd rDl diff --git a/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_syndicate.dmm b/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_syndicate.dmm index 37333836bf6..5d5bbb10639 100644 --- a/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_syndicate.dmm +++ b/_maps/voidcrew/ship_modules/hiryu_class_carrier/captain_s_quarters_syndicate.dmm @@ -5,9 +5,9 @@ /obj/item/folder/syndicate/red, /turf/open/floor/wood/ebony, /area/template_noop) -"hOd" = ( +"hVg" = ( /obj/structure/displaycase/captain{ - start_showpiece_type = /obj/item/katana + start_showpiece_type = null }, /obj/structure/plaque/static_plaque/golden/captain{ pixel_y = 29 @@ -129,7 +129,7 @@ nTz "} (4,1,1) = {" oFg -hOd +hVg xNq vEi pFb diff --git a/_maps/voidcrew/ship_modules/squab/security_director.dmm b/_maps/voidcrew/ship_modules/squab/security_director.dmm index 0da9297583d..eaff7af533f 100644 --- a/_maps/voidcrew/ship_modules/squab/security_director.dmm +++ b/_maps/voidcrew/ship_modules/squab/security_director.dmm @@ -1,4 +1,18 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aGd" = ( +/obj/effect/turf_decal/siding/thinplating/dark{ + dir = 4; + layer = 2.5 + }, +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 8 + }, +/obj/machinery/suit_storage_unit/base_tier{ + mask_type = /obj/item/clothing/mask/gas/sechailer; + storage_type = /obj/item/tank/internals/oxygen + }, +/turf/template_noop, +/area/template_noop) "aRZ" = ( /obj/effect/turf_decal/siding/wood, /obj/effect/turf_decal/siding/wood{ @@ -17,17 +31,6 @@ }, /turf/template_noop, /area/template_noop) -"mdF" = ( -/obj/effect/turf_decal/siding/thinplating/dark{ - dir = 4; - layer = 2.5 - }, -/obj/effect/turf_decal/siding/wideplating_new/dark{ - dir = 8 - }, -/obj/machinery/suit_storage_unit/hos, -/turf/template_noop, -/area/template_noop) "ods" = ( /obj/effect/turf_decal/siding/wood{ color = "#543C30"; @@ -80,7 +83,7 @@ /area/template_noop) (1,1,1) = {" -mdF +aGd tJR "} (2,1,1) = {" diff --git a/_maps/voidcrew/ships/ship_nano_phalanx_a.dmm b/_maps/voidcrew/ships/ship_nano_phalanx_a.dmm index 8bcd7b532f8..4b8f13635c6 100644 --- a/_maps/voidcrew/ships/ship_nano_phalanx_a.dmm +++ b/_maps/voidcrew/ships/ship_nano_phalanx_a.dmm @@ -225,6 +225,19 @@ }, /turf/open/floor/iron, /area/shuttle/voidcrew/phalanx/hallway/aft/a) +"ep" = ( +/obj/structure/closet/secure_closet/personal/cabinet, +/obj/item/soulstone/anybody/chaplain, +/obj/effect/spawner/random/modsuit/base_tier, +/obj/item/book/granter/action/spell/smoke/lesser, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 4 + }, +/obj/structure/sign/poster/official/bless_this_spess{ + pixel_y = 32 + }, +/turf/open/floor/carpet/black, +/area/shuttle/voidcrew/phalanx/chapel/office/a) "ew" = ( /obj/item/kirbyplants/random, /obj/machinery/light/small{ @@ -2779,19 +2792,6 @@ /obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/nitrogen_output, /turf/open/floor/engine/n2, /area/shuttle/voidcrew/phalanx/engineering/atmospherics/a) -"Os" = ( -/obj/structure/closet/secure_closet/personal/cabinet, -/obj/item/soulstone/anybody/chaplain, -/obj/item/mod/control/pre_equipped/responsory/inquisitory, -/obj/item/book/granter/action/spell/smoke/lesser, -/obj/effect/turf_decal/siding/wood/corner{ - dir = 4 - }, -/obj/structure/sign/poster/official/bless_this_spess{ - pixel_y = 32 - }, -/turf/open/floor/carpet/black, -/area/shuttle/voidcrew/phalanx/chapel/office/a) "Ov" = ( /turf/closed/wall/mineral/titanium/nodiagonal, /area/shuttle/voidcrew/phalanx/kitchen/a) @@ -2875,6 +2875,19 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/mineral/titanium/tiled/purple, /area/shuttle/voidcrew/phalanx/hallway/central/a) +"Py" = ( +/obj/machinery/suit_storage_unit/base_tier{ + mask_type = /obj/item/clothing/mask/gas/atmos/captain; + storage_type = /obj/item/tank/jetpack/oxygen/captain + }, +/obj/effect/turf_decal/siding/wood{ + dir = 2 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/wood, +/area/shuttle/voidcrew/phalanx/bridge/captain/a) "PA" = ( /obj/structure/rack, /obj/item/pickaxe, @@ -3177,16 +3190,6 @@ /obj/structure/table/wood, /turf/open/floor/iron, /area/shuttle/voidcrew/phalanx/cafeteria/a) -"TS" = ( -/obj/machinery/suit_storage_unit/captain, -/obj/effect/turf_decal/siding/wood{ - dir = 2 - }, -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/turf/open/floor/wood, -/area/shuttle/voidcrew/phalanx/bridge/captain/a) "TX" = ( /obj/machinery/atmospherics/components/binary/pump{ dir = 8; @@ -4648,7 +4651,7 @@ jK Pd jK CO -Os +ep xU Gh CO @@ -5084,7 +5087,7 @@ oZ YY LL Ta -TS +Py KT FQ lI diff --git a/_maps/voidcrew/ships/ship_nano_phalanx_b.dmm b/_maps/voidcrew/ships/ship_nano_phalanx_b.dmm index 0f6fa3dc275..3f24f2add33 100644 --- a/_maps/voidcrew/ships/ship_nano_phalanx_b.dmm +++ b/_maps/voidcrew/ships/ship_nano_phalanx_b.dmm @@ -935,6 +935,19 @@ }, /turf/open/floor/iron, /area/shuttle/voidcrew/phalanx/cargo/mining/b) +"jo" = ( +/obj/machinery/suit_storage_unit/base_tier{ + mask_type = /obj/item/clothing/mask/gas/atmos/captain; + storage_type = /obj/item/tank/jetpack/oxygen/captain + }, +/obj/effect/turf_decal/siding/wood{ + dir = 2 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/wood, +/area/shuttle/voidcrew/phalanx/bridge/captain/b) "jp" = ( /obj/item/kirbyplants/random, /obj/effect/turf_decal/siding/wood{ @@ -3009,19 +3022,6 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/shuttle/voidcrew/phalanx/security/b) -"Jj" = ( -/obj/structure/closet/secure_closet/personal/cabinet, -/obj/item/soulstone/anybody/chaplain, -/obj/item/mod/control/pre_equipped/responsory/inquisitory, -/obj/item/book/granter/action/spell/smoke/lesser, -/obj/effect/turf_decal/siding/wood/corner{ - dir = 4 - }, -/obj/structure/sign/poster/official/bless_this_spess{ - pixel_y = 32 - }, -/turf/open/floor/wood, -/area/shuttle/voidcrew/phalanx/chapel/office/b) "Jm" = ( /obj/machinery/light{ dir = 8 @@ -3634,16 +3634,6 @@ }, /turf/open/floor/wood/large, /area/shuttle/voidcrew/phalanx/hallway/aft/b) -"QQ" = ( -/obj/machinery/suit_storage_unit/captain, -/obj/effect/turf_decal/siding/wood{ - dir = 2 - }, -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/turf/open/floor/wood, -/area/shuttle/voidcrew/phalanx/bridge/captain/b) "QT" = ( /obj/structure/sign/poster/official/twelve_gauge{ pixel_y = 32 @@ -4135,6 +4125,19 @@ /obj/structure/sign/nanotrasen, /turf/closed/wall/mineral/titanium, /area/shuttle/voidcrew/phalanx/cargo/mining/b) +"XO" = ( +/obj/structure/closet/secure_closet/personal/cabinet, +/obj/item/soulstone/anybody/chaplain, +/obj/effect/spawner/random/modsuit/base_tier, +/obj/item/book/granter/action/spell/smoke/lesser, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 4 + }, +/obj/structure/sign/poster/official/bless_this_spess{ + pixel_y = 32 + }, +/turf/open/floor/wood, +/area/shuttle/voidcrew/phalanx/chapel/office/b) "XT" = ( /obj/machinery/light{ dir = 4 @@ -5430,7 +5433,7 @@ qZ HL qZ Qm -Jj +XO FI CE Qm @@ -5866,7 +5869,7 @@ oZ iN BV el -QQ +jo zo Cm sc diff --git a/_maps/voidcrew/ships/ship_nano_phalanx_c.dmm b/_maps/voidcrew/ships/ship_nano_phalanx_c.dmm index b1e633d3858..4d33eb61c9f 100644 --- a/_maps/voidcrew/ships/ship_nano_phalanx_c.dmm +++ b/_maps/voidcrew/ships/ship_nano_phalanx_c.dmm @@ -2061,6 +2061,25 @@ /obj/structure/cable, /turf/open/floor/iron, /area/shuttle/voidcrew/phalanx/kitchen/c) +"Ay" = ( +/obj/structure/closet/secure_closet/personal/cabinet, +/obj/item/soulstone/anybody/chaplain, +/obj/effect/spawner/random/modsuit/base_tier, +/obj/item/book/granter/action/spell/smoke/lesser, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 4 + }, +/obj/structure/sign/poster/official/bless_this_spess{ + pixel_y = 32 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/wood, +/area/shuttle/voidcrew/phalanx/chapel/office/c) "AC" = ( /obj/machinery/mass_driver{ id = "phalanx_massdriver" @@ -2704,6 +2723,19 @@ /obj/structure/cable, /turf/open/floor/grass, /area/shuttle/voidcrew/phalanx/chapel/c) +"IO" = ( +/obj/machinery/suit_storage_unit/base_tier{ + mask_type = /obj/item/clothing/mask/gas/atmos/captain; + storage_type = /obj/item/tank/jetpack/oxygen/captain + }, +/obj/effect/turf_decal/siding/wood{ + dir = 2 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/wood, +/area/shuttle/voidcrew/phalanx/bridge/captain/c) "IS" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -2896,16 +2928,6 @@ }, /turf/open/floor/wood, /area/shuttle/voidcrew/phalanx/cafeteria/c) -"Lc" = ( -/obj/machinery/suit_storage_unit/captain, -/obj/effect/turf_decal/siding/wood{ - dir = 2 - }, -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/turf/open/floor/wood, -/area/shuttle/voidcrew/phalanx/bridge/captain/c) "Le" = ( /obj/effect/spawner/structure/window/reinforced/shuttle, /turf/open/floor/plating, @@ -3613,25 +3635,6 @@ }, /turf/open/floor/iron, /area/shuttle/voidcrew/phalanx/hallway/aft/c) -"Ut" = ( -/obj/structure/closet/secure_closet/personal/cabinet, -/obj/item/soulstone/anybody/chaplain, -/obj/item/mod/control/pre_equipped/responsory/inquisitory, -/obj/item/book/granter/action/spell/smoke/lesser, -/obj/effect/turf_decal/siding/wood/corner{ - dir = 4 - }, -/obj/structure/sign/poster/official/bless_this_spess{ - pixel_y = 32 - }, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/turf/open/floor/wood, -/area/shuttle/voidcrew/phalanx/chapel/office/c) "UB" = ( /obj/structure/window/reinforced/tinted{ dir = 8 @@ -5151,7 +5154,7 @@ Sm RL Sm Og -Ut +Ay IY Vf Og @@ -5587,7 +5590,7 @@ oZ Ns Rb KW -Lc +IO EN RR Wn diff --git a/_maps/voidcrew/ships/ship_nano_phalanx_d.dmm b/_maps/voidcrew/ships/ship_nano_phalanx_d.dmm index c96bd1930f5..b824663f9d9 100644 --- a/_maps/voidcrew/ships/ship_nano_phalanx_d.dmm +++ b/_maps/voidcrew/ships/ship_nano_phalanx_d.dmm @@ -670,6 +670,19 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/mineral/titanium/blue, /area/shuttle/voidcrew/phalanx/medbay/storage/d) +"jn" = ( +/obj/machinery/suit_storage_unit/base_tier{ + mask_type = /obj/item/clothing/mask/gas/atmos/captain; + storage_type = /obj/item/tank/jetpack/oxygen/captain + }, +/obj/effect/turf_decal/siding/wood{ + dir = 2 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/wood, +/area/shuttle/voidcrew/phalanx/bridge/captain/d) "jt" = ( /turf/open/floor/plating, /area/shuttle/voidcrew/phalanx/engineering/d) @@ -789,6 +802,19 @@ }, /turf/open/floor/wood, /area/shuttle/voidcrew/phalanx/hallway/aft/d) +"lq" = ( +/obj/structure/closet/secure_closet/personal/cabinet, +/obj/item/soulstone/anybody/chaplain, +/obj/effect/spawner/random/modsuit/base_tier, +/obj/item/book/granter/action/spell/smoke/lesser, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 4 + }, +/obj/structure/sign/poster/official/bless_this_spess{ + pixel_y = 32 + }, +/turf/open/floor/bamboo/tatami, +/area/shuttle/voidcrew/phalanx/chapel/office/d) "lv" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible, /turf/open/floor/engine, @@ -819,16 +845,6 @@ }, /turf/open/floor/carpet/executive, /area/shuttle/voidcrew/phalanx/bridge/d) -"lI" = ( -/obj/machinery/suit_storage_unit/captain, -/obj/effect/turf_decal/siding/wood{ - dir = 2 - }, -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/turf/open/floor/wood, -/area/shuttle/voidcrew/phalanx/bridge/captain/d) "lJ" = ( /obj/structure/table/wood, /obj/item/flashlight/lantern/on{ @@ -2178,19 +2194,6 @@ /obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/wood/tile, /area/shuttle/voidcrew/phalanx/kitchen/d) -"Dm" = ( -/obj/structure/closet/secure_closet/personal/cabinet, -/obj/item/soulstone/anybody/chaplain, -/obj/item/mod/control/pre_equipped/responsory/inquisitory, -/obj/item/book/granter/action/spell/smoke/lesser, -/obj/effect/turf_decal/siding/wood/corner{ - dir = 4 - }, -/obj/structure/sign/poster/official/bless_this_spess{ - pixel_y = 32 - }, -/turf/open/floor/bamboo/tatami, -/area/shuttle/voidcrew/phalanx/chapel/office/d) "Do" = ( /obj/machinery/light/small/directional/east, /obj/structure/rack, @@ -5054,7 +5057,7 @@ lV Fv lV tL -Dm +lq RR pa tL @@ -5490,7 +5493,7 @@ oZ ka bz YQ -lI +jn Ub gM GD diff --git a/voidcrew/modules/ship_upgrades/previews/hiryu_class_carrier_captain_s_quarters_pink.png b/voidcrew/modules/ship_upgrades/previews/hiryu_class_carrier_captain_s_quarters_pink.png index 498c985ccd041e55d47564ac7f534369a49d6a7d..ce6930cb761c02e53242bee27f61f912a07da93f 100644 GIT binary patch literal 12082 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

FOwO(LhW+WuXM&u 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 b2J)L7C9wByH5)ez4^Vxkp;#$z5%&K8J5h{P literal 11975 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'ed4!JCK*OBFHT(umTvg|f+n%=JRqK)@QYVCGo- z5za=I)L_`E8`4b(E-85@AaX)B?sTQ^T|hYsS4^h;{O7{Ic4`d z8O2qtHS=a$@bW|PE#-mTDM9td747zWR?qJGIX>g3Z@{V}@VxhmsQn7%7k}l|S`3;( zDyecFn-zVJd9v&R))`)7Mm`ac!s<_wzOr?e6qDto$`8B~$RESmCqu(ta1QwGXJ8mt zbMz`9HoksU2;WBoL(K{dRgx6V&vHf?Q^%ThUn*rQdXxI|28jK<4Q&dFj2|nnJ*SV4 z*CSlh3uPJXk(pZC^p4%Pm3n2)-nH$2#loS4v<)+))hUG@Y zzOdOPp7*}-jiBW}UTQN*q~RJ8X~kJxl{}G#*=l0g+9yPxa)R8tRf5D6&E^of+$34f z<_!8*#42Aq<=fUd*xz`p=`FG}rD}7Ov4@8?Uaf5MqEDmGmlK;mCvZB*89O ze=qVP%3Vth-Z*xL7gb;XTza_#&o}I%IDBy#u-nymw4>u!aw0OyOE|eOQ&5sW?nC6_ z?rv;!iUimQ#DALoWD2V)Krq3{1A#0%$!Kr-Y}n;%Dd(r8%=^;YnHWE^AEezfn53=2 zyGl3a=;=dt50koqk+Hk>-uSYqy^r@%kZr}nQ@Y+J|GT()=@H>i=TtPt10MV^fIBqx zfR07zTiZsSU6faF96aESy(&!h^5>XGPF@Wi&+CN3vN9VDo9#;M$jnS+VIjXeWKR99 zr>r+yf@Dcj9+u2ju(Yho3-Mls36n4CAOu9`@ zCh0ejq)lV#`@oArceQooPFtk^POQHuP?V?W zz*Ii!I**{^TbeL1f30ED+P099rY~>G*Cu_@yeQY~$*t332XBo<6$b0^ToD-hrzsBf zPRsLF#{`w$f@7O0ygyWKVT#`z;gysvO)SH-LF;}C_l=|s0 znwCX{-ELaU_c&~r32TsBxR=JsEL~skiI{UawZ=aWD&$DMnN@v-PcQs6yzlSt4UMV! z`zHa4Hi%^F%79Rakg4N9*4=|DE7c(*RMbBUDxVVS!O94tm_QkhL_yMM8Y!)bxAaSw z>FMj+n9e|A$hhPQhXCVgi&^x1OO=?2#Yoqz=-W2qyo{A(mapWkm=>|Q+$*-QkY0YJ zIQNU5gNKn$RNXInuTL^}^)0_Gh`S|6E%2HzGqs8qr`q~x-2rpgCyP_D8hn0`#&R$oXH;%xfD=T1nIvnvBuo%CNzuQG5u=g7ogH#3ZW>{`>5$b zdM+K@T<}$M{a@E-0K)#-XQRS0|N4!kRG0g`6f5XqIbDa-_?l}6xL6MBT ziOCYK178;<_IiMjTp;NWdskClA&h-w^SOC2F?MP_BGQQhyzqyb(TZgdnj85a)%*LY z6HBg3QSZ?46HovyabH`cg{_&3-1bGtC?X7P9WE9Ky>#gnGR8QNpU+;TYRHQgZps1E znhm3-i{pEzGxld1*@>vuvK4}WpzD_`m2{m^Ywll#+0*qS9qsFh(KR&_6%Von=2pyn z*uD5YTQZ&~3nBB(=$Ds0O+HwjSvlH?Eq))|i3eSTj8U_q{1p8~>dWM`)%Go^A6E%V z6d6xm=C*lZlC`{WfF9xc-4oK1guCEpjJ|@Kw$F<8sTSnq4;l3cm;rEUvYA~?sB;soKm9=IjkL=rBMxR{ElbRfO#>q-? zMiY6dWxx4x<(h!#2j2cJvbdjL0Y|2h+73C70RJ_tr98?osS4^8*CKj6o4odKhmoM< z5sv~|LlTeu2cwmhd^~> zv5=F_o%P10&uKAg)si_Q?p7b0L+M*z|zyO^DB zrnkMj&^u>KHjxW8>^NbajdNhRxjEZky>#r!9y(_C{o?EX#V7c%c^|!ldQTw=j6qQt z_ja%#4iHiNG4{Ek>cTK>^9vpK35b2{0+;jfzYeD`gZ~iKMIobqZjw4De>;`zI=vfk zR5N!A^QwswIeP#;eRwL;rTSr>Y~>m!I3N_RNbAk)qft6VNz?L7ZVv_idgyvFDWpUY zw9NaRn06*H0QQXA7d{BiRs891S&+l+Kw&quQ`n6@7k4L<;3+eoXv~Mrvex;n8da#@ zQ;~cUxF8PnIjbcK7xD4)S&2DbMCIZ74f<4>5Z6BHS!dMFu2LnpTrDW<9)3}^Y_A;L zVc`R^ zqFko3Zm*Y(Y3qA6PLcI9^Tz`04!&_Cyy)-_vLK4t5VzIgpL zS~;pG5aQbHXK;Bl%`L>Uh^lVvg!``SneO8o@T}imY$#%$4fMOx-cU!unAg=}GWRg(n?N3DP zQ|Ev*^~K(9S%AL>^~hdO42GCc)sRv3a+7a=#Tnc4U zCLYSE5zom(=0&PWJVed;05-+5Xrg1w|1Uiv)Ny@hSUwb|<9Xhhw6I)VT>AK)4XA4X zX1GZ)S}n1d@n+lQ1hv+@UDQdOHj^=#qsvagSfMQ zE!I<`R`=qWLzTnV~i?Pcx-R@Vxc^qQCmszIE_VN$WsJc?}#S1%?^WXZoRzB z*Gw_IZNr}OFl(Sxc7M@*Zqje%9^=&Y`<=8s$C2tZ@0bg@InY1lU79Zk_M0_axVs*1 zXhe$mxu8L;s@|7L)Fl0O1i8i!#4|(69}3tTRTr!564a~k=5)rg^oASi6EF5CsoTH2 z-qs-QP>2;T>8JrnyuOPpB+Ls@{_Ac7Y;}L&N|_J4qh_dy6cY*K%AFB+pWN2woE+D80o7NvB_7O$=t<8D=3;9UhjhEQt;B0fhfCKN$ z^?4ZA-(g9{BvP4G5ZeuU6+!Eh(Tm}*-JkxEGuJVHV((nnm7zngdvKDbq_8j--Bc75 zpe*};QqylRiYz_p?>Vs__PhVy3E+2RRnb3T|522K~W zfdBL`rAPHY3vqa0yAeh5y|nq4PM&)6eG_MD;c1_9Ry(|oA<6tZQa!}u(H8v%?+4VR zwv*KxYIg;5e@6y~*)2n$9j$?t9GWc?A_;EW-Rj|TmG2g?K9 zkc}p;@Qk#G#|r8EgEH3^FrmX`y|N#Ezewio4vx4>-FJY!E@|xf(WPy%Ib1zsFb3~K zO0^ChkdbotAdM#e`t{9XT3l%2H_Jmi`YrvB86l`@k_H!Mq+Kx|SyAb+dW*dCUt zlUbHe+;=MW$XFx8tV|)3?a}4OpuIE+s2eMIUC*9Y!3Sid#Trl+8|b(0>Am`Iid*Ke zPd@be53Fm-`22{@{jpMVp4$8{U=3H!n!KI$t9V3uSssRIp%f92!SqR<~2&0iWYzw22NI zQMKmldbJsowso36^G=kb)#A*`VY-QRBY?xiBWUmJG|KZOea_cRrPE3#&$Z<;^q&HW zELbTC5^~s3`~jW8u2Ir*HGCDep6s3Q(deiC45{88dJu*lL#%*s?tJ+cij_0D@uP-t*dsm>2?^JGy UZ;x0B0(Ic=LoJn3C5yoS0VUC2`v3p{ diff --git a/voidcrew/modules/ship_upgrades/previews/hiryu_class_carrier_captain_s_quarters_standard.png b/voidcrew/modules/ship_upgrades/previews/hiryu_class_carrier_captain_s_quarters_standard.png index dd78e003ddb4be48618f56134d7b46df487ce261..364ddc4536d9ed4046c7a1054e810c477904804b 100644 GIT binary patch literal 12405 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 B@ksyx literal 12388 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 diff --git a/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_a.preview.json b/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_a.preview.json index 448d1dff082..71d0a0354b3 100644 --- a/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_a.preview.json +++ b/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_a.preview.json @@ -25,7 +25,7 @@ 11 ] }, - "src_md5": "13958fc798c01b4bffdd5d9c1d649117", + "src_md5": "7efa5725fd449d244cb1ce19b57c7303", "width": 56 } }, diff --git a/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_b.preview.json b/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_b.preview.json index 5949f1a7c87..a04b989913f 100644 --- a/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_b.preview.json +++ b/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_b.preview.json @@ -25,7 +25,7 @@ 11 ] }, - "src_md5": "d58b0e7e963891855cd49411e2f94514", + "src_md5": "5f0ebbb7dd2dab9024f8953ad3fe532c", "width": 56 } }, diff --git a/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_c.preview.json b/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_c.preview.json index 30167fe6505..053b7c42d37 100644 --- a/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_c.preview.json +++ b/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_c.preview.json @@ -25,7 +25,7 @@ 11 ] }, - "src_md5": "4c005aa96c5f1f5b74ed23e71625f47a", + "src_md5": "a9972500830ee4a6b3e73b666018854a", "width": 56 } }, diff --git a/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_d.preview.json b/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_d.preview.json index ac205a4f535..2993beab434 100644 --- a/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_d.preview.json +++ b/voidcrew/modules/ship_upgrades/previews/hulls/nano_phalanx_d.preview.json @@ -25,7 +25,7 @@ 11 ] }, - "src_md5": "3ff8299f8dbe1c41f5e0dcaf12ce32fc", + "src_md5": "4fb5b5dc7f01bbb06b5ee883ba72a54a", "width": 56 } }, diff --git a/voidcrew/modules/ship_upgrades/previews/modules/hiryu_class_carrier/captain_s_quarters.preview.json b/voidcrew/modules/ship_upgrades/previews/modules/hiryu_class_carrier/captain_s_quarters.preview.json index deabcfdebb1..1a72f37b2c9 100644 --- a/voidcrew/modules/ship_upgrades/previews/modules/hiryu_class_carrier/captain_s_quarters.preview.json +++ b/voidcrew/modules/ship_upgrades/previews/modules/hiryu_class_carrier/captain_s_quarters.preview.json @@ -15,7 +15,7 @@ ], "height": 7, "png": "hiryu_class_carrier_captain_s_quarters_pink.png", - "src_md5": "7e9964f24027790ca764f4bd65297ab3", + "src_md5": "bdd15c6e11ed39ba02ab4521ab6e9ca3", "width": 4 }, "standard": { @@ -25,7 +25,7 @@ ], "height": 7, "png": "hiryu_class_carrier_captain_s_quarters_standard.png", - "src_md5": "4bcd8f569927a2ae0e0000a4870f7764", + "src_md5": "f1f488466e2d599dab7432418e634c50", "width": 4 }, "syndicate": { @@ -35,7 +35,7 @@ ], "height": 7, "png": "hiryu_class_carrier_captain_s_quarters_syndicate.png", - "src_md5": "fcebbba0444ede432ffcac98cfc685d6", + "src_md5": "488659b0226c4f637143b4ddee2e8fc8", "width": 4 } }, diff --git a/voidcrew/modules/ship_upgrades/previews/modules/squab/security_director.preview.json b/voidcrew/modules/ship_upgrades/previews/modules/squab/security_director.preview.json index d9f49ef1552..7856dcad5c2 100644 --- a/voidcrew/modules/ship_upgrades/previews/modules/squab/security_director.preview.json +++ b/voidcrew/modules/ship_upgrades/previews/modules/squab/security_director.preview.json @@ -8,7 +8,7 @@ ], "height": 2, "png": "squab_security_director.png", - "src_md5": "a54ea9e2fbe15b05b5219d33bbadd24b", + "src_md5": "3cbb7655c1a52247ad1190ea4ce03b97", "width": 3 } }, diff --git a/voidcrew/modules/ship_upgrades/previews/ship_nano_phalanx_a.png b/voidcrew/modules/ship_upgrades/previews/ship_nano_phalanx_a.png index 943b58f587e65b5cd1ff8c1ab8e4eff555d51849..a293fb34e5381c5bdb5ecbea1099ae0efb23f968 100644 GIT binary patch literal 379473 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�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 JY^_HU5|Z$9g`JhzDMDW>JHG8~VTfTz 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

5%r%)y(l8IE>FqP?Nfn&V6mwaGi;H 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 literal 377156 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

ZRiOxPZ)#@xN`Tp-#vDuuay3anAUE~-sSwnLW zMiP8B^JrRD=Y__R5E&iv`#2;_o-LICqD6}AVSs=AL5s)spci?4s@3NB^Gu`fFy2vh zCU5`2BAYShZl=Hxp3%`fpP=bMoYR}rC4^d+N5cVhtb8A-S2kWx>4*^lJktdBmz)gO zWILXkEKAmQ+nT3vJ!K{zJkC|E%8P<=z+CrdMy^f-SNghgAz6YSype>eNQdNrYz9v? z^g|SkeKGJ7e3Fs}NAIcboZfO3CTqU5x|yOj2;oObt--o>dRi2% zVRqfOeJy6cz=mf}X~er}mq%q~g`mx%BYqlAg#gg#CiNI-b~^mhUjwEQCvG`Znt`}+ z00;XcR+QFRVf82<;uTRezDV4d4$a{NhVVcsqUbY7AJOsqWL5@Qu!CllTMODc+v%@C zq;+gG;Jg4n@xX`D%f}rkjLJ)ms!VDTBAdg&#x(*M8)zhgsr7`=D{IR z$)k25F+3{MSr)r5z35OmJ2a`mi+p)LGF1CV$}}}+R-r_Y(DHbwWqU1w9`_T*Y#ie9 zqbOzE&aIR{kq06LpX=8*hw2?BUv@`^;Zm^~*)t}GuPv+%3W&aOj}GfEsEB6g86Hu! z>vQPwT~sL#2NB&((iSq1k1%M4A;CUf#r~)`59kf|sS2nO?P_lHJnNXds^x~f9r06* z*iivJIdrmkG<7>hfMXpzXj;}<*?9OS;AYUn2p+aDAFx*8TVjOb)pa-XzxVzh4-b(t zQb$5t_s{gqjP+cN)tA^&y=MNq0gdiU-Nblaa_ncM+)R_^-70!6=GD}+I2$F|@=`*{ z=1bKv1ATpAMc0+iKmq7)N!F6ysZzb<_wQp3%AZ?(3&kStWlGyvAkQF+#{Bb^B8NAL z1zFm-fd7<4+h82WDUZr?An^(8&`+F>&-AutPn%g_joL_neC>BA%0oLpVxeE&q+_%Q z=S8F5t&^EsR2jN9-szPSGfMju^r!#oepNe6^P`;e|DMpWqwK7iIM5Uq(OT3(;OFYCm>23p}^= zfz@)$T)_2y170mUJTjB;ye}yqM%#38`A!!j$T)!5gE)N(HH2V`s&DQ~RpQ&1IS(*I z^X_|?bd~FBIPLE$4sc6TS2g(6;9<%w?sI|VP{>e*3 zw-z??DxKbdDp;rshTcsu>SiPsaG^5SV5Up^&;OB&><=2*xV%NQ z#G6_T^2v5*%cC0$57BlOkrU-05op)N35h7l*8u|V@?0BNs^Ac1Cq3Dj%4Ly!7s>?2 zU13Xe|8A>R_zT{0Zkb1R3g-aW%ZI$iKAZwi9qFSCbA!qQ_c`yOy69bI*5g$VKEFWd z&z#W|P1Ap1aZFZFjj`E7Q7bvlNI+@nz@NIPc8dfIm0!>*>LzOl8WoSi33%X$gz zh3!8+b4`=x*P97|PnB^e-lp!yb%rQ|97DQ;-od~GlBGyI8e2tqA0utZ3l`W~$m=lv z*$Y)19!w4$)@IWUa`IRCJw^`?%gp@bMi>>HMx_*J*Qj30!+RRBpl`txbqs$%k5 z+W(mlzQ-hEYR+Bhg|mPSWXQsF;CELaGD9jSy@RXtiph6}xzUS6;?u;Ax}W-_TCW5s zu3t0}{Rz5Jh#He06IAAm*D3qHzoxmZ+*&cNank7W&w~paIo~~zXCJ&~l1fneag=+Y zOtPe#NVd>xSAy|o;xp>Rb z*T-H+qAqa%2VkhF0sOSjxu(<=iX5RSK>#m*p~=;bw-UVf_`zmzu8Yo<4!aNN;_{L` z8;m<3MTLP&hFWLK+Dzn{+3p{INxC;KDm0-D21_K+)!0UofCTGNN&kKRoUVO+R zL>c|vmjqmeWXw-*K5ho81$k2v>tkMi-B6}V4)kww?fWSUXd%-0j4R_a@#8k!!mv1* zV;(}T(L9+oLg)F$CqMJVHk|+bYB2qoCvo!3dEv|BpUjf2n0<+iv%`Qx<@wm&(XOLM znf!g$wCPb>gWos4F7Ca0#BIHD_?7qmGYO?q5TU^vW-*w$X@^N{A-E7z89hRg zU+!#7$!A~i;P}hs3Z#o-SCO3v_YgiC4d=g?6}FLP5D(WQAalTkN>_pO{beKGspZKJ zfdz-(l>Ui-((fq|`mGK5n(VVIQHxSx^db7Olj(*YoeN)4ob$E!FV)Yn=Y+)Y<3`i4 zG7#Z J7c*}fjRENE#Bzh^^6#%gZUHv@_7_4J_p{I|KA%$YU~UWn#ONuJiVW>+R%-jFEBeUomVoX}&W3}oYhrbC$ycX~ zqSXqwl9eXLNB3LtO_xz5L06ZQpI*)d;`032zIx=5l#&*)7cby!b2JWSp?T5mTd!Z=c8fIyu^4m{yuU59S?!9PCt#?k# z<4Db62gL`NB^%;(+y_F2!cf$UW6-nvy7FxW>u5$IjkIbcPs5DBe`>leAAT+&d2fip zjp%i8(>?i3-?d$Hx4&Hn$fpV&EGVfe=MCBt?q%&E5)w`l1>hxFVq?m2qpT>bsd5iD z^~x|0MkJ$rR0bZT((7th)d#|cmp^xW-GAGB{tL})a&APN_C%}h* zru_Ls#p+4A1f!=ko%5U#hkZ?poP!USDDHiW@x{X?P#*j#2CK>75GQfjh74x2Lt zfuWd;75Hy)TmpiW{kFZb@;OtxQ&XkELZPHB6&TcC z4h92s&&M6e;Ms6PG@X`QMSLYpfg(`x*}&txRgltXlBdL!FeO#6^xH#k z6S1QJUc#NO++wG%_lj)$goCD>d*d_1<>k*L@a;zErx<1LK!yMgZY|zTx%aI0tfiQ< zVTAecmTLWDFwl@mviRPgDUkaf&f#4S2b)zrHwX}SlOa)wh4qiHPs#YM4r&p|H ztGr!iP+s%m8@lJ)w^A-~{2&K~e1M3haVGu6JPbV-!FB6hZy+i*q|4mch22_RfCdgq z8J7XoRdv2^7>*%){yF=1QN0Z*FDM3n8h&Of!bfF>x}3hKwncyQeWtPm>C9%~S4W1j zpm*g%*L+cu5{&u2cr5=DDTltn0u}~CU`K}*lQ+hBFTLY6pfFIwN*MR^DS{sw7i%0o z?w=$^saTyz%+F5E3EYDCzIC7t-N_7tZvFUyi>fMpAM2}#A0)4pNVt=}>{I6rQ4Df7 zcwy&(^G;9K76$E?)5U_FkLEryw9wjb@bsJf=F)9&1=d01iNqk{eAAFhP1d9I$PZt~ zO~pzKc^oA#F{Rf0yPXinedjcl&!ih4_M6v1Y?kunMqm{MY-Ia7?UFA8MU1QCm2y)bho{QT^`)g&;C zzkJC&GU-m7TOG-~;$E1-mh|T136I8)gh);q!sLWq3F`ON|0Hh|DNufnc|(P#8=N7A zmJv}=B++n!&o|I+U)?z{V40b#VV?O(apiYFmo2?5BT!@Vz*?E?!;x#b64;VCGS7S% zh`<159{bm?iSejjczZX6Iab%!jz4Y?cbwvBfrP6o0Iv+~7QrI)B-bJJ8k4A>Ny3+1 zUJ)MmrUSqWmKgKJ-!Qzprq!8(m64jcGFiM&7a!|?3#C--gYD^WVHX~ z$

;weN|%R<}WObH_3eLN+=?0Bv=F9XW?sWy&Vd`cF8m9Kzo!C%SB(nK2k zWPyPfu?>l&Qer3iV&+0D?w<3g6YrBe!{x7^R18@jN=1@+n*j!|Yy0=zA@6QTqCMtd zqiWw*2iS3p2W675j9RsP*E~dEojn_ZGWO;)>!K z7yk4bh$ZP2(JQYonjJ_dUJSZD7`8kB_&aY|tpA2t1^8$C_`*;6+;+xTpL@^r`WV>K zChtbX7{tqbl!5pzdZj+?l~NN)-W7w&lbz8{Hqzt#MWFgP2QEpaaYF}TZ5+6isVI-n zp&g(UAYJl9r$8x#rS0_#OUR?2bbWHfJWN-~?6%EogAvX-Knql;8nb`qJ#4+r7~68tQZ~?@6BKS0*VupGI!+n@x1{7RL??K8^AmT$@?O8 z?v5gaY1L*GOUf(PD2%X}Tm7WSc z)LXBuny(@i4M{o%eL_<1J>ycTVX{vSKBNp*b%I3i$tUA(?sc9P=f-`3+4!t>=`s(5 zLEy~3jKG&D6<>jZD;^iJ2+@$ZTzI0PfPUU*?)QC5>skXW!`7udDh>O3+Uo%Z@Mr=e$gHa|3Sw5y<&kFP8su1OHe)rMjX8yEOxqv(<-$az=hp8BrJ;I|nO~vmsqO@}7 z0+djOh|tpQ)elrd$%Yd6DO_3#=9L{M-#U=$Sn50sqUmHI*_0d&mT=9ko`ZAI=+Qxy zbN*@x(kMf7560!dTg{ByU-N4k>PKx4RZCG-1PxSq;p_)D{hi-4C^$K+8DD2@%Sc7B zXAAU!+WCnzUe2{S(Y#=1!IgAK6mpgg4{>MQ5-TBo9jc+O5!2Il)X5*EF2Kjvon~mk zyNx>Z?&?uE-j+uhb6J!y-6;5PCaZ;$#=revT11!MV$9o(s@2k^X6ZL{$OyDUc|wza zM2T%H^Mp5u>)%K{0>XVHl7MqjR0o!+)1wmilVtbC$+4{V?3~2B>U5mj$vl0Q4c&u4 zt-yIw)6&qVOKt_l?&tv0MgH=7zm|${Njy^n6eEms9$C8MCX|yqqU({YUq-!W| z?}>7K+=>@$^GQnpAoD08Zu|b-AJyrHBp5uBBQCf~vA9JDsQAZ(Yo zaifgPX*zbl>*4t$?eh$OQn@f}sK}cT3R=_nzD;~^a1hU;=*%=#Z#gm|IM;5=fBI`f zVmo`j|L413fOAEM*cVfG&dal&T~zQpFPLO8t@t<(z*V&W7hXw?3;MKU+V1l}4^GB|$-|8!s{_J5 zy*z~}J>bCvOmX7)BFi^4)u}CUKZck*mDiJS7?KXAkaUKNA%_|v!xPb0_DqlsKag&D z)UQ8PQ-N$ib9!kR^;9A72)GTCm+zgaOh;KFB@OG&YOIm-R4X;jii`Wuo;36^+)+p! zd`vEgcek?x)s7YD5!4J1GzPuU2X_GDnV}D8;(-`GkdBa;{}sEecVi=1TwG+8x=O_J zF2J-giK(A>@A&gM&~_fOTRP|8Oj-EKGQ5gumm*2EhAOXv6vwb50W9^WGmLO0m@Mdy z$s6#Fge5r`m|ddK5epR1wV!QAR=goI+xu>R7HWwY19fSG_x2nwxTg=6>`IEa8ecaI z&Ec4IiQD$x6vw}*T$cDUD_2Q%=rP$SG5mg=)+VU0(8 z8MSH%wqQ;7o&qRVyX{GD=64fq)4nC5KD>9R+b)#NZrvz(4pyojzZscUakFNEr-L(qdQa)GzIb(sz{!HLGHMz?2FVYaG+&ylD(COOC#bxdi+2D z-ZwprEj=bnaP@oPxvsnnaDHMaD>}@oc%@P;gxYrUY~CyI>mJqZOOjT%@1^7e#S_SP z{og!sbe{sUUYi{9+Xd(>%^|s%DLBLt5gA^7A0Gk7iC@E38A?7M^q^#V#EU;+Bi+PhE~cg;CxtEIvsxu z-ibS|w&*cwem3q)ulWG9YDFyM?I1tkL8mxU)TJdw+o?}zmzgPl^rx+m|E2ixC4Sx;W2B&p}_w zU-*pGu}n>S;cH$50EsYEam%K+91z)_h5EhX(%x31@AAIv;(-zDn|rQgsR6r99f?2e zx;TqlT70z@TK8$7>$`nNY1@(^%{TmZ)yXAuxb>WsHcY{GuSRSblXp)h{GGbJpA3RvDt3(KTD*WSh4d(RGgG>3cfALh@{bNGoU2Np{bDNVxY z^RCf!&fc5|YR?Dm+NGe)lJZ&#bb%?qYaOw5f1}*(u&4E;_jdmPBN0oovY#y4e^ZTi z+p@4{lRiS#WpzRCCZOFxv72|JH5*O~x;8_qk{6aA>O7t1@g^hp@zhs5IZ<+L4wMXV zwcY|(t1LGi1I*w5{3a<1p8-$nX32yjzeGVVu3Rxz{_wFK_jUGyKdeu|~u39)P!YIwA5*@?@aXit#^@auz6_qML> z(wX1)jrOyIBu-2o4m!CXFE2EF+5US3?#T5A(2%Qz!r6X9zyzT~#}up@qKB*P&2nzB z!4>gvG?IWiS15|e#nG{Qt*7YAFR+s-?=`#j`3UyQ_`JwSigzcX5ulNuLZ0;Ksr~Z0 z$PvpI8I?cpdE-*ya1HWW?R|>5vYys(M*R>|?!~h1NIKmUEacWt6JMZHNASOGV~VLU z8t;0-ryxjvTmiR_kJ;%CT7dr#L?{q(G5P|a=bnn}2#t=TYhjB9r;R5^5&+ zrq03^(VsD2XV+F~DbTaVhgqnOPJV6p@F7kgfBD!9)uA%ebSD1(i44DyEi7fp`Yhz1z6gLZ70rso+0WEidR3gc>hb4y=zWzZIJL zIv_4eo+yuMjPgNjSq{G}eBirRPtxT>nIRz1tH#gxL_zWSTe-wnQhWmMZu$z#UWc!@q52b^%m z?`!}Mq$?olq6m5Z{P~yT{5zBn0lmgQD4z$bw?|Nz$>xdzW$=${L?Y&VDO2fp^>J(a zk{UWj`+F}s`Hy)-^?yoz4cM*{i$h#CHMQ#Jmwq=GP?uoyA0r#U5kdE-$o^#swA2g+ zt_wrE9>{?3Xe@jR9F4%7B`#oAg}{QlFTD~6s$M@h`)U#cXptzmfCHtOIUCyti0!A^ zsd7cdOKQv-_~KOo?64sU;MoNXueqrt4LAP!G9V&Nkl56`nl;(qa2^_Im;N-N)e7TB z`m$(Qv0Pus^@Q5+OyzwTPclYSu73!*A+uYI8rCsJNb?DF1$?&cQ~sbCnYwc0wUL8{ z8Vv-fGCa0ek|Q^YpPdfvjB59uNycrF&Ees>@g+F)5zM8LtODE~ZBpu>##7Z%PsiY< z2Cvmng5RZyUk&JTXT&7mr8vK=_#n|g=#{#l{m5XNB6Qqzhv-{>8sKu5hxjZO*jL=& zq7V6DH$JUndlm1(Nn*~Cs)raz& zXN!;mY(XJ8B>V$u_j$@Y64Qw>bbmfRP<8Wfoz(b@&%8y~TdvaYf;F-$s=I4WX$l>C zOkRBR)OWFrixEfR{}0N??;l`Fln?++fh7Z7gacX8&rDpOUbokw*VGn}IX&-$ZocHl z$B(T+1)q(GJFFZ1UfLE)!Z}dr?@|bkZnriy(tps)9fGT1qRITyu>e*hdO zSrDEw(t-C@xfzBB42>ctw@R95M$dx?Y13kHkXJZjs8wc^n#n7A=c;gilDh{ICgiMZ z7mFMcxSeqOGV!TMim9JX$pjy}Bz+)T~7b^!lm4IR} z)dy1dhH?N=FX%RqGDno;I%cUq@ylwWvt3woLWi3Ke-}o%iLNcy3op$|hWlrg)1?A= zy6V(~0xRLJUjsqY(O&@|j;hmZ_xjMO2za|Q;EI61(R)NRL-5}~935r&mCuX!l+eOJ zOX--fWe+@jfXA2j@jY8r{*U5$pNCc z*eMNz!Z0*(-#J1RSHPLVA!NS5-V2b%^&yKCNxx&@>|=f>crg_{0M`al6W;RCBp!q9 zIFX??S(J}u;wLZ?MO9M;cVh02;_I=Ox-yqT&)Eb*MLffBtkw{j(lX?fl{MX!bR^9L zU#nd<^FFPm=)Q-{%pkdJR|Tc^(oJl>ez-sL_pu1X^2S$SZ7Xe9L^6r-oAt{mLmU(Shclb6XsF8m&Z;ol4|HZtS)8-Kv_5vtKXyXdMdGjA9HPnv94@xki zn?=0HwwT*cAnxe+9Uk^2zMmcN|CB~>t}WpIOUvtp`2oB~z+S;vQC9F0n<8~kT29_& z#@J^q58~bbLB`8OeFk8mPrho8bgF7vKd_~CUVyo91G@FiNaofvy8QO%`#3}^H_iQMj`ue*HocPTTw=}ov&*)>} zcroxoS3S2NU~Mi?QBqFYafgJ@HD7oMZfg$LKRY|?A5?&Sl@54Q{rc{^@{gD|Dzk6) zXRcQ7C&~Fup@G%aVRR5P4qUs^U^h#pu(yqMCBOztzYvZfj;mSOi@Jh(4kQbSMTj405} z&67WYm!$!o!ENdA1q<%y-%i}#g!mtpMy$fe!G}r3+?u)3G3<`Vf4;Jyf9*`tPcmua{^L}-(-+K&Ov8bGUp%>bTfcIV|2U1Z7jt$e(jS5h+ayJ zY}ednAQkXqL9F$^;57$+ehe~4{TQQvO$)xqG1tnSG1mna5NIrbJ7E)6;TZsW?2W*ibU4aY7+%O#?Ajb-;z=iKeMQoNPmXgN-?gH@YJMGS6JDH;54xQM-BQws-5Ssd-swibD`>ug8|OCXdjO_XQ!(`Z8*E4PHvH`G5{rx}d!9FJBJW zN51>AT~E0BGXf*0@;H3Nov!iBn!)H6@AZwBloZ_pAX42`P-!HJxG&v7DDJG4`8CRp0- zgB@M0^NwSTgZ{r_oi{B@lfe1lGg?!BnTd4wn^d6837E3qdWi$k@Mfl9pwL5ITMtyW z1~1+Ia<*f&-B?`;5_ynXz=7g<7!eIP@_KE33w{6je2>|`nUiKaP@VvDoJg>$=getX zkC~=s7+L{NWiCM^by=bz%OiHi0f$}t-6J)_dGSmUH?cj(gF=!zk5AxCA}7N-pnygO zAcFpC8EJN1qLm5w$tvT*UJn4~INg9t+-L7P;LqGF+bD3}@p0%hjwLV)@zo=?*w71y zNaHnNqfBBCbA8dp>OD6$1P>x%&HJy*81pMOq+0%%QCWvp$yeRo75(Ly&>zZ!|tHbYK$U z#Ci4efGS_B|19556~>wyUgv19dn;eJXyh_fDD872AWYI4AIcZcuchK`OALT!5W*t3 zsp=N^3nwyFnFb+NE`?)vY|&Js3MaV&^HN`UR6R~U8IbLr5CT>+0SySJtSf1T4-tF| zGKQdZ=6e1t)%Zq|cSWSFcLbGV;XJbgAPHP`cKfDf1H>UpJEA8v1-ys@#iM(e-+bgY z=e_jF&Go{q3aH05$=Mw!-IZ9@hT0(ycbs}z-$5v`Qz=4~VThOFURpC7+(W!eoKXZt z@a&3Js6E3oBlkG>m)31ys$fZn6SVnAZdO`L9i9pw+#jN`TYgHy0J}D#xF)s0z6`Rr}Sb zrX@Okto-VI?(;nUB=n@IpmjeH@R09yYR`9j88br1*Z~I*2Cd?3RhJP=&!Rc&+4sT# zBH^zeE9TMl!t``RIHrGJ2!FQB?$tqQaW?JU?M#}VN|yuQV9^~VryiIJM3g@-EM3te zF9K>)D_XL)qUeD13MUuW4<{@Z6mmO^Sh7WpcZA};oFD0FKg9h;#O56YAKKm-#D9aG zMVb^uq2|-9yt%KFPX%h8{C(Xt@)^#q3k6dydo8ZYmFGl-5zqp+TZ zo1QAIFF7kM>=C!-*JG<59Rof7?d`3t^{ZNZNqP219|9*GwrHpcm26#dvYGEOB~F^> zxXTrNtB@DFAHzr!6tL6Q+E#2TC#RDt0@5uOyF9RAm2#O}Z!b@D zEy7_rx|(4l93Uwd5{rodCG_7{Hr^%Md}UkUxk1B2CynMSh7#~z-IF^cDQOGUq}BVFHZCrL>GzB5;WrBV)HF18<0U4nv?R>G^Mn#NEeHA;7^*9*H}l>x zh{X1p7i*%Gyqadx0B#Ba`37M?Gj$4Djfqi=$@-z3_chH2Z?rr5ErTr(Qo~rkMzW9ChiEkyT1|ECA zeCG?FhRR3nqS+Ht(h$uKOW!{Zl5gK;3OJEFt$C3Nxn^s>nzKPJ%TjRBMlb5E&z(3* z9)%Lz|GJ$AIlQdNW4pfGv;jYy7)`sAZCyKVv8y`vBGHb9erQTZdHMzke7AApP(EY6 zW*C36r|Tj31uE4dDbcd6bx@4GrvM&!)^mK1z|C{Wk>h7xh>)cZz9fa++D6>>>%gUC}v2S34OOlHLgptfuY!*->ydV+bJnRkeJsSQG@N4EEb6!9D~E zB-7;p2z41NZH&6_)mqfNr|AbL8*91*X}5LdD4mu;()d|(Z^jRhor0+B)Vn8tq0eH( zf-12Q)i)ExfkGhj3j~B56fph@2w894jypx~yRNRX56k)w7|iBOGz`;>nPxN#IDznG zwi=ZRf^<*G$olmX)6=;&so+@CXbG5-+ESjFyRU?nGa8Bhu(lrY^HgSP%B7A9%`JKoElQA0WJ1c~TMm{X87pd;7TL zPr5c!^{2OFluP94;yPcO(Uk|?^6&t^jn291M_gKGPV=#`bgJQIp5rRb7r&h5A2L1E zA^g^lN7Z5FH>D`7l_!^jNG?Sb=LHS!ahb`mGvSR}xzB+`Vd^acnM~e+VnU%oD)ZW~ z9fFs>$?%O_sP#4Qfne{G@bC2XMj3}2YBV2y@tu!(NTxC=GmYUoLp4;Q$=@{JHtUa- z+ss%v+tu-h1)xIXWXc5sY_DA$X7yR(wfFm#J~wW&lU3RhPE5rUA*+)6&9;Ng@q52{GM7tI_{w^J_&EA(B-H552lqYBBWUDm0?gN4zwq`YJkxg zc*9|)se@^hCt1`TG?xM@xr2O z_?+r}`PWKCDr-~E0ph?5nhq+vyFO6bmmosb+c2dOjHIw=`9zgM-P-l&4c7wUd?7h% z329;qE@d7(IW|=1Y0go8K|u&vs2`pJ_>eUjUg#hSJGx^Y<34%fa~xv1nsE8)xP=XG zr=0ZbGT#ce9^wwL6YvL5+^i*utUeMCO@nKV4X*@S>w;IhQ_?KWKuISV5mx`=>P@Nv zld6**dj$fqv%9Oh?|{%C)xEgexp!t4+l^+$1-9i_5}w^I{Azbn_tQ<>8#g)BM7X&8 z{BhV>DR2DzJm*%nPZc*gudLTfJZ|$`pvTsVwzmw zMc%5jU{`1~4LY}F$!pHP;y=WL4+q8H_c8tpsq(#0NPBC#U*6W&dv?Vim1OPfAIcB8 ziKyBi^}ft&y{~^HCLy^6Ze}CwD9!5^11r9!YYF0<=e9;6Wd#ri9V-Qu&DqbD?6w`= zGMX;>a--O9c+ld6Hq+J)lc`aBvXlzv3A6AWx!%uw4U5s)f!# z>8E#vN0G|7d})DIGAQ6R4;>b80Dwwvtxe2odqq5KDp@BbuXo+prX;T1ML&Ye>GMJJ+0^c9tv;Op^(GAUwo7+-}Ao11HpN4_~;eOzJQHdFp4My7(@MTx_rgpBo_ zkjbDhER+9Pg*6a*;efU+ZINfaCb9x-VX52OV3{tHt%fQfInv&ODlxmsLTy~!rFM!x z6L>*TZWD3QypWXOkFbO>K+qck=B=1fhOCyQJ z5X?;t1;KT#-6e6LR3f7bJhTtwM9bO=JytQy0z;Gg>~7x#}uctV2o zv~)S%``;!fJ^001-FYDL&W6pnOg~@8iEl#n=mf2)&p;Mrlk>|GD081#(^6v5j5LOUm~+MOjRq0gcna$mTm3 z$VX^DAJa@qRL5qlh)x98%=x6WtH&><6}2iJ%Ew-Ccy3ddv|M%ScuH?nA}Q=?`eIc})y!K*N5@atW^4A@ z0!s;JwR&$}d5V|Wjr4r0mhbC-_k`9mwXns!rQHQ(UQkqpEpF#&t#>E@1R3|^ww7F! zV)ph(7Llr#3&)*7;2>1+UX!1^`;R3zop&|yf?e(fzY~hMUsW{|rx`4l=;JIMJF<{R zvXDQJF=LCcKf?r0%39s1oQ=a@j1*(Z9|Nq!gQNeYPzW(n0J$#YeW6@=o$J1#@(3@3 zHY7H>7QCem8Q_7E+*dqbgisW3tt#6}Kg9pz?(g=CvE4l5bC*eRA@XP`0#KvgNBr7E zE44J*Ze_y%o^{&MrdWoIsqXlm&VTux>a5E2W>;Be#&sen^A*&v%4N zDIzk_k{@r|lIR`W{7|CePl=3Nmm$dekTPzaNz*I^#+vp!FHPiseB|=-a_>^nz2CoE z!SCgI5qf%h=9hiJzs9<*XfIyf!u#7HQ{MCTr=*?OmpTp@-$TB^QewW9@$sLEJbtEt zp>0x5O~o8&YwRH|hw%+&^2Uv79ZQ1?IOfPSO9^$EoGd|`xxO&)W zmOaaMdsWX5gYMm@O}EQDoh@TQn7PaXff(FAt263GIU#T)u`%8Q`~5vz2gJaA94tCl zgBZ0R4LJE7e?`J(RDdnn#ff+<&I|J#r-^4Aa4vAJz^IUUt9}!@aORPGH?QfA)(rus z;?}iQI!Wb*_s3c+m07B_pvBS8(=cAblCC59^?0o}<*M8h|jVc!ccoWTTd-C14DE9&j8I2b>K9z%9$k&Z*j+OXUgD!5o4SlDj`jvD4PH=CEXwlERK*Q zXP5q_$Z4ggTMo&X9Q8cT&&;e4H|MRhnzbsA*EjQYep&*(qH)j27hF_qpj4C&DZk74 z%FWX=X7CP?h5&japxw#x0`sZ-o>axKKNPv+-O$uDz^ZboFRdF6)Xk0r21ULnV?u-3)V6tpMf3-q}&r)G(4l=Orez zjh4IZ+x7j1oZn+xmh+_22?4jkD)YO^oR%;E@5*roAXZ_Fx4x3AysJ6!Fl^l;kMAH`VqH!Yc{I*Qy^1dfkdP;v={t@b!jgpF{P6sIxnhovk+WpP>#hYXc z@h6efeVeJWdU~LDmX(BssVuhfWbo-bZc;Chh1+?W0Cc9ws4ev7_7rxC=_*_69eHMe ztcK)o5kyk$7%iN5f1ewq@GZgC3Hki0BLDBa8c^M7_19s+WeO&dhYP=MKT#EvwGOYl z38x5BgF2R5wx58`XnHTYn$(khT)Hx!q-or$mfndv}%WOOKwvdZSxlu9Y;gFX#>1_&%tKhI-!60{9Z+L+we zqN6R^B6RbsnZ37m&9yGkN!0G)CZT8aKlVep&R=b<#x}Tgv)3%!f_qA|akW`+T<5V{ z1dSh#lphOXvY`OR=Yx|UdHvVZE6%~wj_1a>+J@&8?ejkrfQ{G3AP78&4TK<)dOmn_ zu1FFlr=2dF$>gDoOp71>b~4CU?-fyA)(hm>W|#E$Mfe^hokuBNmqz^DWX@Ts*z{37 z{J}vgIdk zqZ=ei!@jF}`jJEoKqM5vv{m%P)GLg^7ukNEmX7lxe)9caQw_#4>M;;tUqw^jWF~{m z&sPPOnUMu|YJ>c4;Nz1>aVb9Wpj}T?>G?h9d7rOhww8L}6-EDY%B|A&b_PkwT#{F1 zm6aFG4AVdimV*KU{4?c@+n{-Gu8cT;Yvsixv!4^zzxfg8+HSKW#}q{JCQq(aO}&(R zSxGez^#M1qANCITAVw}*l=h^OV#kGz=6#{a(&xj}eMicgnO$+{J^9OTqV&;+M*l>? zO{1rQoUwo_4 z`0zUpi){bWlQ-YJQkhvyyhuL}*GGN*(AEEdxQ_bs%MyN>vs9GzcMTj)YC~iT8!CR? ztyt{tu;>MOnNwMBu#eBbme&$-rGzSY!N7DQ%G;M)R8cZz5SGila>V61qL>hEQ2uJS zC-MX7q}Xm))I{vW?!#*u8kffdJgb#`9#*wRk5Pxi8M#2|uhVyPEb87f(^^;;^`ZlP z^X>Qj2`Le_glZ+LxAyNd%ul2cuHQtxXY*&#vl%;ZE{|%g0bZ+-bzHU9m<{Hi!QMrI zyn~C(arL*YiLY`z62a0RfInx$3jgD$hVu; zs+8&JztW};61b0dK2*~-q9RivaEpBZFqxaH4#i7iLHgk%2n9APsPx~6moTGU@BbUb z3%Sh)>5a49*S)>=^nv9Cm6~+l3o%iM<*zC3ofRvyU3pipN9l8{?f zXqo3+?sINtS(&tl_FEWZ^v5Kmz~f=v3x3DcV7X&xNcs$$|E=yc*5s{~Z6>=L3(Fo( zsdB>X6!T>+aHpr=oyTwg)dgfTlbm@85`gI#uT+A@2QJLs zVWOm`ICFc3{k`qtPapWzpT}nLSUqte;xTZ7qn@mo2kO!JWHl4huR^d4av0TP;}yH8 z)MGsf6a2mu(+nghOUzG(DYHUv$S16Oj@?F{w4W>AuR^F0Y3ZB3xgD1Ec};IL$BDGs zd_s%eK*C=akoDW`A;tClwlFCT+WGPQDq@z}~NbdUJ*IeG!QWA*0u2vz|Z!X<>&&SCBPOK)yc zcCuh#-i;5i-o2Z4-+Pp63}KAvN%K~e!} zC8b+JkY?x-7$g-X1d%R5y1N_c2I=k`1f`|BQ@Vznftk5~{`Y>ay`Ss3pWoYgF>lsq zo#(mMaeR-swLwL?j^6A?A3y4LAmnJD%!Wo@Bsio}0^_VB%GWrA=9bdh=m+iX@z2O` z%Nee1zPu$>|9Z2b4F)Cj^f;7N$0jr48#{^dvWh&je*gabdaE_n@v9)TjJqZ%bTFHf zc1y*ZV}srZ30QsPs06QtaR(5VbwC-sntlQhd5QiDcSce157$zG5he31PYQ{@a~Nxk zTmPJX2>ms%%4XzZQ-7@JEzi?-Kv;L`N@<~DfTN-kcLG0wi~ja%vK88CKggP){@4VO zEOujw`M<(nL#~g=U$}i)B2eh96e3zH@di``hhV{an^@1zGRM# ze^RK#Gd=1whrFSDVC9R_-$Azf4{;2EpyQy-*-wY9rKp4QYS*_Fp{gW%zV z;420gzR0aWsPmTHogb>C!tI0Dl~+e2g420U>{?`Jrh};{Tn=TKiH&i!rh&p)Apz!0 zU7a6jh6`BmXKx_k>;C_n@WS#{jx&$x{xWECt7N71LGzl=OC$oS86|wkpS$>e#x>XgKFA!9H3wCDcVlyR8MlHM#$Jv!jMb|HO8WtO)kon<88 zU$o2JvFu-XA=qTM`p5a$n!Ohw=JD1>>}X}ji=SL4C2rJu1P-TMX{Cbseiqkt@Q>*r zyjG-WK|aWz7l*b8j8>G~hp$_|-_}FDpTDHh+3{R&zl*)L{R@BL6hdbk!61_CAd;dJ zyYDSL|A~A3VW4O{YtMY!Xo~&02tT@k*R~&iA(rYJ0mEZ=DHAv0J1x)AOa02XnHfQ` z9N>*8Wpe6r^mNM0yXv$v0u$j!>gegbfZI#yzX?UN{}76#0D1%fc%g{EF@xHdeDHn9 z8N9z&&%jkd$Eel&F}x-pLdd2X>2mw6xg?p!xa$CU+cFyQT{1}iEg%0xfGjI~V$M9- zryffVlXA@`=!v7^%KzrJD4YSJlny|dvJLC)CDi0d@T*!xDTFQ}iknfr@Av4B09Vk& z(o(U=seR9Q&Xx7X5`_VPUsmd#lSB-BOw)W|;XK|cg+VvwsmY(_Fig zG}^kM8UFAdi80^S8AHZK8|+Wy(Pc6hyTjUJpD^g*p|R8KCq z-PZAo5|e)&LrgBO5LFgUao}d{Zkbnut)w{G)fDe*hEt^v_M7>e8l zYa`F0Rv!&?d{JmpSL`=NV~wXY1BEd4KaprpCJ=l8Yqfe2$KkQEv9vyVT;>bG%t2J3 z7kkM*)ic_YGy2sw;~@CV z!5_Z8H6SY?bSLxSHlx(PcADXNQH63hg}$z?LLAk;c$mZA27pd%C_7Te92NoPdd#8d zq!sxd%A=j9xNr;D9S)}b8Ww-MN0GT4YpG_w>?ejV|Q#-^RhZv?iVR}C~W~)m;%!&TJ26hWS zrJm3b{aJsoNAMwSyZjiFQobPTcb|7D`eo34eQ0!)dA1)u_sXqXWMMvTVSjcxlt!)5 zW|cA*9)89cM*DZHuka9SiZT9J%ckNFtUeU;*zrB8(94$CVU~24eC0dMBpWDT5jjR) zb<-E(4~rBIh)VI@YS3Q5$rawu#9^pFs95>6wWWsLTOS_xy?*v?Kt=7Vh)2_y$q$`S z!smQFj+ZqgHfi^a*;02!)M*1`HUMZ-0=blo^9w!$gNnqcYxGExp%f7_)uAE+M-`+tp&$iYUzgPD<^D@5h z781I1-O4Yt>h5_6a*DP&dHl(QD%XQqWQXyVHsO)vxbS*;$QB zuN!X`_TG#T4YDNI4!KL@ioOosH=a4ILhXzUUO(C1H&;RUQRnE`CZx>ismRa^Vy<)Y zNbJ-jV^OMV776bUjsFjMPJdP}r!Mc13*Yb!DJLWlhH@90s z&qGU|6z&^)GHJp_)jeqYM6)3E{g?T?LMze>`^pH0fnEE4$vd`9_AM=5>vV~cWPO;P zksB#ve^PGMcf5}q-QS|kj_en#Io}~~=24TK9Y>9^G@DEIz%!ISSwV4fKuFUo8lxuc z8oiqUjq_|kc5DgC$>+IPR0g3J8oTz=5T|Ub+)n=ZF%o>`vVo}Gdeh{>T|P+Dvpe!* z2m7X#=>hCzcq}cGJ-Xe`qoLf4T(Uk*dl41(<-jnF>YUK(_5LIwByb@C1p$)(zJH0{ z0T{ZtZ@61NM3_ewrJx|{8FVPEsEA$e$_A{!g^{b-BtG}YZ3%gI$kWqPMPV2!_;p}V zuP2w(+B${_m}=}TFiIs z_3j)RIdq@egGaMiq{>owtSZNf-ikBwGOrQ_h7I3`A)UkoS>*|A`f{!yQtLA^;8 zlRZI=_b{g@UCU+%?Oe+F?}np{cn{{LQ2gRNR7P`l{pTqz?aPY#V6_Lg-GQ-p6(~~z zKOV87;&Y>uq)8*B8vOT#$(_KUyx!GCn|p}?uo?BVcs>Nta6@JA;{5+pVj5x}maLrN z5>I`Zzs$sKt%HKYlcKm9GI7*=(HRRmUsIlbY3nb04=_-1NSll0DKSaRvtB9^yx-;C zbWvdx!l6lAn<7K%K2u2(L8t#%iZXCK z12EfcTu<|cx4@+YkEhQw^iwx97oH`?m3ll}nc*=RU9ez452 z?Lqk^RMO?7?w#3Gf3?7(whF}p^t2&5isX>U7)C+40xori+jdzXO|?C;?hhHAcly%6Wf3HoT%b^AN?=|d9=gtvZ3$YrFH@F>(;1>~(!51n^Jm;>hKG>yVbQ&xiThu6?X zDMN=UjXsXtoc31zdz z0n$>1^A@dov6wSyM1BM~Q&0WIWhvH34_w><(BFSRakN=cg?B-tr^B2C?gkJ;%v^G} z4~}iuu{z^yf^dg|QJgku3H5uJfzPdVsn;^Yf7R8LJJIY2(0 zRkd!oyjlmGkk(O?|agED{aZ{F+;gTeuteB?jK0voBvUelwR^Lz~ry; znYgF7_u2V&Wx|-&__~M;px{b>O9iq~O7Imo62+3LJ#J^#*!3S3$?_zjzO<$L<9NuJ z)a{!wbD+K={3~4GXl~%90?J;ytSj3aXduZ9kDDQx{`$ zQe=La_lz3-4N8~cLB{D3{7=}-HqPZ7&^4A{yw{Q!Nqh;j>9||%SK@ww?ouiLL6wQ| zE)4C1*M^K2bU{T7b^{G80o^l;R!)R9I&Wkcc+S59U^M5+`Fl=?}Yj$t<$m9sSE$2k>cL#E&jFfkt@x-+IXYc5Ua7mlred3?a;CL=|! zcm=(Ijz07lV?K!nW<5*X8dzLATaR^gx{9^U{S6C3>!7x3iH)yG= z+r_c*C-N)@Sz!c54R4qxvkh@3$$FJ-j0V0xZ?2u%xqSPTW~iK#*Q2F?(xH0}Y)kXH zOWE=0G<%w%bL+~kUkCAbd#w@Xz;LKND1qa?EIR#+lsq=kTP^x`9bqokNIG>*C-DKHW$qYBp?t1UWL%Ja80~4p~ zZ0z|%sl3ZP`R$sXfeYQ$W=Qdam-vgC24MlO#9l_nYFiCuQ!R|iUWR9R=0vl~gpm$! zXU!WKmdPcP>;VU2eoy7?D2ggDX4FM4=&C-JCqRha&;4C}$MyrjGa9EPrLyAA|L;yA zOIC>fT1m-)A)JGg)1Qh~v7ZVeCGGFTN*=E(p$7^egD~k)+J5*l$V{-rA``(mMoCHO z@LO=Ml^K|O0Ge!3thBVWvR(i0Aow0*%2LjGO5+}K-L(wCQZ<_AM%z&1cCUI5*%l^u zIURDyBcfn(JTu+T}L)oIlL(Nd*E0W&I#z=$RZcd}+N*dN(?)*ra^KtCvS1lyGpeshu+Q=rdDLcC@Xx@Z<^b&~LGo=9nZo>i1ls$HP`BF#RJ^ z`Ci9hH-4j<)*^YP>~-{QhUb;Vj92(&dEbWpqFEgnzoSF$A=1!rwA!2d-{>2z9O(Vd z`P`cq!4o@S-;K;JZb>#4PoA=If(D@BCZIe`!-p&VKQV4z%`oI!R0NuUmr)TacgQI= z%PK5D+9A9DOsT|9f=D}7ZU;s(b}Ds9A^mBs!qTKa-V;y+Q1ES4I35KCnk3MPXogT# zeHi$*=6pdc4xjI>6RD-n_#i0oLpUSNrAXFz{t)6FpIIG@Zw(6lwHOH`;gH($K#t-R ze+x){Vq_MNP)ke)2Yq?hJTr8U@yj-B@9?mfOwS-<&d8grCMb>Wy`k%dreo7J<+ZjG&8E@A zVM%#YS;jAq_*V=`j9gS~EoePdwduquvV&gxY%9^C#uTMIw{RCo!UMmxmJiFF{UzgQ zr(}I%8uzqjt_vx_h~fM^^ZYwMUGXCh-m15hZ190emE!9;vidUK3T|S2?#=<#@cy>X zp6v?{u>gHGks2RWAdFT6D0N1Xezl~Z#B%7wVNWi1@4&c>#8fBOmc!OOej)SA zsuQDV;$Xy!HDvr49JKg8>uxB_xZp{KTo=*#x45_R`{=3?Ur91UDGHw9Jt%vWD` zckug5weSI*Wm{%5ppRf;`CR64SxO&wb=b<{axx$8k||}Y7W_x_u&phw!!slEi)uFi zGs)ocA3|8|eZQ|ExUOLi@+Tt1u0>x~Lr*=)6J4jibEjubc-JbI%(r3n7H0=<#usSt zUQthb-E$F##LD-iF$?Riu~dUMK;R=R{wBy^KC5|jc4$>d7FVpcPvLd@-FF;;n0Ac) zcSN_RoC)yQtupJX-gbM){ud)LTdaK`NP=IXB4+@y@hpbsh~dFr#L;^%kvB37vwYAo zM^DE(x?IXslb;GwPrgi2?`(M}=&{Ycu?swKFeg{t&LKbF#V>nZUUb}f!Rp*C!oPN475yj+Bb?F9{cm$a-FAG_(Xz|Cj7q1-|cvOFnfzb>w zt+vE0Ga78sfoR8&V0M$3^rvTg>L-{=5#6t=Tb3;i8h7nA6AnY{oP8<2Fw%^9s;S|p z+bV3fwrU2>lH9i6muAb!wci@Bg0qu`srC^ROM3S#v$79~&wt5kyb@|QzW7!-k`lA^@3f^chJVtQwtX6X}ObwWelIB|ms5Bp$?s)vvS{X%sNP zW+x{Dj+dHE52j0jgHHVVXrX^LO~{^raRq0)Uh&g%1ewv$lE4>))wts3`ByL1TT8#y zPKFPMS?pjb;Y>vWGis|!jc1w>wQNRB!d=G+Rd&xdD-8#2o;T{Pt~4P!mr>6_Q5cZK5i-DTX!{6myY}{5c@XaGaDUA%VGuRr*kwTWKjd$Wrr4@Kf8}2chLk=sh z@YO`}R-Zy5zG)erLUwO*^o@Z8NPCq}yW4(jYZL@}0E|*$qq~+sq=FTj$jx3)$I?)! z0XgFi<9b|zlTIZhPJn9O$H6l(eP_UOFN=QQt`IqY@dp&2ez4lCxp2At|IUPp|8FtD zz&|S%(s(~5Mp}=$U5IO~{qoKJ-E}O_76Rl$2k^-zh3r1FyiXZlT#NuF^Lxj~W``H2 zCPgyQGHR1_*lJo?9bJIZiF0!^)7#@OQs+H1KttzUk^U;py}{}V65^o*eZvTijR}T| zJG3z9?$1w&2VjIu5NoQ!U!gUtp+qSJT}1VHlCxydp;w9-{JUy z{I;eIxrchi*YG4hDKjcnuF+8`J5V%Lz6FnQ$Q!-XvEUL-oQ5KFwT0`_Oo{Q9nlB|7 zjk%}Vd~r+zauBO&(DaoG&;F;ck$dotnXVEYOb(4BJ|(4JG@GpmG6q5s^YJZ)99FF> zw>C8yzG4V)^};XovAXxrS13nj5^d~&}VHJQv zjtRYyw?~xS~dpa#`ib25}U@F4;FP$8; zgblxI==WSdI{y=XH7D|ql4@6jU9Kw&q-XHE4EujTJLcl_YYIU6l>+R)>XmfIuNSUW z%A*6TLO}x}c4P~7R@SzYo$ugw?jy`x_xtG62e$w=cdL)e-WgAMT-;chbWch zZJ85g>`Feg=r05DGdLj8+ig0bJ+I%KEf|V0t7Zuh0f7$T$7?ODttOo~=6TIg*&2eY zHp6;XiHbRUrAoAZDsgzqkwLdHmvALp8g3pAW;sC8K{Rk7 z$^r@P6{}A2Mze%vR9|hh*^80*dZmX#bUZqU{)>)NRYrVKq)3x&L?qR2S~AZaxr#*% zc!Atm%MlOJ!Az(YIC!LZ4ZI->m=hY;PI+Rx|8Kgh>}6m5yVIPzSVQL3v~MI_=s6t6d_=)Y8P5IRkP3EubW*7|$J~r8V z3W|>NcYEorzp*OG{OSiAHLxYWJGHm}S}LVAMP|lC9WSvLwv9pQ-zg9V=?B!DUvh*; zw(O}1r5I3Qw^|Siq>quqH?pWuP5=IhS(gO&vv@i>_cLbZqJeBr zQkTReSGle?x4$zp#YJ))X0s(ysh)+a?dDXM9lSI_uwaGwH=)!XJEGU*jY<+nDv39C zyyj^R<=uAJc_eH-`&b7o^*ukl;^*|RUC%6`q2j%n)0?jI*N@xp4XNKFg`b>?K4iN= ztEg|i= zU+>~L+rhuF3~eeYV~tdZdO53ZVy)|HL2{Iz>uOi?s#6&FB85W_Nw=-YHw zAy&uTDX@i!e=RQ5n&nCGEJSYMJ8R;T5Dmye9cGN3KUEyjlrSN0MH|GQ(E1;2=S-g! zU)(_>WDRFd2NApMUXCdD$hJlO*@w(ms|&ceO3~3~DiREb>0+XB#8jcTw@TXC!qL2B z$QbfBs|hb7Ybq;fEgc;zK5!IeWkH*`o7z-w37pl=#&x&v6eazV5(w9qFO)cs=(J!z zLjK7!0(i+K3{S_5pbWE`*_N;oq5)q;?#oWfBrCx(r`+wFiH(@Q@eNtno&71J!Q>WH zb055MSABLFUxBBBcmOU>Ux)(0!}GYb%bq3 zV?yuK*MSc%HpOW(>@2jKt_rGphdKuK$7YhR{t|cG8@`uCU=n@!R6jHSQEXRCD4xF* zkLmextMY*<`zL5u5dojKMQ2t`aB3y`B=jijLM8PdS3WQaa~%f=ji2v8Z{OYltFYm{ zs3{=fMf(`J1Z>8*a^T%ZHSZf8#yuFOJ?y?4GISEkIpo{)hEzLTFYMM^GOP&;5B5pi z;K+5EnJG_ya&{J=x^--+dD1B_uM`{ec}d)Ru`@A`=s;*gVgz_Zf!EKH<%8(-&RX#t zSrdW?cBnFDiUqa(8yZFckEN1q(LxRC5X!%r876p|0S09 zKC$2b6y&$T1HzfF$Yxs$@+2*kUmtxm8Ba+UW4n`e>sDM4nz|?ZT|sUc_I)~ap+VNu zbB3}**T?Wx47DS&tKbRgFgJ;jma2}oZFK@&PPd?Ue z(b;<7`rx)P+AB`LOH<`yY;kd|P_<27aiv4>`g`P8puO1;cKi2ap^wv@f|#R}XeYhD z|ExD$_J!!}qt@N48kP=8FXR$_{ZtyVPzeuW#LULgADt_$to*$F-f-0+t%WgmE1w}^ z43mk8sRlMbFQD5;gG;dok9Jdg{IKg*qU*qye+k9nOyZY$HpOtbyhFssl>L-EmXzB{ zj=@M*yYR*LnDT{KWXaP{Ew~T#g{`>s)u)HIjVx`Ss;hPq%y-f~Tk}OL;sJ%liy*ji zW?yblCaZPc{yzLlFx&@3y!;o=CysU{m0xlPRqsl(?nr8WCvo+;eBq#ptCi{o56d)y zPawW$rDztum8^vTr(E<;{0F_Aa}2 zcJ?=R)%z!f?udbUv!Rpak(1Gm3m-bk6|bM{kT81s5|=Y1l1 z;H6w`PVT?E6ANvHsdK~n^|mLCv%;hd?X;u3lV93KuFC<^#R)zJg1Z9bU@bN|z6Rap}=(xrd^j zoH{uHrkCz~E7w?2J za#FKNeIII~-WZZXFNpv3#XMhg$_IBLUyMD5QH=7I+dN)9HCA=@?y!G^M9%Fx{+iL- z%%)qmeZOLVS@~H^Pd~yJwYzp}yl{7mG;m%2apxPNmm)sA*>Q!m3Sv1bo5qnKq5DYC z@A<_(E-Ci0vb$XFJHhm#r==&wc)OOn?Kw2PcFkGnWCnI`HlB)?d!;+O%i{(b5%^JnSIenaG75Qy!u0`NMdVawZn_+7IphZ(*X{OvIP3DHT!h8?rva+LA z6vfU`$nd|+5RkAZX635$LYe$|0d)E4{COSxMjYRON-F*Udq{!K$*nZI9;-gvXM zo?c4TyHP1WC02e`#hu26h8AYjo_H43z&2eeX^A@el~^2)G|_fqybre7a{lh~k7s$s zp>ty1jfC1pZ=CHvSvAcaS9clU59YF3hFO}lMvXvA`v;)}8@58Q@vxD{mE4CQXKyq( zMm8Mnar1d`^L{yE7L~aRT7~AK_K9pf?y~*LVRAY~CCSxUzUL3~#(nOye4dYjl!G2T z82ATUgwAXrh&?2|yLY?M%dGxv!cnv8OyJ6HI$-49T%TBzAF9#ymHXubAeg$Z$JBF{ zvDTPe-yju@?1!3P!Xn`(bZyKf3ROQ9t=vCxC88{`kuIIYv0;E-(xuQN%ZOJ>ePLhv zHQ`q9E|1)Gazy1}@99`AJL>2*z3d?HPs4Qy9+v5K@gTtE-G6q3np|pMfo(xA-x~!Vi+Id{S0q#DP-FLM@4`pUuc{3qT2vl= zI}Ve1=q-DrKdz+}SSK6G8=}-v^};zGq8k|;@B8a;_Ty1cFc&vS{W&ytbSIYP^|0-P zmO(UQe+*ynbG3u**k^(HSz<&)WU(iP&;PKAQ29??oh8p=>@bcPAnqcHb2P$00C&jv ztA#PT_CJ+jQWL1Eo=%^gVBqDHJam<@%>+Lh8}~b{(Vht9M$NF~8g< zP?vu|y4FDZNsQJGh$QFk>5G0Z-sPfR_Ke7;YCw#mzEG|;!}uGW)iM42Q;Q2QaUOms z57B=JNr?mce+fy+Iwq<%4BrjBFgRk9O>b+QnTm^g7xh9-XVeDxc^@p^%-*EIzyx;a zNe-8rbRX}b*bZk2Ak)hj(9)=rR^HApY{ZvijAt|}L*-=!OG+(O>kAZ4wWc{M4@A>w zn4E&DppWD+*Z<%jJ|(LAI{fOoc>SX>*O8TEOf6wu_kIgD8>i$aCFH_y1s47szprWr zZ;@u!5csWAN>_Ovi}B8q_btBD*|}owmdi!%wJ4)tE~CE^PIj!EOXc}_2qb5P%c6M+ zTD%i;)`n_r^Rc=>2G0y`cFvAGK+SJ;VM*SvL%7~KHIcbyfBaPdUUZ@qbg9TkXDVT$ zOS@-+R=fSCd`nC`?`toFO-O!o38+9x0|(iM z{u~Bz<^Ewqhbh~TogB>d-->iD2fneLSN>Y7%^y$_#jw~6I(X$0^gVd?Irq#vfenH; zZ{lCoXUH{#-+c}f=15FT`@v<@?$-kG^^Gz92GZEgVUnR!e;xmU{pMEWr6W$&y#-Me z%T%J)lw*YjSqy6P19nds6$5~L;>T#ST%lwtF5zjGX!er~<~M4^yqgwg&7gdjUJ-R> zFfpG~lltMC+s(1Q;QR6_^l=*>{ZB>iJRqSAMI-yipT}6^K^l5%q0u>4r=J>WVJSHh zN%4x@S@HAEY(sfDm!YvB*Zr-mWtuzPE~Vvj+mixtM(FG^>&>GQ9lQk9_{6YH7_tm< z?czbuCx-Abk2;k0acK*zn@WUA?E8A`^R)hH7uNMbYh~;=K2)$9@5w=oby;-pZTW62 znDb7>UHaFbJhBt)MMmW+CnnVKM~#g(!5$RW6TNvO++s<>lI=u5Ku%WMQh3V=at@34 zE`(~mkZuhLh-Y*x?4a%>A{q(WYuKN1{4{46I$UU-ODF_QuKRq#HH14N4#VpX^j;ru!R@Y zVZVg2&Vpv5n@*yeBw%WC7dc>1rK$@7jc8JQw009GhXrpZN}kTW(_8nFfS3OH3W?&U z!rC>(N_1|*ZiBM1TH7*cn3BXvV2lzqRM|YVlRB81bbyP(E4IQH0jC?0MDuocxtzPz ziYgYWnvN{yUebXb(s|F9qTYxsdf89x`!?NwNP@T)-~GDOf3o0mX~C`#!{xjv#ISLX z>-%l&kY3vtg=7Q8U4S>B$P}Ch=y5EKt!t8>^R-sUZw%DDti92oxE72(arbYo`UuTf zqzd>i-so#a9YsA(vOzw^++t-^yvo@jC_Kp!FypvBUN~N-&=8k&TGZ~isj?OtAdaCc zKd}(2$CIjuVLmboC6iwbyT@gF`chp)*K6RoNlTJtYFx6>yE0aY0mTwC+EW{$qJZ2_ z3p*mD^F5htF2|GVT$`GLw%SYbF#+7uQ>V#Ttf_{&Zv)bm?i%rO+uP5^5@o{^qef3$ zT(Wc;lL>Ya?|ffggtltC^fBX`2W1ss?E)7`t5YPVQQ1aIg2DZ5@r>c+MuCC1d?c7t z)AOw-L*1!`BOimQX&MhC?AEQxK0HcpAAS`U5ozj!$Zu`q;n`6VAW{ojvoUW$W{ArMe9ynXuY+2G&GlF=uf@z{I)IY|9+sJvWm zS(yqSYiW9NRCxHuymH$raaDC?y0~q+A2hA(v!Hm##WtbE>r0_`tzU|cDPw3QhI~S2 zXLWT^vRWkYS_K)3<#}xXD36A6-9Rinxkr%A&Ni*wc=%p%`bBR-gstS?5!r!%wPt3Y z5rfEHjB3JFwGoPX65H4!2K3Hd)KtShSFg(uwRKKC?3#_@^#tKZXS4H#e*y$o$6du{ zSoL1#&5wSqK_EkPO2A>b5m?f-nH)w_#v>@iaA%Q_9+>EPGVSA$i+h>0Vfj?VoG8Yt z6-#zBBXG>fgZ!P=?#4h!tj6k+r6>>dR8a*4pAu6CZiQ%r5BL5dN0kn&H(J70z9yX0(Y-| zObXe^<<9m~|Kml35BKM^Uyh!{c=P1k?U4+M!3(7M@kcFtdQ5b1Bt!uN_eFe4N#V|Z z`100v-nZqgJ5nfg3G-zpvI67{1-~1Yf}9SQ0~$J1_BANQmQGF%j`3l_g4O*}61i`> z4+e{WexD{#W{kddoPL-rpsVSeAi`BnHtRN-jy~HW42b9G+4+epJ3Ez_AU?IV*ZJ&r zAE-s)@F!ziB`l5lckm~swa;fwe$>VgyrmW>*X?NAen%zp3)Hix|0}k}p>FWR?yRU1 zB_+#*u-KtW`%zL+cAQejEUs7s0eyniArMi-mnmQ2kMij5Hzm#i2e8(7=61vwS8^40@khf|$ zKyoUN7TOmLx3QQ2)oZ{ec=&rsv+CcsM}2cux2B=t!dQdrlsT6%-qMT zgBc~Ir;F8i;vDt4Qs?qiBhcT|6UNdsfGUZ1VBlV+@EmXP3z2eecMzY))- zAd1Y?AoU(G;AbULt|fX^pX0F|fBp8k_kC+%eY+`hW%UlpMzI>W&M6bIjPbq=@evU<2`5!Gwo~ET z+On~3){N!1U^U2aFR5!zG&&l&Y}^uk-ga2gL10sAV+nam+lG%A#HBq7A9qIuFW!W5 z8O=g$eCtq{hp?%&F(ZaQVHONuN`Vlt?+T1`PM=;RgfXcrIOc0SR<=}dOwY&wGQJjz z8%j${n{1CARr-~=ffT1KLUTZ{hltl9Dl_VAyXm)=iKGa>zv~m~@}D#G#P5%#Gl#gB zbfE$tz+bR>>CWN!`G&=BniQ-`~`Q5p%5A_fo7tZv( zmT)JEIRJx-PL{3`AX8zhUt6+PiF_!Uk(HLNvK6!6R!Y*P?i&p8czXvQUs(xGr0G*{ zYJ6@+CtZ%V-S6(!7Z5zcR6_2I;^tn(XOd9v_r|#`zyC(=gn|2V$BAN3cP6H>{nUbi z>d$ZD-wg*wkkp(vFpsm)L19;SreY2zDHZ*IJWFsu3BaPn6DWVW{VDbvwTJ65E~}Zb z?;UVQ&-Uev%n=diF&dhK?~y2rcV6bFX>=Wzc}*x9`_AOh!geiTA7)%vfp?P zjha9UsDSf(+}VqijGXO14Eq^!_8Hy3T@Mi9=lf$Luaa#;?jM=Aw1dhpT)$SYu!OPb z86d(f4-XD(Ecb+yX*f=SAhUvE!e9MloD7(~ByVP>ZA;>|`>(eCHbm}Lc9`2-^APwkZM5GPVX8x>b zijOwuXqzO&%xtThVwlfnk}H#IH83@ELg{HjRHkZhCLemy*x;a}XCh$2SV;2En63Qr zZ1+W7vaK`f4JlTo zpQ=P?bj`-*q#6qB52}Uqu@cl55f;XRUhczAS&?1Y-@r_3zl_?^@cUQ$`o}oDcQ@O~ zP%a8eRMJ?Sx*vb*jqXMb-E{sX7q#}CosGMDIu_0c zSf7;lwS&zHqOg{ZSHj+`X&6WtFA1)!3^ldAh^1qdyVjoowrrni6_u2(SNl9Sl zzY22H`Y!iL77*vw^y62PbTlM1FGCqerXgX{1)Li1C(21WFPHgVfl1Wmtb7^f zPazt&$he(hc*-&O`rmebiPD(LaDnxoPi!x?K1-c1EiKtDZR?Hi3A3^;$NM^G-wi(! zN)@zLDU-A#)~P;e?04@>fADK;Y|QlxGc_yg_t4{_YYLmfm~;Tk6&g=T=AUg>W(|O| zg#Az0tt|v7J>hWzHWj_CTii5CF_EA1bo~_yN-dHN*B{x%?!(cdTq%9`+0h#R)*;Zj z94`KXvo6M#?(TnvlQ?>ze46pPrNn(@KHl$JdvqcdEgSdgd@n_ck^TK$RYPm-PW8va zu!0%J!Jnolqn=;XBaM@Mfgx?k_y(k=kIbW!wO_6B@ zlAAqgxY3z|k=qXcDvK6-^5bY#><{Z~^0y$fa)zo8+YV7;@;jW7%hFN3dYTr)ydJp` zcv9*QiPI_7J&qWwDvnA@JLJD8spb#?A;?Fn4b5LK+yA~h6M=Up_IIzUgO`bh0vF2r zVfT^IF@&jqfBLod*GPHk@!8;NNJw)g{Xz2X;MLtM>e4yyn(&DoUV`tk2BZ+$WVaI0 z>a@G4)D0zm^v9r5oPyZYpDJ5d_gg1IinQv^DR$~Q<3?d|a~Z@*4z@pZj;Oz+eWdQ9 zxNcF3sXWnndu%?%>-2}oW}yxfRsgOSG5QloYL_l2hQ@z!kNc`&Zm$X%OR-Xu7F$p6vY2q{_HQDWmpR|kkw7fX;2|hl8U7YQV_R7lSG>z%(mw{5n6xERH zTgT$N3^DUphMvdxa&niL4ahO^3so+|j;Fn$gysO1bz7x7KR-Y2DJo>>)Kya!-Z~^S zy_AEah_}|Wd2y*M*TecNuc$sWxIaUThSb7Kn|U_Mn$GX~JS7`l<2||bEW{BJ8bR2- zsPB|`EqAMyBe~Lq0@NI-x@hn_7)ity7@RkU8W1mVRP{s^+zDVngY|TEL$(a7>MiY> z+Wq+go0>jnpdiL6)kZ0S*wcjfBB<@*`{tkPvZQL=9(epKBG$97fGFPX1mPO z@EaXCnMp$Z_=jfP_-`nG0ip2TFK_B@UMC%W%~?IVVzu$ay4%~Bvi^lannMijPja4r z@iFnq?pcD~z4RU%ly!rC*R~N|4%yY6IC%4jTwS%h@=-BKktRYyj$6M+y@8g%cT%8=~ ziiz;EpH2IKZdRN#ap=2su63bxK4I0`JybCSqvP+a04?}@LgD_rV4NRY>*~T`Vsblq6h44KU^EH3 z+J4!#zvgpDqqWb;$>Gfb(%4@yKv{>b?lr@Ahd|sVN5;)SM@4LIk)*o+zJ0-Y&|W#B zgLAB>tKF(v{S)`(N{_l+%7kIUtxu`$GOy|Pkk{!1-HM*Ib>#2Dy;Tmy2o3GreG%P% zoyL<|Xja1sSEp@A*#f^SDnE#H1ZsMSu?rFTus#MWc1SHqz~RHpb*;$|x_m|0 z6;S`1GPKIAUB_8JUVw`an~aR?3>ylC+AOh)?qJ^`JA)xpQ?I;<#amx5gSfg@sOH0*?!L zNhiT07E)dv7pJa$Ewrit`rTh)ySf}I;om%WN^?so(vJI>aU72cUXw?-O=aIP;o=22 zrP%t(nh=V#Z+g73md2{z#X6B^n{m8o4)N%<@O&q?dKT-p#%#Qa#;2E%keJEa?cMS9r>$gA4bD^avMNIt?rl1n<7duh3)w2eWx!@ z57#_4j~?%rqZ@Tq?_Vg)?|zHga5HkW@?apmdd@MPNyGURhUQG``wWIgN`JWa6%iUh z*xgU-Ir2)KR&WT`324a}6*CRKIk;_M@M=8i&w1BtkhuFJ8}z&F{!5(U-RS{RJMc2a zNb-Hw@pPo+2T379wNyUS^flm&8@Q=Sm3+Dr3jceA=1HQM_-cL}`MFss1grX?zjISG z_~d%CQs2S9Ci5K1!^ii3*gDIwDBpJ7(+DV?5<@5*A}GxOQi=kKfFLD}N`o{*N|&T` zhalZG0@B?b(j7xiFtZ>3@B6N`*Is*$gRk?2d!FaMuJb&9Cxw=Mt;PddpPQ!(Wj^nq zzA`BPnvpl0d*zMm#6>Wom6W)%ZoFdfz;!pCdU2vXt)n`Q)CitJS=DotFHq?ea> ze1f5*l=9%8C70WiDe<4-`=hWfw%Z|ZD_D&0YUHLOz|?w3Au+b^2ygFPzVupcxOnA< z2sdn*n#Pq>eZ{a2lkTmxL4fK-*_IZLiz!`$P0Gq(wK~Z2`)#k=`!D=$A*M|26G?$D zPh*X-?E*s3)>sOq1l@@twJ(x&cJ@1#f7iX1gmf&zcrvb7O3DdZzypShKj`6KZcaZe zxh7ZB13gbSgtP+sLA6tF?=sqPRcTC3=j2pTl6Q>Xqf~YQVVQADcvSvKOQNZBu{lO z^H^yY?r&O$o8A3|oavwKEDQO#qV5L^cwL*KQSd{ixa;GIQaO3UD^;aL?KP0z~*8~Jw*+V>=pt;+BJ-V@huCA>x*KQDuvgRE_AstVxqqeJsr z+u8ltr0Nduct#J(pc{L~mJ&rpGJ|B6%=Hh*VHgyjV5T<&)Iu(xK9G&3o zQDPSm82EX|7U8z{>C6IsSxdUu5JEOHwbm?sv zgVk;VovzGSxJivot3cMiT&qg6RkK@W&!KC?Y>tw6Ap}+xAL-5E#Lve!s9d@7BXV1EB+P`MJ(N2s0`z<O=(;LM6mhOu9T0-`ff6CaHa zgRAjDeVTkJR)Bwy>yUDLcQ?;!GEio(>wCnrZd z+frd5Qn_OZ$8EX|?z#q*V9M^%>>g?!OR%%!`22uL3BI=h{fUnL7`z)@`EG2nl>d8F z*sGw2rgs))S0?;78?9+2`Nqca*CIA%uTI8#ZDg>szp={Z=5Wh8RFfyZ#$IsI6As@ zb8%r4RENvKF3~op`A-6KnXx=@WwB^Ov&4eZzgX?t&fehBBu^3dlUioI(2Y3YSZ_uZ9Z+$EPl1Sj5IPZiUpT zQV$@Oa-2Cv9$Pf-#HrMU&ndQEUp)cWbzKz9ZI}3h_w` zW++5A(!pXTsPxi+=L5>H-909VEQzOGdpCv4a_)ja=TAyzpO`**Z@*YOyXUSZQq0TQ zxyH6CWj?XG97g~2Gd+vvE}JxBH}5kzWh-RhWHhE9J&U>27*#;07sMh3b8S7p62Rbt z6&&x5V)`0}*q%RyMUjI*F)8%O#`4nA2#QZZbB*t`;4K3jA9pohGEjxcbU*z2Wn`OI zbb_mp3}##U`&3~m)+DCv{D3v{nRc4QdBq<;S-#kKa{ti2J1&<>*`4e|K)H1LUrM9$0ca|9W2G>0x>D<`!uXB)XrL45BnI4h#4gP1HV68i>*e+x7$0lX)?Xx}E9-%E%|so zoKQ9hIm#-iG7}jUIc^F1YG%JNPiNz(RHGqFAaejQNSxchmi0dUm$|8W$lLg_~5Gnnfbe(+k z-Z!*pbok{L_SH;}ZHA)V>m_G0j(Tj14&LaU4tdJ=?f zk_f1;?Mr(md7AQ0#P3vq%U6>x-iz5QnkohjCx9uey1PecEqWpuy6)7@HHvf9VDuXY z1IHMt%tZPbhG2xINRoyVuv!rQb79(dxf~SC7V>{$RhfiNjhiaGwL?23Osu4|; zJ)1q#?>gtV7u%DHkt&ton1UMN4l<&=bNeq|$GuKTpb4JP@+;^Kr&kkFzkJ73@o+(w zhKqOXq8)STgC*H33d813>fTqKfqwXVFOq}&Vg&i!3S(%)&ts~+^)MZuAsxpM%0R-y zpR<`yKwKKWCdD&U@{SXe31QX(wLw`7TAo42$AU~ZpC2A0I^518LLh;9bVk9MFvI4c zRiFdRa9hF`<<6x593h~{s;e`2;G)dhXo?Ot%Fn%O^39JOKD+QiI*7OqS(Nx~r98mA zl)sI>*zw!QDtW)s%2iaths`_zi0VTrjU9#l-sP3Y1!PyjRWa>o)lmre?E13a`wezE zM5({DzI%n`;*tH=GYJi!yQwD-VcvVnkRX-{WEQQ``*w2(KnepnVBV|E3lBam5Yoe^ z%5izwauSWzs(sJq=JRX9L!bS8e{DmJ#UCq)QZa5Ql8^J^CN98eCssE)NJw5 zrv6Fx)?%5<^4$tV@*Ngw4~*kEh&nue%zQgCZ8)DuIrTF&A%T7tWC>L?1Bw%S#Euy% zywrueXso~J({yX}J+lX&e)0u@%Wj}EouS?>Kx>6O<2RjEQ{B1n^~@ubzc(l0fQ#nVIorEKEJdJ5AJvvZhsz)j2J{ zkOLMODnh|1W~b=uE4w%{tj&*b*kWGY@z7jhC!!*m4XTu?CG2h2iDTn2a~7R3S8%-^Jv4`QM4rdD}??ZINe zAWr`}B`qrJ7DeZNcn$5kTy2i}o}J*JF$0gd4lM{;DVJ&B^TYfE&<3ONnSbADzqy znn}g`Ba7*Kz|4aYFK^mM_?C=8r7vCN&LKN(4ez*DI4T0u?AsO(yqosk#7SQgs#9mi zoK32Cr6^!-kHYU5MuGYVRZ(wkcA*bGcRrX8tl>}Q+ z_t1BdxYX2e4e%{B(BjjMTcy0`ZnQ3p6X#&q>8dX-F*WS3ptN;hM~ z$IjvJ_)NwSMw?nJJ|Ce$cG*d36;L^6&uwNw%{h z&I|ExkRZ3@w$VN?kuz)O@#ty`&E)x!EEla%r2Hz%N~T-^@Zq$~_bF~uRhE~K3_?HO z;{mzZ-h1+SRZ`CT0-s&xr{z<`?V+W7%W@J}U^WFWU98JPQMb0MT z=8KGGk}%c6GM(XXJ?)HW+&<8)ao*^O{160U<_PTtX~sllJsMA1t+km$P9o&z?znPD>L;t56fkNY`wV z8~N<3AM$%JR>-jqJBo2&CA+g-$b z{GF0+?I0TFsLW$K7uPzr#{=a9yGMJbNPtXG{PSns5#heKqGJBwL7q=D9Xs~rTd`b> zyi84zGO@Dpx{Z&}$3d=YZVA3b3KcZgRXyXP zZ^q+1N3_V#dT87iT2oSE1`af7#emV=e-7PwkEjWN2D_5?3;TrDVR0e+E&yx7^ybGP z23b`QWfT=x%On1UaCJV1>cQ~F!>V0t={+6)!t2`#;I8X|vd{sv-ql7lVFZ~R5%3A? z2<9$|p_y(iV)0Pf*=M}(^2%?*QCQ~489)4K`>t5*9XS~nS67kgOdWhxyetZ$Vih$0 z8+gMP0SCSswg!rmwu-w33W=yRVSAR&d+jM?=TFGkF}~hFAz)fb?Pz{ggkIzA&z3fJ z?5J!NG_Z-W*nF*K_24OUxD%_bLPxJ*b+j1_%@1apXlR%`f3&i9EoEjv2CJE5PRPhi z5DGw{j^?Z&?ZYVv0UkAnmIOlvnB+9I`PIdW3QJ@|C5DD7&mLM{e8U2{IQh7QOPZq) z5eJJ=4I;u4%r4b@;!t{elP9!(rUL#DIN4x4tNT5fMd#&NSom>dpSO-TB&1ZM!UcOyPYG1KQuG4^!Y-|mb&dIs=S zYiZ@lhOY1zlsS`ZBOQa;i2O#?&(w3FxsezHcbOkzP&0SgM|(%JZi|N3QcLkOgsi&u zvG#(;@nabtnzk%VmXmwaZSQ=uPyZ@q16fao$IX2q3ZfW>GT5yB3e6OPjtyz-fB<2R zno1tVdFNOai*1q=oNdDS>Y=?Xa2`)DFM#As4p?4jiwj_O663sQbBx;P4o(8y}`X0k&gK*eS4)jF6GHngCsc5TOi zxpVV;`@eXs~1=vNA+mCvrgVRBs`WVO_$ z_9%Rmsa9QtJIr0u zAYcgLnuy{2Ms$qAcm%vkE5w}(s~J^>ZhZBERCu9=iy*QleNfF`AY%#qF;EwD9%Ju& zVGE7*Ge_%u`V0FC%d2rH%l#Gy@#JKG*3rwXi?#2w5F8Jb%@k&R2M+=Lc7isIcK1Bj z^G=Qz>-h5CGgJF*mm5EvYR&y_{qUR&8>PtX&0G2^@f7D0Ww<}^wu(tguu1W?UL>QH zSi==;P{<5ukPeNG?%@-tnXk%iP4kB(+kS-ZSPh$6$`Z|P#{6a|8pR#_ut>U%JQ4e7 zL=hv6W8g|NSW#6)(XeUhLv;kEy6s0U0eXjB%oNUVs&UDs^s_HS$&J_jM0XO-;@I<_4r@uibWg5y`hg zwFuC4(>7U6L^__!C2ATs&Kn>eY`8Z4lmu9sOY+^`(84dQAjo;5Gs2mbKxqXF=#Blsz+zlCU<7bp>XhTmRQdEhG0+sawCkD zhzsQ7uU?^n=FxwQ@G&-W?K^-C^I{DffFG$m5q-WO8bSA#3aZmh29nEP=k{k;qZ#4) z0Y7(=6o#N5eMzF0uHDa&vs{QY(ZaG@^e0Ya&2gBtWc5jTjDtYYCIKN1XjrC&? zNjS()Jn#B?uL~~`>yW%Wy!6^S&C|JbVa8Ca^y++;$Zeryn{TGFTE{r-8KSP-!~qA0$d)$l z_3Nh=%!EfO`koY2$)V-ZIv4sJ&k)kffqd?7K)1nc5$Kp;P}?=jxl&R0E)H(ZSV1&r zmIsToko4fG5ePM&@u6htobF;jAAGP%V~#n1ICOR!Z$^j#QP?wzFNf}mReoz6%2CZB z!JZaY`9CT8r8zjr0w8_WH&%hv3>q1<9*I~&+WJRFT`2b@HOVHP_J=0 z>p|8t1Xe;U@S)#zNMZi73G(MGRLa$OfH&!q;4eocBE%Iy61~z8xAIo^WdU8pNt*Q6`CofFN@W-vLvh*`8%rjSt5;NgA%6C z=%0LifXw$@`@<+)V+*o_&K|cEI-*?rc=|fZM0z+JyMa*SDNotWbcXoB?C6KZ!oVA- z4d%lcX?b&R7~cQ3P(AWl+LCBuB)rO!X3&vEAVk_!(T-U$?MWv;amL^XV>%=J^i&vL zI0NU}z3Dtd>{rII%K9=R!;cS;kKb42&UX+}`zLsM#<%7lZUpYq*5sviC)QMN&6Q4 ztYvk1o^oPG!+5PVR=HKzh%i&V9){q!k-8;%GR2W49h?&K?(4gDE@CN3mF#l>7GyH2 z2`Rlo)Ofe8Lcs^dzzlEzL30`#$UrU!DoS%sxSTvtgjs{f2M3jL;aV;Wt1B6c8E>8c zT8=w@W`2wwah%K$u^KVQ+X8A3!_P;-S>GQ{Z+FwU*Rsx*;Z%YL$+~wiYaAG+@maCC zldzsQreN{+?_Ng2(yEL&+lwDEL-yo!6w2#24R0Z9`p6~w*wxmG?1J? zqy4Yy>KEo)mbrCxG)aATUS>$rG>MFM0y9T6Zj0Mus1%IsA*H7!8!x(VsH4L7l8?)E ztpa@wrse(Q8zp?;v3AWR=<3CsNtw733kk|GZrf4BL7#hlL!DDA2Mta`-}D0t&DmV8 zWTd?pJ>e|R(cajV)|}o-SiP*p%0(j|gu4natB!4I`Y+=!^ z-&9Fa3@e zx?x^>1<7+Q!N}R1{(M{BBZeH(dJln9e=$SH5Qice$$=;BqoWwZMy>W4-Lemkk2Icr z5uxwn%X>&YAsD+BKgKQ&*VL5b>$w!(TTlD0(ROu3s$4%V`+a_M;Fl&C#GIUM48qTQ z=W{AKHWS5gT8mZ(=bw7x;dny9*Vx>YHW#RAN=sC$`{9IIBEF-B^dD>emudqHTNVk0 z;K5nsEwTnpRE-JN!I0p=*Z1M20$JWy6v^892=PTBexRIWKz4N-xp2PVqkkc4*259W zG|896ht<;D%=Fe7xKfe+Xc9K-nQNciZFx?Xo<6x zSH2Jrz5tPyUeWDm+haO#uCJR1B%+QzGb;wQe(82Kk?!yUiobBUX2&EUUD^8bW+x7kTMJ5;*)QFr_t*-n z?i!ZhKc$Q{8=Qd7B|u`JXFTPCJl(Eh%b^bbnK&JZU9KXJUX%(PgbT;LleQ45JhO}a zYPvNeXn7TXK}Y>Yj16Yr-9wsY{|mJG7!TrY@r2Zr0)2ZD<5-zb;6<8L9eVm$mzV7CswB@bWJ3@i>flQo1^T!Z>9P}futW8=ZU*t1r>7ii+8c*p{5CtcS6 zm3XYixApZm29PcGFR1PJCp}r2?sq@U*qOG!`rQ89MVCwC7ckN2lzeFUFsHkMkfP1> zAz*36Sh>4~t&5xkicJkF(|6q_X|{lFPpJ4^l_@@n4GsyWg>iEfE!E(g#{9m)7Z-hg zUsn)k6nrhVypga?>uMSd+o0-UYWV^QJ{nA_t``XClOxSl=sqvMN4zlVERq{12z!ca zr#UxYS&7MnQ0Dkc2{8vB-tBf1@_*?kdmVSnaC&hxy1qhpQg7=#CJg*84&?1k<20n- zKw2Zy9+78XmZ%`hy^n(z;F+XWAU~IibQhxTew}hT=N)HKJ77$nXlkAX+m~AnJ{GV2 zC?N@nkKWJ{fN$Fxb?_Qjs3U6778sH?G#z(}&&=Wc2aGT0V+}P_n1d4Ogsd(WC3dl{ z??FF7%`-*K9t_}SX!h)mD)6v!`b zqtb$Yn}i$!TAN$~pVMeuBVSbp@)YW=9VbCe<6|Sv;4^SPEUb(25gegX>Aa(^xEfzG@`NnK_L}&byA&j6w~wPh|+GN zw5Ql&n^KfM%9`Fdl+^5F3?YvO>UWKV$2FnnX=vbi{&K3?{FAxB<4(Wgc$t#45hl{XwXFedqlE0Kk3U!Sz%cRZ0+oc{ap zAGV8*3;hqu7GBiSlT(;=q=9@GAvb8ocTI&Pljmkt?jI<6UM+@TIMM=b$u=&LJcZ3M zZ2VwSc2cbg<;9`!Ov%^Ba-@#r67m0K1;d-_&DgbDqLFqLJ0?x1_vr6EPzf!hgZwQ~ zoILpMI?ZSNTd!d*%tSyCegBr2{pno7jAg}Y1G>nHe#QVZI8q!%3pJKBicF{Ii-+08H{7o;09dq{w*HAKlFSeE)rQx?j=*zXfG74gPy} z^n;1pKmZ!JEUaXwPBEtu2sd2w?UJUmIx9_4bSV2?sJ?bP>!uUwX69m$kk~1~dGvN* z$DHN+q+khQbct_a9a{#}p?n#1@(sds)^ByvXs{Fe@(UPczV=*B0}8ZuN_maXo&u)% z*bFfPVXe}3P>e3$WkE=N{nOgII`$_5!SIV=CQjx>LgW=Knwlh0qZ3)4x$nNuGW z+VNI-J<>YoDt%8BovJzawVc?0=<&@`!lk_d#v8uV`rc+J{WHgy`>k8|U5m5OG7`nz zdwt&3v=>ON_f^JTyF<|6fq%=Y>42=-8v0SzgHoo5dh)AfY-Z9|;Q)KNxJ@KXP31&I z^v}z)x=J40Nv+pDjr4ij{N|Q&qu;?GL!0TjmD!LASuc>yGph6<57^ipbHTTF2L}dD z(a4jUqZ6MKFWFSAwwVN+vF~?WVr;{+zC0t}YbduAqcu3UKZNWo)|(yZLU!fQabcRu z&&1hD}K#v+2 z&OF1k5T<*o(t5+udsTn?(@pPY63Vy#g8ha&gCX|gsh8T1s`wIO8p^}rI)oN7ja2Ca zJh=e-8la{<5pQ)7Q?Fny{fLO|RCjIB)s{coXg7is7rI>|8RCFfMA6m)7tJh`GEa?w z)>iFTD?_v_%a=nnMUP3Iii*|qe|`$$LeWAqWmdih207M)$%ioszHUo!+%9(mBGt7s zyW0_4ev~;r5B1R+pj0Tj-Ld`lcQz}G*Vo1w%WzZjMN8(~9@Kdq+r+I)?{JRN*L_Ad z8{J&OtqReXe}4+sKhe_u#Rw6}lY8(T;+*Zt(aCcenUz<$ca<;FKLTvm>f)D*<8=u&+i=OiHkfmZb{49hk+9bIb3X1>z1ILv4Rtw(XP6{xb%CfOJfrKm)2a-u3l^ z74+sQ-lsAfI~hBTY|`XZ=TZ_8MaM^4X1~fZ&k@?_z^;~7y0%sRyWoUcPRnXzzY8M@ zE+OtO5<$P|lP}1*ANRZ(Z8!^78UGgl6rXjPuL7g_7E2Z*Ezo=Q5}UpZ-e58c9)MZg zl3o4PP9lnP`ujr}a~nweoyYKM?&w-7Hf8;)tyQ+fahW^)Ans;L%7J4wloFPi=M|ey zZ*~6XY&S1vy@zr5d#(3Il-TLmGcw^xu;?jtBU%de5oam`N3%|R-z~O()O9m$EfpdK zM{R6o>Ba8Hv3OHE;hP(zpRWxrca2Vp3JA!2W>@w;BLLp%Kr=>z!KImW%f9xP^m-_I z1r&!^VdG+t;X`sWQ-r!LCr1ODRl}rb107JzIp}8gT*#!C)<>J4rwdjSlG~m`A&}9P z9?A|u7E>*UwFE+!qEwpL9(VTlX1zv)G29D{aYNsZ(9Z@E1&2Q#3q`qVx5p7zTC4E3 zquM6acTnjBmxi)P`ir|RhIGXjbOLxD<8OaB(|$A61Mz)IkgqPrqE3Y9J3M6lbD(S7 zP3^}tS(v#^oz=&8yLT@T^(xcNfWYi75cxZAeu3%GzHPys&U#s4451O$3soBzOH|J; z>2Fh89*0Jgzw!xZdSUTOyFCU z{AQcR8UQUy_b08?9`tq#Nj#4s;8Fx>TcXg8xf)&uOLWhbILJMEh(u)^0$#-g0kuW; zH10s0DDX~O4Bc>dx0XN9%z%%(5L;;)fylg#Q#hsIQ5}#Ac=`YYO|Ty^4|?#i^eBj0 z(VT=ZeP=-fj*@)b3AS`Oj~7MX+D6vd8p+AMaSw=B|=y0I&?kl$sl~;2Lqf zESB4Gsy#Q2osCV`diRcGo1X!L2lDe4SL0!4#OcY*-c!ocUmQCUHz@!K zbRgp@ramQO=u>Ki;snvrq1qUgK!lVkKY?E#}lzm2NH>qoUWPL)@k0vg6i6YuqzG6 zgD3D)A7Au|0&@1#HT#*0Vl&_F9-E34f%w^Okc=pP24WU`Bg|)ua1#A~B_3#i|?>)cHth-+e~1dlK_E3Kr22rZSKI z1U-E#CcAa{{sUyQbUz3w@gh4}w{ieNm_zdS2%DNEDv{J!-gf+H)WI*-#x#Y0`ikX3 z$N>}3ByKfH*2p(({QFF-?h1Lt4#7cqn$Z)be9ssR1uu*YyrHFM>|or=a`aRQIDFdx z+ZuunUg}qL_nw#k`ssSX@b1UiX6yOev~FL_&*+HlI%3hb6U>L_-A_R-im)n*KHcZ) z8$u$)az{^qh=bc(te(wjR^=x@l-Q?|zE5WIR?)=B^ z0!}#+n!D97jivH)t-DHmr?|eC(Q^1{1TTdT>UX|9Jbp=}%9}8kDF{414?@(=e>= zEYXn8RBb;)z7=KVX7s*@#+orzc5><)ECeIw=6djEr2!h;d(0A%^@o=bc9OIF%zv`n z6sbt6u5o0!2`V5Gv(6xx6&0s^@Yy1lQL1l2d_nqxi7MGm1$!%FC~2$w2xR77Xi8jA zuG4Qd!?0oN=yo)Rm(M)_KAw&7#`c{_D7v|la(YXJvs3W)(YH!A57CEp88L@8wLDdg zuu&Q~-5rn{H@*D}kDmQ+1OkdL5}2nN841^kd-6CexYddFnywTy0&|KKNx1&H%n#xr z10UJ`wRA0o8N#ub4CaX*D{tP^y87Irk0JUgdyw+j%*+v5XVeA=BgZO-dr6;R#^jTF zeylTedcG8CogdLkbYSFm74Up({9XJ<&w%D~x3A6R$$gi(v&N=7M+jxBCGk(hBp{vZ z-Zu2N;n4xU7+4;bAndnUjv}j^W#>Ek-}?pfofg2>@DDwFbYq}d^K5Tt&*LYVTyw9( z1ui|e1IRNkgmXRPF<-8W_x||VnRXcWc)AFzL&YOZ+~>rIKQdZ*T!I+)x?bI=Ll8U{ zd#lkITDI{~_UCsETkam$EwQmXirGz%I~c6-jVcFcyE2la6~263?iKou<#Wt|L@K{s zir{Qks%wW1J0YD>?~Qe1>Pj&Y=?2~UT2VjnTvX6-#x_HpDYy6XNpb?TBuNX=S4z6lWkadZP&8rxx2y1UmB1-aO{x_=W-kc|1T^)sF-HTzS z7Dbe*gTlT${RlA~ET_(wcyU$*hRE0N#N&cVR5UtMCwzQYuaiyYB5@wQJGTe0N!6I= z7htCL>d?~-Vp(0zb;WOEY(74D=z4$R*f^}N$6{)aky0l8GVMgk(&Xy)U#{sw!%6Dq5L*H;wJoIm06|z=Gb6`Y&wgGJU?<>FL+hi3q;Ko2sa$ zfaIe#ZdMPnY8-}(1|RusOM8F8n}dhvdU3$)fn6H^`!~bh>rbADheT9_c8uss&Oh~! z&XRm>$A|nT5vCd*r8(@Yy#GyQ!K~xLvB)aP9Md2FVJoi!JQ=aMdKPbZ*llH|a7Utw=&k=@A`#H-rGZXA1-*DXKTlrFtdV4S6EBaS#=Q;Bg2r+dgbG8eQ zCJ~EVx5;s`2mQJ`t zmkRxGrANhlq)OI!j@y?*S5#5aWdZk&6QHo}?&j6Y#$_LF)n0RKe6xmM>fI(87A&!K zj|<~oY!&d{Yv?88sV-9F{Prg~0 zkIUoIF@plCew}K`WjsoT65(x1+D& zML*DYgrhd2UUh1P1`U4866*d5g(lfHpl^Jn#cl7RYfI^aKi;g_pLBX9`vg*Wyn0EZ zGWcSVzDZ?4ToS$HI#m$L8q=9!ue7)Z8043gcxY+ysXxbUHq$}# z>o{EV{O|b++My8yL;$`vAlYgQSKfzu)GVCF=(YfVO|Tpi5zYdWVO_-an)==zb6Int zInMKyqlMeVa(l3bL+Sl5#kwQI_)0$(&EHjOKg3#QXx-fDCsD~wZPyxZ(0xSm`_}jk z6Y?UR<3{KiAB5;ahxs9SOi8DQQBt?kcTdakJ4&4Us_YJ|xyP#g@c zB!XY`1YapSh5RXh8D#CV|92fL3TvYKxRbYW0o}QgIhQ{rE=Z&@a%_Xm!p6fBc0|T#Dc!*o`QHwX3e30!B;Id9 z+As;y*sZ*xq-Y(rDOHLyOd0ICb+T+@ysJ8vI{Y9spMh&mTu&v!E$lPZWcbIH=kc8L z(SQyf!|Yb@>)-@-iGWNSrF{K6ZV6Eaw5Fr&AUR|$`%l4T?>L{yRDQxSD?REg*f; zw9_(12(J{4u;m;*InC}NrBC0ObTS_cnbDjO{qo(Rt+lLSIf3FKd9)|}=gF5j;Y&+Q z=DOy{hxt8b$~LSBl1KX3W&iiWvPDn)%&5+FEs9dJ3=AopkCqt_WW1|r( zZH-RvILb2)T8BQ^cyL@DFGr*){{SuHIDLJ%CJ-egI}nj1uqzeXYsm_3Z@cwN~D4ku;knw}alw|h|%aj|j`Q#1Ol`fKm@Z!SZ z4L^HX4_T)F@lUel<+f%!;efN-Q6OpKjBlc=MEm1KT3jH%iHpgVM2QN?!jiv`XP)R} zk;ZlZzl9}MHY^E`-hRn9+4-g0auT~t%wX?#!VvC&=y<2#q7t_}+I-lXiEptPU{VaC zOGwyae9QXNCo@jD!KaXD50VkW1y@-1ncrhhlQmAcWTWg9ET13KB2?Kqc(2bIENe_> zwBBODY~AQ(2F5SKLcejWNPW0YLUGWHp8n~YUzM?1!R2OeiT!;!>vQj3gV9$Stm9vN z>TEt;6?40W?aG&<{cNP{R*!ST&mC3xNL#v=RE)DHBcNHusExhLq2~R> z6Jo^+o7c4*)0+OaSBSP}6_Qgf(B>xzr|F*46uhnsB`ZX_LljYRGLMv>xT*oSeUE=` z`yZR_KJa$2ZwjPtPBEsRSBGwI*)QO@o{nBO(Jg2z=#2{w)Y79K52U?jpPMtN4TjUf zR8-x!?aLF1n66R3>L9tA=l{N82@K6>LDuO`jz0WJ>2%~4l-blWN>DL;pYf+nC*jcQ z4{lM>1_PawiKMZ%g)!C+@i7cBypF>pzSelb_HGL(J%r3a4cR^Y(MH#MZtU!(8gp512s$(7c_ zAc%i0eDgE}`GtFo+>d03a9cmKB_fX}gq~a%uQrwsK|ac#HSKm>Az$GCqe%u~{r?$i z>Xq7XqDKZ2jUsx$QPNRyy+lf=G1{{z8SmVj!TY$cJNYxK+ zH=O*D@l|IE;)YrCaz8l2H1n61-H)QpH*zINe5}-P7{?}>oM^Tf1lrpLB|P{>#dEs5{!{%NFkU+Xv3sOzj5Hoyycx z@f``(pYkcv^Tx+x%oI6hn-3L4%;`p37@N<58+kFX8C6pU3R%-W7>Uy8Tp-kjHU+Px z)o?pSrbQPlSiCz!HAKH<)ts!l68>AHd3<&O*sH!96G+mAqelri`V4kqm ztFBzUyrdjL_Wa6GETcn#zB?^$>&8OTRwQ+29^5?}vd4<)PhEf5BD=^8ARIwIG{738 z*B6af4d)kB8a1cYd zwLTUa$a!+!*AH4Dy(st3ZiG4nsqUZI=8fGcUod|8GP3utgNr7EvYRVDJ-wCVVJ1Cf zswRAZzUHVMReMJVu6zsG_-MfvMfXX@uyfk}h3l z1vn3h32-d9hQDK`0{F0+0)Xn+e-z5KkFt}APBB>`R3U2vF|_^~%JD>+>{$QV9Jjmj z@d6RPnZq&%5AD3u4Nke)kI{skc-E})oZvyeL?lhWY?}}9psZG_ZdmFsRHV6gWkRHK zqkL>o48Z@oTR$;5{BwKc#fI!~YY3M|$`2{^!YA$vrgVInl>D7vP4Y1SpqNoVF|ezFs?c66?w~k zI@j#Q^_Td{0N0%y8@M8xHE@+737g`0oQ$TH?m-vb1O;31ogM95LLdWa13CRl0jfAP zL>GK?RpNMjWsOJW$nn|vkp!1E85sbbrQ)W-2n5ZAoky5{-y4>HKPjAFP#`>c+SRMB zG>ra9pBWd-Gs(%}df_6Pd?F$ZHlMT3n&^F)pIuQjc#2>*qd7lx(RfSe5~JwneCnCK z@z$-Z9RLSt8hehF>IxgzTnf#|2w_&eWKDW6`nWXMwjJ9Li{V?dQ&X&bd?XzTz)1Oz z@C~SezL*V*3cZ&8u%NT#7)_w6^FXwjpm}8#ovWccU8H^Uect}_=iiYGG4%D&pJ}D! zbaXp)I59C$c&?aw`D;~VkXkg;@21)t>nnaPSWMrDNm9iu#@PMhQGII@1G=ZkcxB%H zNNA}Yqxe5TZstKYe`ODFoacD(cxeA8GfO6w+Og1}E~97#QsQlX!*|{Ze}P+@@fEIa z($U)Q=4GeNAYW;>Xx2qqUt?We|JS{r9n0oT3i8N|Q*zqYadrB46=2EC@_WjDw;wdk z^C^EAZ?}ocnVx~(xtgFx-PiY>&uI(}4*qP~(TBJDr)%K19(T^ghW+}| zBDnfH=7Du0gql)su1bbQ?dtG1N$r5uiZ`mwn!`xE@biH`XD@M2q}hJWyognb(W@iA zKKu27L_S;OV*OFidbcPOiHzp0gQm=xPoAy7P+^YGN2ET;UJ?C@DI?g7CNUBV{bDXLd|# z(vsaUHV`YOD>2JDUuJ5zrRgMMxm>Al-SN%zHsk!UCpGPD^U67>d3e~D^T%Irm=5OS z^idB%=EF|r1)>wT6|X^MoTNmFYu!}UDXHU6aMLE14}rPql{wZ$2j_EpW}esCUc&5D zzneL<%eX4z#C?B2-ot};Hq2jfkRBrjgy7L33JS~Kr8P~ndXv=nCeAf5Lk(G2dD~2S z)D;mG=iJ11>@9&LrL|4t%7NM2TO`2GioF#Qzm4(r8i+~I`#ZJfQ4T(Hjx;rhLvhqG z2zBk=zXL!{+&1DkM#W1IwX$f%YK_RjYb4@OE%IUk#I@RIP*_AP9j+oM&i%jvrvCOa zPGcdeNrHQHSjp*SWR%~=Z)4zSA7CWnJE*UmtwuVMj*Jlkt#F<0C8un_1l!45#&~#u zyU;>Ni>rE_?^bb4ZSA>=0dQ{=x~UP-<;v647BZ*W;gdIN4+tenEC8eH7p6Rf?SRF= za|APe0JUJI>~i7yIjy2;(w8IM#qf)N1p=@YFKH?i%l!M9II3efOC-dbtdw8p;sbsS z&h9^HU^p(R{kv`>m#kK}pdf0Sd9M18_c}b#P z`oV|@-XvR(ugrYC!Lyid1k1ylJ6j;qR5ms|>g|}?O;9lP&Vs!+$>5nly+R~9$=LO$ z?V{@PQvmTscpk4j%Mgl$UaxrB693X9m>#8>UFlQ!QL!x5*kXI~>mXeLaZjA0_)@qx z5mFA=YR??$O3IlkKStIC{dLS10kK$Wvu_vw#A0W+(zLNsn|v|;8lrm@b8h&sd%Tno zl-^mCy>}pmpFbXa`q4l0!K3e43}z*UKR#p~OnDoNes558&#C^A^u3tF)vtIxkEZru z)| z2Mi2*#Efo0q`2TB&FGKIF?`3^bal3t^)S=xxI<)A+AKAwN45*ONM9SpXWv((?4io~40Oz~r|-h|_nV%6IaD;PjxnjNP`Uf@ zxm;VlZ~w#DN9>WIRsYz>CaC*G%YSh^el_aCRRF)3)X*!IfdZ+M_pNemt?bka?PUU!tnzMt(>=)B#8uS#<+(qQ#JnB7zhK%|eI6$)!@S|7g4=yyb5b zH#wZrAv?961y~7}WFekXSlz9>)Ao;^rBZEeOZPWqab-8DzW~MS1_tMGRhd~%Lx4y2 zw(;Lo_OqPZ=c*SiIFH&bIlje*EKqyr!Zb+2^Q^YDMxhB(Sz1GY>0R{mTqU+yk9zlv zZHqAGhyB`EPGE6ynWApUt=U&9PxdM+f?T4p`5LPlsO@6?pLh*fc}2w_W64sm)b$os z1pQt@7BV5~F7U)oH31x^?Gr4T@x*~zQe@+!reGQ#XS z4w%QE+>WxhzG0VnF-Ro$24~`_F*mt2jO+(a%);X~qO$!&E#&qymsHN&y&C#y6lwQz zc7Nc>`8h;)@^#D+&Bu@(0ZK^ER7l%X!;0m5Lp54JY^3m)B4s6XXa}{O3^r|NlMpA` z6{3j3C!5dK3e}Hv zEnPC&>Qu&-7l)5+&0o|W88M&F{B^x!D)j1N;8=&1aIDA~W(Wfh)}@{H473IU)x6VB z$Qn}Qi`9)}TOVbF2K#41Nb2CadhKNx09#^m4GxpH#u4S^9q`AS!sSBNQq3}zPweMp z%fVRz@|OH_8=eU-^_+(0`+9ow#V_*6q)Oj+XE6+=7LW@oq9{U9gM)+4DR;Ax_BLm& z91XP&fp*(+TaA+FPGjRvZLyW`kqKP~Pl8JL4MQY~O50DwC^JSIf1|SYkX!`&$1<(s z{F5(F07>C{3A8x}e7rhIJ|U7QLdNOuxX4RNW$gMNx zlRo8F)Mc3LytFVjF9J3B4f2+@Bokhv;&m%Z%W*7sFsVV7e(JnK7RxFKTe~*a*Zaa-uZtBdke29->B~w5JW;cB?Y7rP`Uw0M_E(SM0s7@AtFgHWcYrFQ;4=8*R;Br>)WbiGIOfQHFoH9s{7s7@p`D+yh6bUyrtlgl9R_4vPW za;_B#$_S16J976(&Z%P`MQfQmVX0t@g8x~2_5aph7n-hh28U5yPnfqSHb1V17lb~# zSvD3(WNy>Ue^0O(_5`zMMxWho__j8dAYbw4*?-waO>Nk7;Ns%SJ(FMqgg)jL6_bQd zj&>qSA-8eA+q{@2fMq36&H*q1NXM`6-S@GT@6^?YM|_T~OdU!M5Bb*iLiikT!o}TL zlx28CsP5U`qkT9?52K&{hJX9_+GHD5+2uC&$N4j7I55Nx3;!OFd;X*!ugm@@W1z`- z8Yb^*YClcM8z);L95=dHy)Bo1w>YLz&O@ifNJ(ptE+vpZ%gp2ML2F8KXEE}h%2D~; zzOhI?jjJ~Jf4O_>y$p=h+E1WLO2k$baC;Z#7G8>gB^kZ#Gdge_G)%-ed$bUv+tenM|KkZmuNq&FB0!th|Tp zRtx_G(OKi21#c!uI(+JSm!+cpPtiR-ZuGt!)^WESd)pVf|TGRyUfHlD2r>#N1>^zR|E}%%+qh3aUT%cYPtI3s7hIP#bb9uEgrkwq42C3U4FNWxVT%uU8!yh}q=EXh zgHxT_v!0_u1*=jP`};JEIdqky{1jZRrEamWD^*y{v`4=uwO7*eY-UT@KsYx_K5b2w zp!>WbpL_giVXRUbb(H9pUdr+^XU`Kc^7eQY-QWpdS*`@;d)cp6eEZcgO*J)nh37;= zuQ|P?)Hu&;-vb#Wu7k+2+utVYBr2@`3j$|wq5i&8!CQxb#_go^ZG`khgI;ULS?a)3 zrR+Ep^!*5Y$qJBJ&YjlhFN&%^Y5)2A>q1lhWNbI4qsw~w&?%I63}gW4m|QEKBz>6P zERK?Rl^wY+$v93%-_HxC50=B8|DYbk%$bwoGb%)>XJ|XY5xDNExv?o}7X`RF`$C#G zcunWDBv%x&bG7E!h4N{}wCkaUlkt|1B%p5+-C+Ztah)@~@@mk!SV06nfT7bL6()rH zQQ+HmRYAnf{o8=uu8aKXxs0Wpcl-RM>hB^7pSd2o1qS{2aSRn`LE=R$xseAs?cwxC zk(mR3nS&O1CII!vL_A1+AzO8kZ2vSLXqXI&U4+b^bRe^PQP$Vj=REP^#xFJR6TVmK zY2H20eH1Nl)swO{I&=4MutD&XG#*7bxv9iiA0BQib|N-0T1|=Fm(V}(E%)P#$N!lLPWx5`RDYe#F7)k035Ih zRI+E6T(b1inH!z(n3~cV?Vaj5WvXde(ZGAh@lUycnL;g!w#T6HeU_1Hnzu}3SI+4; zxM)&are?d}UBt%1#FOFu3NGg{IkP#GNZxQ16qKJ|AiUIs`GOt7W*a0Q%01~+yD}Q-8SehUE7?Ev`t=2SncF!6*bP2Nr z1EZ1OwUW!ZAh9-7mK?r{_&KkMRB(VM|f#h==h zznN<(uQMw9_8s7z#3dyS>+O}0ke04R^OlsH8wjnsyrh(n+97Fhjzgy7;!cC}EHv5Y z?Kd$o4STB4!TmqOM8AQ}l(j#F1tO1mAK|%gS6-f-p?!^}ZyyQ2|E7~&K02@V|BrC9 z(YLZqqLpN1M!5QqI}y`yN#MIs1FVc$G+dLG5yr2W9&-!%dicL`q7-e62a1R~ZM6QR zcK@m8;hsO1X3t`H(R;x_uxnuIp$&#k`v6Nu*ZA}`GmQr$ZPFfXf`;-1w(_}OuQ%~H zf6a$6vJ@7EJt3^L8oW$M$4?1P8_8$XI@9!6z8(t;v9T5q3BXAG_F`rU6$_o7Pu9mX zHxZGlk<07WBIp2f>UN*@(DtU7QU&X!G>5YO`q$%xfJWitlkAR8s6$f^@LuiB%)mCO zMVXbHwx{Z0Fmm(8y9JQf9e>jURRCkUk5XiY|caSM7N6VRU~X;#eQ!ZCevIFI?UIZ=1IPL51hA`$JSqo~VXy z{DvhAL!o)Kj3 zo|!xdN?U2XZ+T>hF8sCnc;~7ugW>xEH*UB#f(QXu=rh99EZJri!d~!dLXjZ~0R9UZ znqAqyx*EA$Hvp&TJLS#Nr+Dwf)slIu@T zBC`Dh;;%C}>ta}(I4wsGH6n{^z2WacW^&=bhnpc7qKcFYNT$OiG7|!f7sLWdK>-Zd z({sa;u_Gt^KYN%K266wEwIDXAD@xs;I`v7SwmD)`iFtn(HrqbF+HW&CRqLDs*mpPcXm-)oH1A};gmkoj8^g+h$}$MhEl@{IRZ{+|j{u80q>Xivdm&&enJ1%sfsR}=JU|Y1V}LM& zeO6&d6BZ!-L+6#ALcK_QPZ2XC>m#Gq+Y`LybKOOy)ZdenCsgm(wjj%8RCa3ILfu0k znhS?udZV*Cx(4VGigx6bpuS3(XGVkjPc$S_yUSF<1jqQa%F@VuzVvfRp&6KyQ7&Y%)Que0P4pXWmFkZcnj-?bIObd+kYrRf zX?-`rwWs}&x$N{L?mACpow5aZ{T`M=Vu+lb)${QTMKnS7Sl-NH^Ayd%qZ()M2lw_z zc5?L3{Odgaarh&CsWAVGw`S|M*pHJo?Yxo(qoMKfcrCJ3^)O^u-Q{#_8(7D^cM+-n z<#}A!BD$;p@7F+hAAQVQVeykC5-MmT*Hk|H0n6}VIkUyVjzBF8`e?)z_jhDO5rmf~ z6?&$o2Y=yOXFWm~8~0^eP%4aL72;^0>q5Mcvi(!OFJ>VP?hER+f8a!3&~~d!E#LRX zHyb$=8ifM+u34ZH&>T+XC%H~MFK1>pTrIn8DpX#mLISechX9XPFYKnXKdtLHCwbjgu6Du_tDo)Gg4oa!-0a+}jq&G#4Ie*D@K zu)utq{K51ON!RM8fh`17*>=t2;c+u~7$)WCi^@e!eD~skHIU$nSlefb4C_YgH4y&Yf zM-e?L^RUtBj-n38N{NIl%OcpV5ZesC*yaj4&Zs3uvnPsVMNY=MBc6|765og=kYq7T znlbZ3Njd^3Ulai%EF5a@KTXNw3r3G3aP2$>5p<$y**-79>+&mpJ1DqIBMvT2DqWR0rtx-kzxeivK8ej#I#tXM z@KY?smi;I6F&pUc^MQxUa?+gr*5^uMdJOH|OwC4nFE!Z4RdBrkda$2T{Wa&m4}2El<&BX zlz^vn4d!c1;LQBZdG&OK(-GiUUiCZ>@XBx{7mgDeZJ(S8g8E1Ds;fWUc_Efxldv1K zV%hK;lX`(-Hw|jXsAvp;ts^wtl9z{JZ=cm1YH4ZD6Tk+@jj0Z=8CKzVug#GX<+@JV z4}2bPyC80foCWUJl}dAu6yq2{m0UUM^vLBs)-iV5G$)h6pYB(M&&d{Dpp-4m-%}$c z^xj{Px7I>2oG4r~C`W&2(BC@*<3LgMDm67;EQ8AVa(Q0+c#VhCS6~&Wt7N6x=Qkw= zYd8*F@4{D47z9f3oEKAB2Cq+?q1gGbn+bSwP9t_`Xw}AYk%MojzFz!$f)LBjh1r1x zEtM~H7#GIzcCDotJtnzE+YRRGbkeIO!H8tAJ3vsW+2S|$^O_|Tfp zBUDErRB1O`;Ua8|qLr=!%B`aH1ovd$=JTaPFvZGm3( zIw;7^gxgNPOR>j^2A8DdNQuS`C#fK`QLi~P%9bCk=ncU$Vc6Bq9X@0&E7a1~`a+-`fD?il8$noi z!0;cgB_Fi$5xe1hQmlb^urujOh9~dab|=n7_-$TNlhH^m-`xSWjXmQ_2r|8;KuY-} zMzB85dC!#NlG8+i;y@^}7c?P;Jlc}bHwViK;}Vy~$IH&~`NjZh`5%X?*WJIcIR^TX z&|WV>!0U(KTEQI3i*UnZ@D+n1M>lP{ylZYu9Qb9C@75lp(=~qshsv`;5=?!jnAdS} zhe|P``_(%3_Sec@YWCB!o1$3uX;_mCrr5aPlrCW)!-;_+ z4ikDcT}Bo!0Y18(JZsWKV7wTNw2zi>&9CN#6tV_6DvfcvPN3=Plp(y&juxeSLmuV@Q&GZetV{xaK(T+r%s=Sh#b#90m5P)S5=EeJT}DOM zHFCUq0XeM4HqN7MwpV5=laXLmg*Gu?qx#~PcK z(~)(NxG{>lKWvN|KW!cH+bfmVLGfSnDbw!gRI?YV_Wx>fILx!L_C}wO_UCy;A6s?J zyW^9hiRSw=tfMlTB_Lnc_eQ3Ti&^qT@D z|F${eogUEAPAqfubNHa7KUh0iK3Aiui+#eP2Y&zl>LCo5KlD|6pwZuNV?T)2w33dT z0J^(P%e7nEz&3!Hf7NI40BOe--G%YyR4Hg8GUnL&#}N2tJk~;wUzRuRlpM@AtlY-L zka{ED+)0~(`p(^(+cz?AR*ZABo>K*koK-&g=+`7VZ4fOO{Dwrh+kBg%tZ_YRT-*I6 zF$^~LlPF5ImC}3~Yy`d0;ah4|xiy0>k8Y9?IY@t}-;4!6LLI@Vx$}s}CS8+5u4HJR zIAj|-5bEHQ2H>zD8pOQay6@D$y(9$opN7wP=iKf)n%=|?b|h!LWhG7ai=0x^Qm0YE zZX?2|5b#0}&o%y>u2LruUkqynKhc+f-KxzkMALsK-> ze%mJ!Y_wOSgKP3Bn5W1?;0%yZEC2jPG1{aZqgRDsAlNka25oRyP1E4{22319>Y3`l z7=|hLO<1u+&oteH3cQoMI72Y>3Xad}Hf$ICwUeWcfXC-9?RGwCtY`NDkzO%l?;QmC zaAPuEqMqu|p7}@{DWJRhIJIdTyD!T2Gw|qZD^e9G`g~Z#OLGof8o!5jFZB}vp&4Ty z(U5SZB)_s=C@EunKT!h21YlfT{;TG4N+*~9B zin312%?rCNEsC8#{=IQ7NU@J-U*~_K=1E~T_F3ET2QjG@rB!H%P`(zbSLB}7okwnG z6|FNr|A0$z^o;r9>;vvqrONbLr3w7Ow;a2O(;h{6K8lq8x9LZ|m>5aC-wiM74nw1w zHch11yh!2JBMdn1jgLLs7GH}80DP6*)*vo0Flf`wnZG|864`@#Lt~?brI=~OBLrTg zaOL0nktz7%@>Wv>Oh@NG>-q(ra2k%l$|e|GX#iDdV7o`4yMPR&yzI(@tVTwtr|8u| zN2kH&yAtoSfxJ@$`Zd!=GLa8Weywn(?sR6SjbT4>7_0t#Rrgv1gDUG3{Oy93>Cof2o+g)jC zSRDp$PlRaCm3(}!wE(U<08?LeI9qGvw4+!EtPdhu4Rz!?AK>8P8kOjUWAM@$LYab` zre*?w!eE@wOYMC%5n&#AM0gkWvAZvYPP3UXh7t&FrCV17J9pLf3R}y~`=R($)Ye_U zp9An)d%|F2OU1VS;n22Kwoe526{p=}!=JOL(#pNGFY6Y|^8?e7l<98uj8@yd8*Dh+ zQafnB5j14}DkR(7?RJTj6|qYQ+y5(~kh)sHobYY-*Bi%6GLm9GWt~XemnL6#$Qk6- z35-<`NhqneSHqQfH@h#C%zO3q^(pBUGD5u{ZUQKorn$KXe-Dc}+q`_M?Zxw5DYK?8 z&nfJqcq{8&h$3{f#1rQ3{J=o}u!^s*KeiT-{Fqlw4TYYzds4g*vVYwBb(`LwE|rbT z5eE*ubu(?|K9U}w=X8h>qk-#Xo*W#!ccxh9gC#vNb6&(Eo&KUalpNZOa!V*@RuSET zP<|aip~{VEDC^mSW2AX^*7{uRp~c})QA&h6 znJc?`OUEVh+TgKo-VJ_w>C+rc!r;2;XJe8x1w2bXZD_KIuOD;@H>pz!55Ie~oORga zpS{8LsN0$TWhfIw5iW zlr`Oc@$o5NdG>>`lz-t;+Pi|NzEWRR@-Y>PgWXm#HE<3-?%rB%;a8C}wME;Deq~YI-N(Td!Dz4OMF1E1()tSKB=%Ou1ikMBZ}o zmsyPa>r-NvrN$V3V*2K=x0<_BP%q~CzS{^yU)djKxc!ie&7(x!>XECFS*KehTPJSVuXzXPw&x*-^p&rD<-cDYhYzrAj$l z_5&u1`1+==HQ`K)5!DnCFE2V*57`OMP&Ok*y*LUO)TKWtw*TtQp*$97A_P-_7Ktd! zOC+_`fxSP9(eiL}GZ2y-_~P;kl^I$$Xv%ZGKgx1s=E2jt+8Mn`ELdH7^Vin^Ji0T+ zecbQ2^kEz(UI0T?fqQPRz6lL`uF*;uCKJ^e^Ss0P>WW0rp61WwAH92+ql|fVc6$yY z!{38XtFr-#gBBr{<;51+Rg$DSlibMnuxCLt_xP-jM}FX+QJ$)oeUXe?%-Wo7KvEDG zC{gUog5Zsa3zk5r(6N`9CZste@Ev=s#LGJm$<|qm41H`l$nyO9aMFt~o6pbuCXB0f z_gs$*O@@vzwjg-E!F$cwh}k#!+#N&ZJoAHrr&ACDf#db?3%}EbZ_Gzmfr}z(H{_;O zFxi6u1!jaE;$7C%u(C4N48Bh>k`cst4Q6j>?>#&ls_m|ZlMaRYE+|~o%hWZ~SxU?r zAEw}RmmfAk$E8^h`*NZCeU|v=%Np9cDV}e*so;O+5|p*o4+x4Hiv|j}Hph=$T^pK& z!1qWxTk9{X%j_us3*BuRg3v`q>FFja*#GbMeUdB0k9V+8%SmC?Mz6;S*~t5Bq-pNX z7^Tl( zT3DFYS4#(yTY71!&8`H7c^_|aia)fuq&eoe8~M@_{NxAqI=DZ+V{f~MZW+ku6RzHF z^3~Nh(lF{ zs@^IH`a+g(VW}Cu!Luu!m3yL50`_C#!c$Wlv)cU_Z{7%r8~fMT`4ae$OI(KG+%W0; z_z7paX18y=C_TO-sRySWf$>&+M}6V}rD6wI#G1FdECk--8NXl6N99RGKoYb3uI3_5 zspE+;bUo3&hac;Oz>`t@PKb&$M@dR0%_(zTCzu%;G{_EGg_~rKtODtiS{!1)QWSH~mCywU@r4@`$~|+-e9AxX z99{G`lSbJN1q4hm)A&XXu2-8^+si}Td6$W%?tva_Wnm2oku^3japPTG>toGic1q<( zrLah&#rz%o9N`($`gd?YV@ev}wZy(pJ!SpZto}1rT%!m1@m!x6=<=(CxKL}etN_;r zuwTVybntJ7k`%^uoR9F2PgP_fk4s`^Z;ry`*`IKN2Kd72PId)Kaq&Zf)z3efcS<+o zs)jg&s|k$&Fi0~w4yno>ssW5yQ{a#5ECUJmIDwYPElk9@-${)%#Q92y5Eh!w%P_Ws z`&zA7TMhAM$`(SpQ^OdK7EY?*u%A#Z1mEPBalGrqLtmHJ>DN2$1;ehk*j3K*Rwq)x zK>;Sd4@8)fmb1^fI~=&-@0>d#kEj@zPwa#jo|X-m2_b5MYW>2+6c22We$Lj&(kEi& z@!Em$ZQHMjl#5Exc`Nke9_?%W*PG4!<3>GA5Mjfycr% z5#ysT51F4QENo*$!_!4R(2Kf*n3eqE;7Lo0bZu*L2dYR0hv>X@=g)4&yWc9f=%^?+-Cotx zwf^~-`Jn=gW*Qs+J>H+_{xd64Y=KhwqKM*_TIHLx!aaZqUy(ALEy)k%zMOXg;b zpa}yd1BPqhPj)AT;PCPHR02+nKk5m%czFejJ?b_M#57*rmDTn{)`*iyr=uoun#t!_ zqO9GF$#$*I3NrUM2)o5RyK~)57@L##PZqww!~ox~fXD&FaRV-zdMZy`lBr9FxWZ~l z+sx|)Ye;@H!eKPxPckdvx9m&TVfp;ZI{TtKxS?B@YKX-)U=Ql^%7ey~sw25E)~>OV z;PpTCs4q9uEuYHCQvw?s8^ER`X{9slE5Evst3{c{r)cDQSL=`Om!_RoTwH7jgI{(| z;$EKbZXZkphQA{YhQ=%;{|Q!6k9WuX9H$CTSDxD$hpo*?eAYK;g8R_O5DuWRdx&Ui zPOX=a+4e0=!<`r5p@|Qt&pd@_?%Ltw$dTzU9=*^wZXDJgu>FqMe|nG+ja#9yi_S`K z>s2zXszSgE7dlkFYQZdhIhCi^(1D4S!pcGy6x%;fos$rq2aKJYqTaQ@3bb+Cfy!P- zh;#1a*2hGlm4N|TEb4P5E{u{QBv$uU+-(Nhs@evG)!%wy9rX`AB0qt;-k0)DqKakA z*lwjB|7DVenGB(D)*6|vBL4ql(MYi6$Y0QW|W4M=r0<*4! zEeL%L%Cv3Mr%sW*#3XOhmA6VcseigFnp5 z9@{Ry-oQ-R`I2mr+disHm?z*~ZltE!0d6h_ywf2i!XQxEJzYH&Wh<(#hhKA?;nu1F z#61`{pw8PG^E3nyyD+#`0;f~{AuY-)+~@eQRvw@o7D?4FvxKBM-9wzB8&hU6BN&a| zVn%%u>BbQu?EtHYr^j3k=A}s|;_(CHp*6$YX&T1N!WG`SL0YUW2i1slusHArQb8NE|haHwn&UU#GfUl6N> zL6dy?Gu{(8rkF}+5ZI!a4CI^_=cRpdr7oa~^JX&fU4(J^Q+V!s4vedn#Rha}AkX;( z6p6s=0CvVD_(rsA^2R`2o$!Iy$tkrOb^C?wpRdb5pVSB-x&?z`FR(18;vSwavdZym zCX7aMR4I!Woe}JxN96;_Pfw99Q0fk<4#z_;W44su`YLD5UNcGl>s9qn3cRRe=C$?7 zfm~^m1v+LLq>g2;)PjQv9AD*&$niw(*jN$M)E-#)FwNrGCSiX0lqNz}?I~;JNdAy+ zn*I#rE2suOxEtc-bAJG}x4H@W34`n1L3Qh$SxPkI`{E0(Zf^vjXzNRoymO6+hoA4s z#a2CRTinM^};VPE^BUY6gZ7Xt~}U|Hekfz~k{CvC?E+-KF96 z;XKcV^i#M~kCen{wg90P9J>Ekek$w6ya7;{T`RzQV!$`V4dAjwK~fD-pjWMT9YI9{ ziyWD+?hq;}YZ`q#L_920P(G{$Qh=twtnOc)R3u8z*u>^gS$a?m0b3{kHZQgmPJ&qMr;%gE<1|Bv=s1~6;pO_?!B620Up&3j(xOAp zn~Yd#n#-2!o2lbB;~K~u^*G9SXPv_fO}x2lWbd~sbCdcjO3`~Dx$BeIx^S+ za8MameTA0&BQbBb8<`8Gq5xGS)K*J{b3@i~Vq$twMq~$hvy`p~W-f)uHx34lv_|(H zfiGse3xgf)`lf%{4^LnB_DZ=;nKvO-8S~B)sJsfUIRc|lN9l$wIc{H!ExVUSV|R*n zFWyi|w|;c20yy{obHD>rRc4+Jc!|WUNf{M*-2Cr-AhDrE9Ae!IP*C7Gx9!0{8f>~x z{589pc9T-&h^wG*tNJLr6tm8A9`mB_PoYkvfVmiaH78Jlq-*eyjvtVty|#~ZB0dW z`AeoVG#U9wslG5QiM>--r_kTa!UYJ6vN5!5ul)+-3aZ+clN%-3tf|-6(crs0iXYLg zNDMD6ydiIZ7hT|&<6CPcK`j#CrR&VOanf2D_fxXV9R4|o!qjU+2x+q@s;{J+3;=pN z$&XsM<=Mabe0s(%tq_oxCi0GI_cwL~Pc#p<4QUo50=sT4dDDhigMtKAh|DeS2R^w? zhFH-rgg4p@!PYD+i1)O`M)Ia_R4FI;UsW4qf1h5>d0U~|@D21f!(uG`8nKT&>&14H z@akIyeu9;%&SN=t@}56$`%o7F1O_u{9wQA#<+&cB#T1W(ymfe2MMzSC?xk)kj`qtX zvobM`MHt=X#LP;r-01`?@yBG9$F^)pAEpqc((X&Z_xTqr7~w0V=8qgG7(sx?4;gw` zv8&n_KXVcD4pu|5ox19bBhC4F_L2Uk(0N-C_DA1m_=;ZioF$-vvfI zNpWvItgs+h#%Ddg45x;B>&@?$D~SSJlH*AZWi!M!Zy<-qbV0s&P&KyezIGY>H6&qQ z{l`wR<<_kA`mA&=G2UPB3?VBOrErZF;;TH=Ar0yvycB!B#+ZnBBdaZ;FLK2>{zp-)3ZySSNGK#sb3Vn6%VWjQbf^vzfGpzh|g zaA>@vdQyz>YA@C~_MR{6*dioQL}yVTb849TJ4#^Pn0NTOn^0z>-7NfACCRTfrWxr3 zEXV2A6$Xl)Oa0b6aO3{?2)|N&PdenfQqbv-f{`JnX~#W7_dajo{Nv}6tFzr7N}ZF$ zP6x?XfOPU@jkgtjJmcKT>s@a*g8p~dL1=Ab5dW9jll28vnHpk27a_4gTpVfTm}^# z7J$OX?BmXr2^1yw(XIsCc7Q#5S=ph2$wG71>CJt*Taj#?bv);_1z$7Ny5&Wek> zcX%WjDZ2!KBY1PhcV?B|yeyx2p(P-Y=)bWsK06!oB3#MCPo{vCS=H$~x$Kqn?&ub; zcfS+4h>o9shF5x+lJJtV9Scmrr-4mKM?IpZ#6jZ9?YL9t-@99G2S*ZL1v}h9d&lMQBZy>hlot?J`k8Z0(kI>4o&G6F7FCv4te|_?7#TT1#^rnc8 zZ;h8-wulMd1+8W+x1_R*qN54X(Zp_emv*`$^?io_W57crZfc*1gp=^+?-BQ~zr>K3 zdweYn;-R2|Pt1)ag|$Z>dXZPYZM?h8gZ2k|h(G1>anD5%+|xV&y~xR@e*lV6v`(O{ zuvUZ(os&Ys8}{5xyN|I0Qnc2ZZEb=m4X?-Ls%>qT$n4wakptFb1XM2*2kQ1G)7+IK z>KDiL%Xwunfm~`;)Dk3Z)j~eV&@zn4yk7^2Q}kV~3l-xlc;_GfJ8a)gZ((AN+`z|6NE-^%G1;Cj7Bg$CSrG5a4qbu}v zY4i@DZBHx6f&om%ZLs^(8-{h(>tz))>#5h?0+UX*eGx6ZN_u<`kyv{jz1?e{%LjX} zf`FUGaDSQSt@)ISTb`A&pv1a79{jpheF~#70u#cjha-PQ$2wl?PoJ2{=Gw8;QXHQ# zq3&z=^PorF7Rv}D{lKSrZXFf6V#cCILt{=tQ5e*CVToo^YgSzEPwT1lLDu2@%Wm-N zBhf@E#Vb(k=~dqFwyVGp_M$!LP zZ}89gCNd3tPY*U%Eh>TRQBrEZHOE1^*9#W-4L?$4a^1KX{v zZEZjm(BHM_Lz_}dA?u$XpAXv-Ui|u6+My<|W7sg8re9=YgTMWMvxumQzndrT)3!!8r0^?_F#K>q4t?y|1+1J+_7Zwu^2h_Mb%)K9(77DcRg>MueS zy4ypY58?VrR#i%Tl^T{G1bSEnSdL}Z5D+@YK1zI0+skizEs^L2OfprbsZ-X{3dI-$ zW#W1vqsNe!_AJe-jtkNdlhQh9FaEAV8quuiE5_}yIb)h1|1$ z66Sgrr6C^Vqj{e(2Y=^P@)8Xk3tl**kGj$8`hO~FoxRU7bcjzD_~#;e?G&)nJu2rI z1BZET%D&w~u|C4LTcH|(dk86CXMg&~(aI_P8G5R>RUYu8$nB>|KD^E(ctiSQSjJf@ zybj4Bu*fepIz4;p*_F7#LdT~p=rkPZlMmlC+}8u9?YHxlTFY-nk40Asm}{tndIJlp z8JZD%IcR|+Rj57qsYUQ2_serN!MUwx3g;K6(3a!Q0ARjC<=aosJ#5=LzRw30ndGd& zIo?X9amD?=c{OImZV{;v>_C--`wOFnH%HddBo76dJbLE=L+>-^=p7N0V~DHxnl6B$27_oL}K31RFjgo9d;+r3K|%zm?v2(Sp=`rS-g#2UP9-XyZ|43`&$8_{fmn|fRFw?xc{@z1yd<(AXv)sE)SIB ze9<|?BZ6H*5peKdIE97#Ba+d$U{|J(O#dc&A-oXf@pIqK^(AzHCPgR%9{5> zx;>_*DtaDuf^d&7oC`r$4ld% zhVw>sO4{W}eUlNfBie8V#P0cPK|wKq!`7SNRTBHtKlU0I>$b1F9~Q?KJu|l%HCh9f zj)d?K9Ss~YHyO49@8w4M2!PNbDE|WgV_Vae!Yxdj>8oxeLooRY^O8m8;^&gFYMYYt z(C7%erAE&O43r>!z6XTEnCso}wLHhCAwJ(;x#FW&u#u?IQKuadOnYvvjs;_jh)v=6 zec_)L!~JSMc*vl15Ot@t0*Sn*`e*kqYYU^RZ2)RtDlv#H7Srt?IKX4(Qrt2Twa2B0 zfVWK)pO6XBEvYDED(6?%msQpFwg&9~15A*Rkf@QYlG<&?79CDF4jIN7_~G=@0SF_m z$KKe9Qdk!n14{NpU=hgfqP$}JIA0d%9pOzU;eS@5ehS;@b%+t~S{SG`Omuy#icGJ; zzV--$&B-cqnW@YQ()$a}7KY2jX~r$|_$bjlL=zFyzT-*0JC6vBF@H!Nlu4{Gh$(L3 z+nHrAX(1c1IFn8Wp+G`LVixDS{piYy)D@oh#)46rlQdByJ= zjUKR9qoU$}`!UcI)&+F%E`j%cBegE%{zdLm6EkZkE*#>4P$6rf^8Dvz_VyP02jYMj zQODCWPR0jnY;u&Qywt?!bb0kUYamBxP)Nyu%9xd?SBI5vW&$z7FgILB8Qh?&ncYQ7 z6*wXKi4L(q>G_jxB&;hij~m_nCSBSmY7ADoTmC!xqTL12=Wei)Jep$3Id$89Ch|qu zs$Xod24YilE~#|-1BXNLrvIC0PVro2uac0UjIBxkKbqW))aDlPv*?X)r>oYS5sJ|b zxYQ6_iaoDC?kFqoeWda|=JdL?L)|!8@jU69R008R`AxD&gv33APypBrYdrP;`1gWF z{motf3+V3^K*_^#3HZ{NV3)lnJf^?3G1yH8?lx4>_k|daz0^-b^C4Q#HL1?eY>Oj7 zi;D|5O2@)Tv6WBa#NtK}T3GgXgl)RD!-l{{lgg9;`G_#dlCqITS%a?3I$pt}eykjEln>Rw831a=N~LhsQxr(@hler{2Xi zFQ@$FwgmaLHo>f~hQ7;b7pmn}gr7#py)};6R_Q+!nivf^&_==aI^Njx8w44wjR;O9 z)B(b}M&iAPn4MdBK#7Ca;0y%1H`F%xcha$22JjCgfB6^@uI^XAt3RY-i@p=IroD5z zhr}T%v&waYp-SZG_Mk(Z^O%RlO?rN`jyqtKx2+47BGUZ`GBv}E1n6cfI_!n44_giw z>@tz{jJKKQzjJ^%^69h)E8d)*KJ-(>zN1=kt$c=dd$ibLGZ&iLW|a`7;MMG&urho8 zWXP$3-d4g-&&2c7MMRWGQud*m;H_0^W~9C2hP8tm_07zpnopD{THn9pRF>T8c!VCS zi?(Ai|7_t5O!P-$#Cqwc>**0oN*t0PCh#4J?!2;*0cmzcGfG(3FHo!C&;YhGlnsY1 z!67awz$lch6+k3PtbQ-Q;OFEDnx8sC-RKKvKpA#F?27|MP|6P$fFJ1!mD3Ktn6-b9+0N z5HQw;X91g@Zc?$9Qlq=6bAOfeA=~;z(3!cK8i9_E5QB=2&Y|Novyr$be`WnO@!`K? zS=Ty0|D2E# zis`o3+Qz5ywTm10%FDo4mU`EA{jImywzz__>gfCNH&flu#3M2IG@j*qQIQhwV`%g1 zb!fF#q{G7=Yd0pw=uPe~!j?137*LB)YPXBOD^eHvyubz zL>Ljmd?GdWgJe?BJ9!vd$O9x1WklwPqO-nK#!hgk8RFihkQ4vvR<;CI^;Eo9{N(|a z#bO{}AUFUIIC&%V3toYg7FG?Vsqd+xjx1QE17GnT42AKC>})a%`D+nHK_e^TSkNWy zR?imf86gAPJD~a-@rN7^SO&)jZwn9Kk`m^vtvP7YJ<>lbe?x~M_^G2`#q{TY+?b?j zGVH`p|08WLFjq=bL>5)<4iDCIU9QXNdJM=bwDgU;T1%6{LVLB=f{T)-%WOe7K?ks< z%{u5#TU-O*%~*KfB+%5@U~L=lPgus~)3N%X;>7OrFwZrb!H))*anL+ka{S0$F~?BD zmM$Z%pT%k<{|q1rsoa{XK$ynbtEoLoh%x*0`Eyi%zZ7J07l}l`sd!*NJw5%uxDUc; zAyh_>k5iuDjD?qFtFLcwuaK5@A$t!>t%}uNsP(-`5ts}b&#qw31qhEr-t&hUGC1L9 zEzC7@TOx5N3#SnqM7knCzH&<=7@>=jUHdt@D-VG@fV<#9?OiZ|?>=LztN~(b9D%ti z0$|?647-+=?Es97GN+w4pLBJ}78Z2kz9(;d5=dLAhQ(*sg#j*4-E)2hBKc|or5w+DZ*5ZC}`W%A5|1Pd>{^C!^dU)hB{ z`*4K1=DrKrtuj`_HroijHU8z1U&xHFndPgLb^qPx(>veQ>sk>wvHUc7c-SCkUtTJ;?@-!{x6ZM zUOgzf3-*9g1Gi*Y3)7`9dt(k-k{Az6$c|rigy`8dNS?b|W=Z*`0nzPG>u*>&kHw!nnC07)DRZ6ia zYt;UjGq53oA2SBx;I;o;iS)Kne>8i)ynbuiWVE2?e11C>H!XAB9dg}d*=g(Zj8z-y ztIz7i5p<Jt&~b9qxWQ-FA8@h|tqwjd*}vT9?7q=2ZLeh2O!Yd-JcQyi1FJVW;hOVn z`XK!|n{+-xCJ>ZRC-nU8^4X!P>^P)Yu+*Z-ecq#UQj(UMc9`zoovL=2DVLc{m}~fr zMgd`QMxM|Q<|Kyc&rE*okOu@OX7F;v?NHRc$ee^4C7TI&pfozC^^tMK2g;ox^dpu_ zqf{lOR0I|q)Q5V*ALy~R`}XrzG2P&A{phVP+dtInj3}@u1bQ1Tq{dTHcd54tk0L%{W92CrOj@r2`~xcA<(Fq=-lSI`MXW!XO`jexuA$N~IP$yC*KZoN z1nu*`fR3T<#tx2Me`9Ry_xSvNe>(DMzc(Q|-&{EF;}Zgfr)MQcQo;7sr_?DV#l?lO zxEoB|e#>N7&H1usx<|Bmwu@17xDQ(@UQlHyW6s=8661%re>Y47s$P^9sEiCU{vZ4* zK(3~|{v*=o=6IQe_ZzuXBuUq(Kpa}EcCDE^>uO5u3x-tf`DsXLN9!jai%G}xv2Qan zpTzBI&861;Hm^T&WX;G6kPds0gdQ1sPBUG<&3C0~Bb%-G91%qP)Lx?d*6?__ypHX z%*>5|{6@#uJ}ys+H;jpwVi-iPCup@?>6G_v9*)%EHny8X&rq z>KGsb8EB3CsbKfD)jtV~ab#qeszk=rmDTR}sBW5k_<*y-;p({3?xV~oet(dQtLaAV zx$wG$n^0tA$V54i(^?SF!A_+ z38wtS>7t!eeVn;^mrNn*`ugN-xH{|gJu0eD_?Xe!tnh1Pd`jOtkne7uxX2w3Yh14j{;L8<9XkP`*KWu@)9|gp^C_4*RWM=cyn9CHIVo~_1RuxSsyzSE z&p;h;k9Bx({$a0{nU!M0*Kf}m!jDXm8i79-?T%Ac`DId-JE@iPt=9>a0`P#4rGO#y zeu~V*i*EoEDSduXE&(So3=H2+g_vp_z{Ka=C;Mx zmS3kEM<}o5Pr`O0$YlPld=E}_%TT(8*A!LZPe~h{sZGArF%r5;&Q1&vF!tFOZDNA6^KhDpRI=bKhf1TH3pjyhcuds) zy~Je`m}FV7f?;e612QlD{Uy!J%nlCo%cCg#KL2VlNdHtW`Sr`4-edunU)sjO>$J8s z2Llr~?DCix+KgzhgTqfRtNslWBZ-rog-*jZPHA7txg7(=8rxaV_M0!Uj4Engm&%$( zL}W~kA|>EO+mi3UtINx$N3ER#3a2|Lm1DTyCl$3NEkmpC?jPIh9#-mOWc&G<0`Zgh zzc0MP@kYEue7N~3(1auph6152G!#+Yfmk0wY|rH6WN3>hN@y(Yf2;i0b*Y==6$sE# ze!lf1fRkMM+XMFfGa+_=uMiS5a3v4SbUbkmM7oxNkuf8c4PUQ zh81RgNP(E>gv3nktIS=d;3>sqx>{wcr#!N#;P3I9`_YAR^r)m zaVfufqv)qZy|OYNyU(7X{o!MGMB_kqS@?1r(V-sCrQ$p%M`i41jlIWS1un>X`z&Qv zr$^g86ckGqOS#iYqgAYCLptYrhnE>Qeh%YY_oD}dDxjC)#L;gKtX?ad1c1KK%M+OD zI&@4UrTjdWHfa>$jtj=?kt>^WFVQGOg#ZQ5@R~;>IU*UTS>&3By<1-~nhooW1Uq zP^SI#tu|AW^+3fRG(Fye$ro#?62Ee@KR9JIHV%x8SUgf4i9BXK4M;L+U9CQ>6jcx) zFXA01Zra!2_?!TY!aSowxic{3rQfC;=(4GvSOw-@&_hX{I^EmSbgCIR3{oG&>Gr-Q zJU4#S`_rL5?-{-Wo8lQ{DdscT|b31k#K00pbEbF}9<4Hp)B6kA#A>s?c$zt#cgSVU1 z^$>ioi!_Vf5RbcRQowwlS9sPrbr?D}K<2#kiOKXoTpF1@S!eU#g2x~pTyHgMwp3J9 zWS_@l_6K0O%1tBg-;bkuz+G+yOrWs?`!C{dSZNS*FL7m!wav%*+r4Fx;^J0!)qw+E z(t)V|3@)JSoT~PdN%e<^msdUFZif-&=ajm_mI5yw&6nJDT6OUnt;;aac|Fm|Ez~%} z!LbbU$MowA85I(<*UjmjcQU_y-R+lF1zs=pOP>0}jDbXeD{*VeIv@BU zjuad{d6%3j^j{t}aZGG$8ouivA`uQL{ABptaJWnrXlA>2=CjUwA`v6* z?peFRS8{i$nfjj$|CCqAFDgo@g~}UJP;T5aXm?Vfu%9UZH7C$-tY8IN@RR91apRLk zQrjh8^88BY<>vko7kJLUKNd1H0~ z!sM-N)vK3ZWdO#4j?xGJ4UT}M!l}>wBv?ftWl1dZXX)q9)du>~3BV@1Zft0%iD%c2 z2r{ZM#bHIM<%stxi)C(p-RKD;xBk4eIhaKIX;RdUo&9koVpsgKaR-W}yl0kh7xFn` z*lIfc)P}2bV29H%R^?UDpxs}Z#J0JtBxXS#H{xwb6t`iXb(h_|3kZI%Tf=d4g zC#d=0SDcCT84pzNr1X*8X%6aG$#JeG-XBXiOtfZ{qAB~hL#9_lm}20EeY9${Qa}J6 z<-Jj4lC6V-r3>V(5;6vtI|9ht?dNoVf~5*VyGS<1LSV?W#C|D|1+_mRDD&ohXvtj4 zr5v(wWSSov!cscaMVePfFXWnR@xW1E2T!xH|CNkBX%`R%Q6K*&$yehU(w3cHP=-4I zv^Y77*U;qkM?L^g@C&(|kstjZ2?^)A?^FT;nl=tjN?u;nQ6;@jY4aP2@E}`rjvgvc zhLxx-NI-B_T|xXkChL8$o1$1>ffE^Px-N)rtKj@i(QhWOIZdpgA7D&St~4*RpXd&q zTQv=$C1B3j(K)eWdIJ|muhD^DD}SZ~4k6-a|6W*$d9U;Y_jkE6l#+^*`2+@iQi_3> zai?1u2T1?*jxEr<;4f0;d9=>Ef_&1eh)GFKHbqR(wn)mva-AxlDs3_*1bBFOhGj*oLqRMi%dd4Gv5M$KNIj4~8(@7dl)sINo*GZS zK-Cnb0E0>lcak5N%ZHftr4AI6XluXY29cx)bI>65wY)M84NQ8H!j(}8)1A-nkGqA# zlw{6$Znh~_ITXe2FzKp{E#3Y9=I;~@iJh;J`b%G>F4CY&e+nd8q(PsYNJLBvReUD5 z@g{Oe<7dDwF10&5Yf%({G{&X5tx6?ri+u)(QNLWUPp*T$ZADet0X3N-iwrtXUKQ@{Cl(B+?M82^QIobtODNfqa?7*gk(&k;|U-h39D zRsf`G-JcS0&3?Xglkcq+*2@|%qqxQEYBCq5bohb|JFvRyr(4@1+4!j=L=@SKoe*ef z$~Lq3T}Q50>#1~H9L4{AMzNJ59KX;Va!fbsf8sOE*mw**lpx>8CJ@TlJNZds4Q=ZA zQdECsQn3`HOenqwlP#%FN}gM82m|ai^adRY4C9%d+n`uL>LFpZkah)-VU#ZxpWU84CX+66V*Kqcz_md+d*dUPv)6Pje~&0%5XJ)&=!2b<<)#;^U?D%L3yZg^3`&wY`Z>wMtG-G+oa_o)wK!u&l4k* zQ}f#l{+H_2G8z{m@gD&1?ga0PJ&|nhCmh!JnOW*}8qeT^2&9-6#ayn6&cz;cS|#O+ z!VL3sy8B`~PJTo+++;hr;Z7V}7^r?UxA3FS9%m|65n6*bSfm;fFn^$%niToadg%SR z_4uwUL0)Sd(xOyTYCHw}(q8}!&TD)>xZg~K*?oSbI!P_`wWhG}hX7gwE)6OP#G;ze z`MzUN|*eBSX#Qm*V2$ zzgX@|%`)b&PUn0Eii|o1rvKI$4b9E;fD&$*ohs-k;jTmPNN~Q*#{)UQVA9tw2;Q&LX+yv|B*Ose$UFAd`8l5?Q#4s&z#W!-PU)g7Q5Tj=VXH^?9=~r? z^2IWU>4m+z$6*G$bZ8xt(L^hqk~FC9UZLW6K#fsmBgW)mwC|!1oIxJH1dUgdvDc4Agc${H~H=DPc_=$=qO>ecKnCfE8^HAz}eeW_p9J>_Y=+Cuh)KWiWu*Pz8Ye|R6jdt$;!Wwiv|DD(7}=k@{u zG!No4Bp#M(ct@G;sz5s-ssZWHq}vvli47M)ozSf*f)< z7{*Rp%zXc0G)O2y5Drg(hG;4;LdE2MP;&0&W44zJ07u)}ubw47yDu3tMVCS~MkRv!`EwkM$`h9;W3~5(|hN*OP5D~4UoZ$cc3^ifFLK{ zeRQjfh-p0(Aq^tE^=X}!2I^9vG+$t&nq20#fZc>EEJ@!~f;Q8ww9m@`-4v-zh{i2} zcg(BM3%`S*AOD~Kjgv=sns#NWlj|4GnTZsiqy%Y62Dm5ZcmzWUBr5pF%R<1JO0M-d zFOhHd~NGfG=bLm2`_J5)3-G4*XqjhBO>tBPO z#aY?0eETL*^ZkYsz%o`L@7^uj%WyrPWKGJUej*y)pX;2u>$=5o4Bn4pPy(-a5?o%c z1{Mwi-cvi*sB#Qp0dBk;+mSprFneuS^qnS%(Pa7HzEai-10f3F=2_B#d_fkP|5T89 z9jb<^jMUUIKYqO2wi`4eU`ARkLcvg8b&?2;KK(W?Jbk{pL+heR(}h^U6a!}hhldV~ zI)IEe_MY#;!uHKUL}^u36Ibl{6l9Mv_*Z_PG)HDumf^L#2*CpB%T(rFQZJCoV6fiJhU_n9rS2$nS z;T5H*jl)8zRRk+R55K{4MWGW_-+B)gg06=CpnUTmn6+xhmRzBRnT}Vp_*!RnX%d2} z!Dk6Q0+qOc;YdAo!0qGNSyl-rQC2J|sbc;?@lt%P-EGoptrf7HP+d;AH0xd4wC*Nu zz~&c1MqqjyWD@@eXw}f_fb}VeA3n60C4|)PlG)oaTllp>`w*u1k+~RVRh9{Rb z_C3B^4f7vxN5d=#$^&>aSij_o0dRc>eZxBd7_p3c6om3fA^UpncM!m+e^?1+pJa)+0> zI6@0SDj7oLSI2~LRjb4+GbW9uJgmyPvKeE2lfya*j zvFs^FhrR@Sc8&i7>1qICL<}(l!;oz1y&%jP4(IlpU#%YHOvkb>e_-=o$?}d#U?u%8 zcdhxRcY7y?qc)<1_cOHSv`+@LO{RfVfGeTx-f&1SzYT_0>Rs~v*@V!XDR4KKJ~me?A4u@| z&8VO=Kl5wl6Fw%efPjyQA3IQd=l-~5v_>-9=ifZlU4xV6K`;~3V<6~e^u79seq?cP zmEB~Ry;BGrDaTonUb9@}Eo`MQ z9b?k8FSoAY=-~+IzfMHzfD@5v_b(TFND}yST^%ba3Gvzz)NimGzm%3>t&+5V=iY;C zT^rUL&WdWMr>Y=IWLj>n)so5NWJCr#Rm5U^wEahjj4!E@Lcrf9H(ZT1G|y`*lNbCl z_qFSO@^O3mAdUPAg#h)v4g0ffV(Ft*Ktfk=?jGAORL)*eQ7Zp3c!MpU*7=O(_q1Jt zB-^AFZc|w!16Qr)ll$Wk$s&jzeu8CTHtX3zJ5LUkd#xYB^h%66?jQ4*r|L!9&WeEMhfDxUmtLv}Tp%e%!-kENNm!T1nLIows_M8tk=NHFC03 z^DBtRm%3MYBXNQ93m@qI`*$V_YV*}>;|3!lXaY;g8eMu^FrO!Bguex4pzjaLEOG$H zBmO3-?CXB1S3c8x0yuXfrL{nFa}^B?tW!X2_*)NVZ4hZd^S>$RCuvZ5S=k|Jr}au)_2a+bV_`(gEs(L&7oCh+ zHIrnp)v!LmjJIytEkPv!HpwfyYZ{N^>Reei;RY@b=;f_VIRB6+Bjq=hT1w{4L|N7L z>`_sqEIDIYk3h?xlD))EU0$MeCyd4LX?;rKKg~ur6a@5|K&&Uml{7;m4!y1hK8SAr zAj&H_X}|;n{yR#(ETD*AP89cp2ETpOaKaQ6wXrfwgSfC7Sy*Qg>_)8r>9d$i%-@WQ zzfNIn!T*89$^Oieo77AcaN|*Ce|%nR=TWZXW`bsZEbs9bi2C{<@m4so4ZEnt z5iXGV*~hyD*O^~6jJ=e$Ne4SALY3y87u3Y(-urtKeZP#)s4m5ZgKqjUjB7vDjKxKW zCOvd%=5ERVRNVLz{486X$^nj}{F#XZJ8;g?;WQw*gNINxKL*m}x*}S+3l-#jXQj*4 z8uI`}s&fP7Y@;VZ9xYRl3XToIn^m`O1jmf!xO~uu8&SXv-?7M1l{LquojY&W@AL?p z-oU@*%@?j$l;e8rsl6~E3dhbX5ZjNqa2XbyU3E4bl3Ow=UGK~fHUZO_NU~rRR!XFj z%R4R*5>?W;eAG6cg*YC_R;j37h&6w6Nwab*t^|;~OZXGBo^j+=i+o84%2@aweN}K+ z9T)vG+(gCf^DadCb=S->5R1-!?Aj^U}kJ`T;6 ze6shSTa!y?uW$y!Q>qiQhY<2OHiU|s5PniwleHLE?#-!YaqjZH0r#&TsT(Tmi6AK# zf7-_w`{9g1D%N|C0N6O$zwRN!oH8K3d^v}_Q{ewIaI*cv+HdZI{J=}aiXc8Q@t=@yhez%#9r%qul2o@NL=S%HSUV<mJ2NwD`>bagr|Z~sK-}>X_kxSt>DDOG5_@QhG?ljDU^0IZvs+wb zRcLXhO$U-21cbHqhk6P;TB4q|gKwbTiNl->m{E2u2>m=&1g*myQ68gcelvX0E(I?j z;NX`}`u2U;AO|20M{OplKO6&6KF~-^fcFpV_YO!RWiK0gXOjEPx38U5jCT51>SO%_ zOO$?je_9F?u5wM|9W{2@WiF7EW=myJ=K!jJP7511d3sOIN~)mX9SUdv=x9!t)Um2U zKCSp+LA(rjXE8cg#^+=1rF$gP6N)AnB^ZPM&7ZJRM9kEhq9)0RyA*%QRm*sefx^2= zC5Z4P4(IwmEL(DKgpK3A8EI2-6JLYU4PqnqR%8_d1MM=6__ZP^xwN*Jf6KZi2{&)#A@6A9A0QB z=eO#9-poLu>H)*h3&|iR+^Yz2~2}41ACNRO3F^hEP+S5}~A@0eN~A>nl6a>k(%$*WVwE z({Js6x!G_zC+?E?U3`9kbW8g-vN4_;meIXsb75N`>EbAIdb2xzme$IdMBHu`^U?@E z!E=QhBnGru55r3<%ax3cAMV8^*PtscI|hC?#~x0*h(iQ^X8-A-`osHRPS6|cHy+Yp z5^#|+9N={qb)$J99^HW={Dx^s+v>)v#GN1p?(`kfkbu7$Y?T2F2L;)`ys^c46s~jo z8eADb2;A4li1G|Mx4RCCpKo?nkb50|&{+wLZ*c^YuvG{|WrPS`z48(DK4AuOUx$@t zzsU7JJtI?C?q5~9{||IPfmAwv7^%J+UNanFcUmTOhFHDK33C|>&QKvy{>c~$$i+%Y zZ-5c3tPEZZ26d#XpNEl`YU@O%nZ#1@=>0m=FOJVns1Q?Ev>3>n0mi(n%cgxE2p{M) z+vfOvb~YyWs0+AL3QK|B4`LY@DY3!0Z4M-e`kr(0weGNF{TU|)21uoP&uOP!u51WM zUC$iYr7xW4yDP8uuNIn4Y;<{tz70{#PKPe~bp5z>UkGxESf!Z}ZZ!9PElFA(`2qHR z2@-04yYDpvg&`v+DCQcPdIJB6Wy&CB5M&#CR9WuY?t>{Lg;Bjtllib?TVPro0aFL3 z9!G*UCo&I#gkuJdD^bI%(|#tQI&~GEZ)kaz9GzNsV{TB6%egntUFsg?Z-t*l3l+}S zepZdz>>a$ArslDKt@7hk`@B8MLm85m6te~S9{9jE0F;R9{DlNKmsr*B2fg+;uX}$G zMKrsAa(*3S+JxyNPXS1xlV)<+e=&qR|B}-WTNYpFfHDd6L1)0!6Kec82tcT9xIlmg zFKF`h74~qM#9wFY`_(B2&%&=XS;|y=ox9Nn$*qq_UoUG`S6;leGeT9rD_#8RS>4pJ z(xkWNSiPdR^wzHOJ+C7t)qMgNoEP|1pFZ=_8{t~8?qlKEgA!swZdRkN>=~;FIPKVo z7)dlVCX)W`5o; zB#2ch_B>X#{1X6H+8thM3t`=*-kIRJCw*+{^Oq!S!^ZI6hm=9>#9P@LSFwzNS8>;H zxBUx!sAuK45B&3P>U10}#SRI@b85DM<*HDZ_@1p59$o-psU z*=1w%r@C})u}K{P`WdlJFc<>4;jmMYHSZ0*IGf?f-H@Cj>#F+IJnr-G#m2H~mIbV< zcBO3kdi@C83gLM01b);Uy^NeP(6CZP3!$dI(rl=WJ8@t(&`6?-A7cJ3b0zjQzQH73 z=*iE@7wS$C$+6`zUw~Nb11Z|>3y$2qxTdACasO?hIlyX(*NEK>Hg>U#tJ9p{Ei+A3 zMM%`fTHXYu6X7=ECXcvJW^>opA$~}TCG6vVVOg2s)bw=4ZejP~)Ko58iYjgF($%WT zyC>Er-j2Uo-v_K)`k=_)RG70T!e6$<%v5=(%1Y}H=2eyKhnZCi4QJudETdMx`=)Hv zRUJSvd{bnyJ);6391xlwM;7E#R$8jO_mSMl@WG@N=%eD7RFk&38+`^@lVMQBV$-UN zKUdp%@awY0V(nd<=qi{nigj<}!`u}qaxKJI40E+n$tTI7r#sl>kV|ObU?bcug`%k! zHwg*Oq$;(123HRO_itA;dUO07N?ww|$A_*PJ<=5k9mafoM|KrvW;5F&+a9PC2%oy+YakE5RasbogOVv`!%8n}t2 z1=$J7A6pH6Z19LtTS`lZofabVa~141wUr&j+>?} zK%PZQYNIXOJUnR~GK;+X98t!Y0dQYKj{G1=ASzWz3_r7aZp9m4Xkw^NS(FGh6s_WuKvX)biZ)ooTVdnj_dd} zuWJq8)uf{g4A$5@9G@i3Q&-IP4RO4w?Dpn9ivPNn0M+Wvgm)JdFG>u;4L8a}=4DV# zPW7pS0_1AQ!VjHntdtZ6m`z(ikM5qjaAs|dl1nas;vUU2`0iSCaZ^^3o5-bIY=C%h z`;wOK{>&3u2DrM=(U|!AtcW&GmB8~Cn+T|3fnsPo){r)c#dXP{nIKz81pDk9)eeJ7 zPdys?87*0?>U9h3Tj5_<;j#76|424Ur#}C}T?q6Axf13`Ox%W}L-X>lWzTJ;A z58)rl{PWIn4!S>@87nMaZ&$Trz(0q+_X>Tz!74SDvp3%o*nJKHU!Fg-n8Fb49+ z2B_zLt*U+(oVk{7g}XQpaXuEv<>2s)eN1f9qj)EAsE6xJvj}!I$Ed`05ydtqVe3YK9WpD_+^ijHLk z9FdJf6H9Ln!Ua*@`ulDxwH-ECAMb*FS&Cw6ik~clzgE*pJ(1vRnxqf5l(k`1SpK52 z(Ac)@TN(3Jui(r!$MQ|C!`YbiP~gsHi&^n7>|zll6#_Rbo< zK6}MqdhAMQTC+=)^o0N)$K#2NpB3buklq>wony&Q|9ryFSRN&vT_vNo@3Hsruv+3$ zuI2hora1OJ<^pBiC4SNL``0gMv@FNSf#!Ixy=>aUw#E2?&04Es1p)?cYg<>dQ(ejCSy zdX&1sj9&KIvY_zsi-V;hkK5s~IyyQAhJhT-4dLp6K0e=Jq6ga>yu%WdDc<`_!tb+a z{Ubt({!%TTd6O@nZGYoOt z>zZ1~jvC+9TB|8h5G2eS1kL1WE57P{w$~6v88DI|=G z^`vk(e6#XKav=f2A2L1Nfg|g;M!|?TrDdrxCOh~ro@=x+*K{#oF05jt5{EXVvi9I3 zIb+>imfOqsI&BWfOjjpUUMVhx#5kT*2Yx79%pq6qMzdO>v#Iq2pM;d5BH2g+b}8e@ z)SMXs+WkP|(A5}B_RO>kG&nSr2xu>isy#YArE-&!ScQd!wPsU!_3!)C9eN%dOQyXc z=Rjsthpl+43P!5O7pAcMr}VjiO+qRG~E}llyTn@^|rH&edzVuLdVnG2O<+rsU&Lembv#UDw(U`MORfjIYZbu_Ie{5$EGjnfK0=)Kaf}-%7N#c zSh>=gE(j8SDgw-&l=GN!D%ApSqvSIx3HT=lKpa-lA=3%481+Uy!(jMp=W(rhwfSA zm$&_syXHzhZ8#S;)C*t(HlG?1*@|;C=WU=6$r!w@54Oi6yt;X3vKrX3kr6Aqn|}dl zRYv7!YKe=k@Dnb|JC0rU$9CGHv&ED*mk%X+j-Xs(l_U%2G=nrji)xw%25cLBM0cvn zWws+N$Yc*O(`7d+0o`rPvDA*uSPdBzR1v z@t~gQ=3rbHrCxu{LZ#Z2M~^T8Rz8{yZ^C__w!F&Xk1d{p8~)NhnX64ivg0s_Odo0m zdJEy41j~P*~W8tr{^R+GHTWx*iwqSBiboM z?z0j$2zpj`M;?J3Inx$Tg|63NJAHr1+O58h&8?0osQYGItdM{M=%@Dad>uLYS0DE? zh%9G*4APk0@&!)CsxxDvkvdc0&ykRk_HAHgmL0MAftS#%ev_|F*gOOU2!Bl+ZE5V_ za4s^nxR_eHk8>S7gy-Q>8a!m8Til$&8Bt-D@+9cq4p_O0eJpUa_cWL;f<7k5siS$PaJj+J}; z`gKuh=|r2uJ^Y!VIH@aGGP=ZkhWij#C*%v=-E*K+;I{TZpX?WO)!8)6L1$o8560r3 z^T?^U?VqbGv2h5=Ss1|5eN+Rd+vA5N7GPOG!FpQU4V4R%0ypE(%2k-Z!1LQXs2@)S z-)t}mn*Ag`mJC4m@&{_>23#7xdh;f!sp+|0=fanDcYh<=Aco`qF=?5)aah|;G~4L{ zn9AY$eLZe0Rz7dT=gTlCx)5E^&>-*XN@%F9dn2YU3+};szh6odn>BKA_w)wK>Va5Rc}e))yIc~##@wUJApvcTu*%<3Ij(UH`_U!|&Txf|W9$nNC4c^4=-*crDrAWUa z*&SCkM{kSHF$Y-@&KxJ>w3IYy5?U7;Y6}P6h(eh22Jy)rw7{9#j%T#hZzDyBpU*)E zu?X#2vw=!^bz3n_u^ zTxGSc+AQUMBfl=rmkbN9v%xN>h}~P$rk=+Xlao<|3rF|%SA5_2Mtui=55UGC1VF0H z{BMix^;g2CFZ#u_$14^VT2>fPkBrfu%t4-Wz}ky)bI5&+YcQCW3X2^8hzo8drhoa^=?aawVEWe8uj7ebQ(oK%bK zv9Mmip-swuq*TlRqor5Z^6xvS7hDnV8;P>|-j0Yp_@&LUpwRhDt?w|U4cbQU!{$!0 zzGv`#=_V%ZoZn$jzdGC2Y5UozT?k5>)O#zbJ!w!jbF!HJVmPuC)N&6Z7Ba z7ngRaBmxDq2>d-{GKKBtTHZ45@NAFdunwp39-oPOR#zKv$%TE)V{Pi2u1a0i;9jwH z$v<{SAR`-Umor`2t7(JFz=^`$?7d(eK(k4R03%A(SK@?F63oFtJrp?4OO} zY3gFkya&pCLmPauB10I%6VByLJ&ab`j|oFLNyg!L_ZEIQvrrPr1Ai-}L>Hr#D8Adz zB?ny``_?PUpBMWV1@fe|3m}ZTp@xHH?}mQ5wPHlAL3D@9nK(36m@xqm-oDom=(oYq zU~pYM5st2^>Pg;rX!BR%baL81V(Ka<>M4hONfi}4LXyJXlT1TIH>!zR7XFFWD(wl@ zx#lrG)=c%|D&~e&-7?rMiT5V!ZtXd5lO8)Y&Y-MLX7%4DE#jq|Rf933r|@5}eP4{4 z>Zq$EQ(`|AsvSF6CZ?xR!y%3BF1#<@+OaD=L=fw+!gab zafaAocOrnrhd|B_WJKa1-bhTuPkGSYAiKG$cXn78-k|sH+XvI;eC6HHs#NGvH?}?( zG9|!2Rd)R+1srb+!KP-rx}9&S@7myZ9&J1I>d0)}v%@-kq^9*BdhEKzm3BUeV6yYs z=#AY~X!6MhpJEYFh_g#ne^~kao5C+8OM-6u+5I1HS&iJ3KbGlZHuWmEfpB3_;L9Ua z?3oH2ZrRh>Bj{`!`%qf)E#WqK^6hSS=@~+n7wbKBwHt0q@4;0YzL;q@20^SI11)Ew zjK=G@a9ymTl%6=|{dbnS*Z0!IQ-`0cbDxi7h@<7@9WSa3Cv$nI=;#L?)V}naMd4yF z$PLn>n$m&m6zm^s%wy;c5>biN2VeN^&!dWpmMSep{9(RM8@W|X2lH5~96!bu{iFBp z&0h5Xw!-6Jq+bSj;qjc{JDIZOq);l}QU9qmrN9?~5WZuJwY7%}M$^n?`>QD%e5z^R z9w`;tB5YnsP1qAmjyx-Kh#)It;2jNd^WV<0MPGYa4%9Tn59bJ~!tOWGC&>&yubpOzO}|Jfd>OF}{m zB6o{z&!Su1Rh} zKNnYRE2#39E;rGggS0P;>xm|!lSb01j`(d;1o>R_mAS2$7BsR9f`$yhm?)`%1{`F( z{cH^$3g^F+o;L{$+b3G-j7@F4P9fJO0)Zk%Vo=qD`OnNp!Pi?GN>L9NxRTlgg@ePd+r&JmR zKz|4Lb$itPiJ5)3Smn5}9V$awdJ6<<@xpoxsZ6iU7rNw{_TbninMV>1%3+&%|A<$k z;v(t{<-fdgg^lD$Y$bi#U>S<8pI>$O(|`d^`Y(iMH+a66vZgh%CQl1o1>0$Z{O))V z;#^^1j96%dHenvUx$|Xc87-c+5Q{L)UIygBGrS3~2}h(`=cSxjjde2>$i_jqAi{HM zO-@ZsPiM*A-aav!Og%_ktFbZH{1;?to~cP1L3W7?egMHo=F_i+h5r7T|R zQ4VJE$L>oR+UBT!P@@gSIVZnn`N(^4<#&=q~?FoAXX( z9SFo$m)nW`$iCS139oYZ)$XjI{cl;G{c*_|s`=6I>->YI$uPohcBX~h%5m_w3xxd1 zczAIjut8`AXMBG*`-0)eh3a!>y}9pwmIh38O_RJ(+Bg8qi95$*zKi& zZxp}|9|x0l9sEHjzSrPtb8UKCE!;D@d-bZYj1cJ#9g&6^l-ub9*dQRU5phmWg#}{9 zM(c|+kslaGrY{>S=g>JQlwO1m^5e zaAmQSdE53{>rUH~acGu*zuxcKg-Xf!=Pe|T~D zpkY&ELZu~l=mt*hfEE^>m3j*8r$D2DpoBGG-A4pD6y+YI7lvm!)Noa05Eeu~BkB&y*?vXzyT>D0Kth_F8uhL_f z2jMfk03q6d2JTv^%g*B~0~`e|FzfQa4=VWggWmr8LBoYoi1z-N(StzeUz`GW_m?|I z55vd@AsCLc+C|@ejGf?`_!m03=c;YGDFi5fw?d7E+CRzOyQ;Uw$u#{?qw{lhab6 zPlU#p7&ZQ`HDuMZ+&!%NJ#q`c3Xqt2zr;jwh!COacr1?1>U=~x&M$puG>#~C0u0n& zf0wqlxIRm8s2(dCC<<-~WE;DfHZfGXoEb(OB~$e0a0niWCFD>OsUQMc<4>WC06kBL14DhMc5_~>1?U^O^o??>cFVPT7FNUuacJ^p z+9+<|+^HhvI5&~uro&-@rmpHX#Q*L;2aS=g=Yc`Sb6)p&P20=8s&{Rh zOxUZiWT@7YIO#?c%#Br(myreNa+yq4ijO^8(@APRFU_i5c+cHSPd>vHErzFI0UgQp zwujw0XB$hzpGEQD>SS7aOuR?ows~J{Yf46II3gl50P?_L=GomCRjB2zOFr3CnFv#zm7o zMn~^=)+3XQtzFD47v4lPUig){AohSZ=vdNsVy{(~i3iY_*@Ib!Nq58}y}VQX(#@|VGTa?RR8`=xx=pjf6XYF$9q6gKvI ze~|1a6R&-$3IFS;QjCT~xGZCAY~h*k}j%1nE~8?jMNLgsK*_7T0r&H_&y0|2Y9Q|f~ais zj((5HqFftk+Mv@UoKl#(ViWAT!1G9&O;b{1B1o??#*9iZf9nK5Ix9R2i#FkLL z=TBEn;?q*yJ>O78W5qE`6XNWu+-DggRx0Pqnz}kV${vj{j*et&tjmov#u>eKz3>hZ zS3f5HM*4b()#tErz5-TDoQflAGr=t8z7yXZC~^!ZEguCIOVI;Czsog-npJ}r&rqTvcvP|z|E?S9)-Vx~0Vd+s(rKR-C}L9PN#QR&SE*{F#Y0Qq^5 zb#?mR$ZJWLb-dHk(#918HMT>)Twj;2zG)HEj?G$^Dw&PquS$GVee=Uk%QR4%BspH7S?5`qf@6SrT`PG#6NrRo<=lS6Bm;MrJsGb= zRa?7qgD+-#F%6ibxqBCOHOKQ&#fIHb zu{0H6vz{di@}%d}zO&*+<_l2@Us)G(WIG3&6Xs33SdW9A;k;;$gZ?Ox?0$XkMjL1s zIxOcpnip%cN!};_Z3>^PD)uS=eB;BRS2KiPX>Sfv6D?Rlc})u(H!KZDFB{_YtFx$b zP_K{B|C0=#p0AM15g;=#32;ylspeIeGw3%PMAk{R~H}+E;IlRLK7P2Y^f%? zdw<_}&h2f6+i%~%nMtiCxAO9N2(Yed09q}FKESq!VuE)of$9<9F+d=aosor-eq%j) zr~jRd-52%ch&TXb_B1}mRH_dIztR`ylR*4-t5kW>2=L?Kf*|-f=IdtEKwk-l*)fV8 zZwzew|H%6Ca46e1>_MoIdLtcpFQbTLnXF@< zr0k4+?4#@klVyxqpYPH8`+eW6F6zv`vv8)Y43B8a$QbhoO0L>3 zg3{c2q7%gO-s8F$t&5xj$KB6AalN3^PZMLdtM+Lqgl^nvQgnhOYbNPPf}twuudXFG`TI*`>;Be@uz1FM?I*HM+RM(!S3#8D@O`<7PD*~$V>CgOAdI>pu3R|=IWK{3Q%742KkyY{`$~F-p3I2 z^g|~u%t%o2*|Y*t1J|tePRMG>EGD3G#8Ap0^m2RM-yNB+ z>o)^=WjY~4WxxPmw?CfPdqR~B?xn`+)~otXxL{m>dE4c89Ha9%xYSuPlqbi6*1f-8 zrYcxZwA_pVR;7kBMnX!q8%F%6G8xNU39~BzdWubpdIze*D1Av(e5P$Es@iQcJ!B^^ z(&Pf11p;+U8Ys?hjWapBe**)H-%%2P&n^M{zkYwQA+p;;cRDnc5N~M4GouB)oc=jYxSM1CXK z*Ad`-_r@<2Q+C{|0O`y*E%(w>FkkL007j>1R)hKVW3@9+2aEk3@JKy2aG<8G&}RXZ z46W0`SL%uN{Tf#>u1gG;opf4V?0~w>`2^j!HG2VR<^!`~a)!&e?aci#$3PCq%y|i} zTT&ez9n*^oYOKP7;upwimlS(fgKn=xj@^HgxbUMeVA!nk371}5=3p5sfFCL`fuLV` zU%$mKylY|OfX$s4TpLddWs%6r8+UN7=hC|MvuvCo&m9GK#-bvE(m85=P4m+_m54JL z23&pnu1^}WHGgYMH;&2Qf7{*+753=s{Ik>_8V_CNnr1f-U0y(QjAm?SO6q^ou<)>J zmhR}0m_hacP!8%oJ>XIdvET_bO#0kFc_r{Qhws*2a*rgj&--R(?smv;f*#3su&cQw zWEr>nOmix<2=8ydV=>q`Q1fULZf(7J>7^QE_EpE_32O`amevr?2db)=%6zdJ4ZPEX zPK1h%GdE{UR@e%-qLu9Hvpl?0mVq~^Yq!FS$jUv;oy`=zW9f15q1s3PxtITAbAgx>)$EIqwy{&PrLaQ3h zx$ZwF>S(Ct1>1c#sz z#~)_m%OB+)x@wO)2QZ4F=U4gg0`=2HstrndR+xjk%=yzU3G%sD!TcF?$NNviFeRYJOIV=l$L)=<4RsGamWBY^0hp zX{A0#%rG9hS1$8`I=4-e&wPJzB(!i`F2O^klgDL_{MYA0E_gXkOF@VHC6p4es%?1x}pLmkf{I z+9OvcMxw@7?-)LzO3lb&<4~P#L^fmm+p~ehI~xA74ypV#1gN2so6XpxZ0Q`HW}es+ zXZ3d0sj+8UYd{h zl(_C!=W&z=0pR6d%Wmj*U8;@WR$2%5Z3cXvrF*)f5A2GH9UhvmYf{m6(KNk<<-Twd zvj2b85yY7(yHg)Cu-8GF+Bi7qhJU9GM_qHxqFK|1d!Vm9>ic<)h0U_P@ZS^drEEFQ z3hfh8NLiMTJ#<{8PjY`HFPquMux-fGXqngtyffHRv128_TWVdF=arz|4<~h(md>ag}K0~QC8v>=m*=DK&JE?_J4Xi@H|Xs3U@wiBqzX-DuA~5WJB3WZEdHQQSQ27T%efMtI-Ks6e!2b6fyv zR3v}HEegWkN}fcdlAddEj+~DTKVzB_)H{J)5f)u~`(z1@<8MDWX(_Ug!PMo+`I!IS z9}EjKKSb=#xXep5_Z=F3k=}?aCm1>Q7!td2%m)3C^((|!j}FMHILHK&-lT_*6}3HO z)i{a`M)XO0ULR~brGEJ@QE-o6Qfr2`?Bhs6>VLgu7W|%_hGI|f>>X|JV>c_s9P~iV zqdBxaCLI+`ssa};qA8d7pNPzS?QQY<`k-kn=o7zD0e$gt=wC7E!Q$6mO+KEDndbj$ zvVzvCahNVXQdnXjyEtFKvl@5*0+QYOR9*30!B~jv*)>}1{34#}%w*BZ3Q7tai%L$) zw05oz8af%k8%A|x&VjCknl{}-vcJJ+o`^6}{gg5$6qnQ{xgqdDKHWqeBECX8t&;*Ik50%mVS3gnJj{o+Eb8!nFR-o z8DRyHT{t$wvUa-@6AH%$J0JgkwqwMny#l6xHifw>Vm~g~mw17FM2YL+xBe^vk^k1m zMW{rNkSG_JPwokw`(zD_-r8AG_kj~y?vZagJKo03^M;i~tQ~$xo^C81mg-o<;{C;V z`%2w^J+eIfdv4GbBq0etQZ{k7H242?^O!Ud2!$d2qv!Z@blxDR^h6`)?=g_c9*$qC z&(n=A`S=7tWBWo+4QKpUZJoNn-T_TVQ0cm#dW5cETyQSz@VUE(r^HnI9&7k2veb*$RNNL}|%ST1`m7gm;Us>j21;(|}|kgvm(7v%+mDaNc=!BBcaGXuw$ zFJh})dn~V;Z#Y9NSEt4O>|3&rRQ)10QGJ?#+O}mfYzHpre6jS5U}!1D4aXez*~AY| zaJE7ksOgK%BA*xCd=Dv21bMZ61??(y!<*skU!X(&m zNnQc5qm(cMkc)$tHb%!L8`IV&P%%})r)2c%c{g1}M_a`Yw%K4mnM^xS@`WLlh>0PW z6)UIK$6_8IZr{FrF=Pjx5+?kFf68lIsRi-D+ z(3-w*jgM7Y3ueg}jt5&*ZIpZ~ zlayU1s3&k>l<-+q3L5`T$}s$&Ji*cBM2^&ibfqX>!7|SMbe6(6`4*kku}}JM8hbt< z#((y|uXtjSs8?j!;Re&|p+mc-qV;EGsYivFgSs4?kr2ptogPk&G<$pNHeaxC`xbPL zU1d3#%__{-qkyC&-*;~^)yh$1PsJ`HE>V#EG|mcK*_3*yakW1kYZ=UAd3kQuO>(CY zpa?70Z?i#8OX_Na5-_{9Y(X)r!+{~fKH&9wyMh05fAuMI8-ZWf75w_%i+B1yn5gy$ zCoj|G&6m2FBq21sZDpKM>U~C7LFH(hhi|i{;!J@k{f5RWl{}?d>mhEO>=l?w-r2CK zt~V<${~+aM5+%iY->^yExyMyOr;ariq)t&V@^E$s*e{eeJ-ZL!IZ zQE7z&3xNWRx=Mr2U?N*F^F&=&mPy33B2C9%UU?Mqx*w5hV_iL57M@?(amypo%p;{c zFUZTmI4nWaB;l@Uxu%I<%81|#x{wnP*NdK8*}&99oL;BExjI8thr&K6QsK+Qpw%4- zQm0Db%5%0jl?!mw8;BjIZ|jWlK|N%}&Q2X|y-S-yXd^p`R$p{Pyb~MQHI9&E+F9 zi*FIWs&T*aP&@lSHe_cOZ*ftK(GugifO*ORAGcNC}Z`}kM@Ed_(L6#KvY4tvO(N7Yy~A=Ytv2;9Ac2M;#P`hk}XdGy>& z7#~-PBJs4_n_9Kox@4~(h4tW5$_7-T(UPh@F(uQOIE8ED#UVt1c|Igy))Gy@X(Oun zJ0+Er6+8wqlO_8g@mX0nSqB<`o?Z1aNn8-9F5q#O6!JG=Mu{te?(#{?$PeddGxjg1k$Hx zu1hNpVqN+qAW28(D(dn)AgH)^>$3#QX}^wpo=~bVD;VdF833F~m~#|p`;OxW_O(4H z)j`p4{vYhF-pdNO@Q#WjK4HBfDLW=CgWD0T^rR8hw^cuzCm{U;vK}SM2~$JTI@iRC zTlXg!x_>dd;PLE@e&|1|<6*ZV!U*mpk#;y^;Dvh7oa1$aA*C+%qsm~UPrxUMw+dCt zJp<|wQ#BD6Tx%L&MsC7y7i1I2@G zaCaAUT?o6D#j?erPH$3PfWg5e79B>8kp4VNqKo5Z{WH^iQGuaE`(WF}S3D3_J%l?{ zh*t^(UdJHetNmdm&*R;>A{T0DuvDbdK^82Py=XdCAA0dI!JaBXV^j6&kN9meh=7A+ z=$Se|sb;xT5mPO8r1D};V`;0W^f`gU%j5eW63TF<2Qkd!Qj>GL`mxfb-v*C=1}W8Mu5r>si;oi{D{l}&-95o>%Q^br*h zg6Yd4ub}jSpUdfH%PfLs#JI+d?nbLez?ERrxmj4$IXQ@X>iYhA5-W{G!tXQaX8*p% zVz~ic$I=ZTE}W5}tF{00MtJuxR%)mw+4{0C-ql-)C9*6n8`o*gIoWWr)$^e49XjlP z2_H|Lj)*zVZ#S#2t^|QRy!Q#-_k1Pd3YvtPe8;|K4s3k{4rt&q=b`Za2{4H&+1F{# z855RG1NbkXdJ2~ZGJh>Qd{WRF_B82hdk(|eY*lW&KUug{I(xxj%z_}?q2Z{4bD6vCIOJ66{S2KkEU=>GJF)(HknBR=? z!fd-Dc9QTIr>~;M38pzrEVA$D}BmR`;s~C zlCQV>yC=(8@FUlbzDc-xJ>fZ>$GW`I#P|M88t_}jcupK%6o14zP2KVLEe~IxvIVc% zC^r2*cK*BO-?vb|)`4XUU6g$nO^QgsvF&i8yw~g9%C#dtn}|aN)^Yu0)Ry+lu4(Zs z-kE=lKnT>_4Q?&A_-H?Vy5szvn2@aWWI5%Yo`IpestVN%Q!mp*imtY{)#uNj8!*<> zP%6yN??(HqF`QJEchRVzSVQRYLlT|5Lq%+{q8aeN!5dSdyKLNALA30#g*u^C1V_yu zG5=A%qW#Pg>QaiTtuKprh>gA_0lNj{7TMoUUBCY>w#Tt`Za-no{fn>CDdk0YFuVvp z?=0}v%JOk_d}3hvQ2P;bxg*g0x(!c8bGxQwPA+&DE$s?Fx^W|YcZYEJjnr7_{XY(waTb>Ixc11_WC03D3c2v-hhmMZb`djtQ%lGUmQK&yzKn!_u z#@~!4Rqtx2i!B9wQ9ux5tF4Rjf<6YspFmk!p%?Rc?1O%bs6K|19+81rt~$sS{Rfa6 zAOU|k(BW1^LM3Z@nc*T=X0~tCyQAbOnV?rG|NZ-m>KYnc)gLJ(cC`bc=B!us0D?u<`-oYJTZD#R(O9@G zTLYXDdlke?!;=6Ob$d+2Ml=$|Ai+xr7Wrn$aZvVm+ftfINuEIaMw6=!qiuP2cOV6) zglM287u)^xNJVYJF*f$UJ+$AMFB&7zDDb`P0PG}pg4EXz3g0pMo5kR1?(B6#yaDyE zv8`^ST2@t2<5mFw*Rb`i@I@4D9u=~P-0jyTpSNse7tc}_8?kU19xlRL4p5eYItz-8 z^SWN!Rv*wGd?6Wd$fnr7ek6V8BU1l7;uAIG3;bZl)qOClD;XuNFUUx&_2!mAR~6&^ z3#lVTN50|oWC~h&TL1!n2>qCWQ_WJ`c*rK&Sf3WLBTarJM58z+y5Z@fJ`ixWq7jwV;2o=QrE@<029!mO{6a1%t_6o|F# zZrn&jg}dc?GkmI;#=0*Q`ex8VWM*-12$s;KAcQ)1w`uolr6j7}Na^25Lj&Z^mPw@n zTL~}c6@!qTF1t%I?@X$NRncGsNt(XO1wL_@%%zJLpJ)xY@}hLfrHn(Dw@nuuo%(L0 zeyyPlcyxf=3n;~+ODeGedK-SMS8bb9!@C|2ff!%lnnlF&LD;bhTyCrI_6-o47{!g+5(md#=HSkczz=22 z#G_=sGigs;p85=WFojlN#VkbZgI-_>50~#>ZEFf zE4u{^AYLB*%027^YU2@G7<6CP#m1g2aQddDscF;PRGj&KU~+P`hkr3V zko`^$JIUlK{FJF8w2f`T5>K|l(2~Q|ReXI1qJvGZd~8?N#-t4PHVjP&oH?wzx7IVK z3gAY;)SP~U4Jp0tH%~p_Nf3VK#U zqb1#!*wo@yTZ(|M!>3WS-mLoYWUt=}cSBalwhUaY!Z};>I4z-o^&bCkg(_Gas-8uA z@;EU|=hFJ_6vAbod1~`_y8Y(QYX$8HU!06%e?c&x%?p!+8CJ&RLuCgm#x0B?f*)9e$XfUcfpnluJWuSf5NR* zQTHMAC_^fKu#6qCoiZD~z@m%6TIAop%to=vBikRM*@J7?r^nrm_G)n*!qsHlYc=5b z))z%5LwX#?r?&f_-V9D3Qzha!0&Fy$Fq2HPn_p8=VxxnO**t(8taq!IAf03F>OPi` zE@rLi7RjuAUlHRrAj|plrQqHouCO z#WX2igKKCwioIbUyfAQ;OCstr%BL6%-#IcTc9l@{F}sjed{)fyg_Jf|exZUoVT$}Z zTPpMC1oyFTjH{%RI`Rnk*M=7sr=$R0$S(;ex>`Qmsx{o(<3Km$jXW557Z@TlB*iq- zdBLu@_Sh(1mkGqgWnEQy2T=T^%*=o9Rx^v%9;XqDKQ&9TK&gzp(0Gvb6%p>|S0R%0v+JC!K zjk9?Uz}W(VYk^uEfflI0$*AuOKkf-3B_Vz2O4E9+{EUw6J1NXIcg1$6*6=~Knbod9 zB*PEbWOoJf*SU9Eporr@GuSdE5)N?wigR7R-s?`=%O5ICGPVvHu~ zqb$cV`!{z#4>*Jpi~|0U^=mgw_3F#i+S#T`VwI%QYv<(nloTemx_;g2J}$d66Zd{g zbAO)G+kLr#nwpxsLm=dA1UPbvTH~Y;27M^m>vz7U`l>d~bo^FNgX{9xX*%`NR0(QJ z9~59Lq!*wU!*Lw8%jW(r(!*v#}yol6kz%*v%P#Fj|)D4P7V< zK#VPmZj~#>idjjsIySVHH=FSe2UF!GrZ~A?<=5>&7M=oLaN~RKT-a0FXsV7fVZ>A81pV&r2>|zASB;@H zC0iT`hc>p71nomFp+>d$Zx1LoH9!18tV7g3`WeGPMA_QfaJD{nGBax3_r}%iYoeQ$ zo}^banr3BZCqKz%OYAU2-a6)I1y|`e&8b-%IKK=x^-Z{<@x60qP>tiG%x*Bl%PP8I z#M*WELtC+Q&XD9gsFKvF=!I2b>xjgA=20jMeEoPq3GYkZe^cQ$v~K75J*2^2L7DKO z|9qXCE6oyQ!#F9w7$U%?9`RAU%bI^O`-;~EPv@(ilsv3SNu^`MSC>cnkDqglJfY+F zJ+xFna2)agT~N8vjPBJ#I0VEfnB$D{+26;3L72Y591R;W73xJVg0Zz%ci0+h`ii$| zd~DrD9H-bwb=E)2$Q7nwVfl^No=xUdZ>M)vK1M6=F%h0O@oJHT0UAH+Jp`h|fopZp zJsoppBiALXu3kG|82>g#d?d6jpsQ2Vb1KoyH7Aw>>#`+>R-3I9H>t3LV~~izzWmy*~0TR>~K2wc!mo@ zTsoa;yR$Hm&h@e%=^8d|&#QKcBbrVtS~WQK?1Ax4u*4akA;LbR!d9Kzp^_gGagmn? zK>!0{`G3N{L^KNTyQ^oTSKoUNC2>!MY_}{b^}7NVZrs!$k9VW(9>w2Z6l3Z|&;vln zq@v3(3D0APnhs-V{eAAC09a^*Y#Xy<&{X}yx=#GfteIAX?cfVw`yVX{^$rc3Ymplr z6ay;r?WfwX;S^!=mJ5js^zC@0xp_YQhi%c~(FBCmZ|&F`H>I?cbo`wzr*ALpQ!OSH z&=AiI$A_;)Ed9Lp-SeL>V8lZ-Jp8NUxa<%SM+HiNHBl#-R807?;`AZ|I=P6uh18{60n_hfNjd-(6NK%txwL!KQcUS|UjPSDw#qnx^&doR9fohPo3f~A1@t%Ld z(S^U@k}p3KjQ1HK@qQO#hB;B{Vo)qUQxMAus!w4||!$OyhY(bI!DcbvUx_3{NjbNrjhqutLuz6uLU@h>(TSuq2 zpH^k#E05tZ|M2-=v$psHaMtU{k^K11!^`*KJkHl=(&OVUg0dAD89`s!OFRzHr#_7g z5!=UPbTwI*%sVx$^gxCV=jcc=I%!g$*^7cBFT&v>+=cb^D^#L+upR2=l}M%@y@J(E%V&?i)XqbL-by$7NW-0_#?37_+c00n$XF}F zQ{?D))h8T6wZ{Ca;8xGU&-ybN_D%sV1_gDDODs738|uD2#FOV1NPb1t0Uxi3o?nSB z)aNpmJa2Lts2{LdJ)-MA7OFhvnEMK%fRu3Pzhp67r!e%gsx!# zpA_W((FbBPBA$amJI8vx!BpoTC zLIpTM3&d)vnnMlnY#MkK!Mu&rV-PbZ^6MF(vz#%an*tAg)}0>sI@i4O|Qm^DTh(-cGi^5<`sV!sMl9T zyjdNuZK)6c-fmY|T6(B1JiPh-n7#G9eRgufshDeG4PAjZSnF#*ck#uMM-O7-Dl0WT zJbgDo&dOA>ZMu{VN@k?{LjY{~k#F6M26aEScW)(MFxWpRDGV4)5(wJxV`c>{eDvG6 zVrA>Z2;>!j7*d%|U;`1GAXNu>ma%8l&Ov|SJ+KyorhCD9KJVWld9m(@2}~v5gL^n? zCzUOkQoN#Y?H$#NWj<|%cGH^i1a{+P*N6q#5GspW=Mze?f*$&$F{=7@Ek@9zB%62y zMQ;x6cpKzVtfyp}Y@Q%~?C}V4H~yqw3*nH-Rm9_S#?ft^b#xT&%5*Fuv0&%W&y7rvxe(>8kbw2Y13UfuZ~Ha zq2fjXo>!sZ;xHJ*>9<83;sTsO!xQA!JzTnBfm0%3N?0h-7r%QA8FpUuzNp?=*FTzs=Yp%1@X-^eX|xb^S8A$n zS|_8IOzKoLh|1JcixFH_&W0b2lTF-E*dpj zjYUQFzc~OVj3qsDFk1xnX0%#mtxzpo%Bw>^_utcqP1<>Rgr7o1vk=hMVt_B{T}=cg z=nuh_dUMKL4+v`Z zDD%ww(yX6M*wOrWOY%*yHP-9!TZU90)g6n5u}SyHUf{8dB^T7i+}BY3gacMl2KlSA z;mf!9=v>#aKU$~=NK?@Iq$4*+eU!m&!R*m=-*pb`ALDKBce<2Y*l$=Ha|<;5s3Is< z*l{VO(vzzN99W_EOu+V`#pU_680)eT+!7nw{*9Y>P?t5X-E=xmpUF$soTTek;Z!Y9 zpOns#2yG=j3FG}aIRZioH`nf1Iw(VT9~AMEUREgWTE^%qg*x{2lQy28KM=;?gl;^q#Y+OqE01g&jK`F4$Ab$nA1Db zj-W(G0cQk*1)5SxsB89EtZ0G4Xb`Ku49gq*ZP+QbboNq-F^lB|OvI@PcTnR@s>QuR z{teS0zKbTzE(TNCO=|ILY&`*0`J}ca^K0{mG9qIm0Gq|YIU_BO5(AdoyD|*g~cvoqSw2Ob(1|+`~kO9 z30xJ2Te&Hkopd^QdO(FRmGrZMt!-{_`*Q`)4Sz65PeeSKbg+_<@}2N7C}4k|0}Xl&Vv1+&Rmo=K~t8wb>m*F29B z1kD>&BkAYoYP{xz434)vJ@rT!R%Z-(McNNT_A5rOYoU;wk3T zwF&tb87p(29vKiM&eZirNU6uL$9*ye1sxk)Kv2Yb8sV0u5gbbm!weMXITB4-Tu_b) z(ob^5pL%QZ7PPgJug|2S6Qr(W6A&pafy#o#KFCkGItVvJy4S<_dd(xnRZ?o{5Wmm; zVPJPf^}$WYK1t2XzY3KmRxUs-#+^S^UeB*Ib-h!sg?VpqJy!OkiLq0Zth{{JNQrI9 z3qwN4@PM3ZX#~NI#dAHu^LjGR_1G2UZPeeZKtC<bbx^QLtG&m)(ldV@ zke-X}z~=vqQ1cc$`uVK>)bGlw(7Gv)V#+oZH`7Yq0WVswW>yg#NS-WENc{o&j@=h= z6Z1Xnbg*mtWZTn~LIyDmfxD`D0TTI7g%?2uWbBZy+2!830(P;VcHTEhO!RwZSU5eID zpqUl==gLc7v35Na+sfIS?Jj!0*sb;Bg@-vdK}q*I2l4DN@qOEF>L~smrrPY#-#E zp-^ALmB~l<&Hd*IqW>5OUAMoi){I_74DcIhBUz-B==Pt!6Vty}TOuZSei1vVLA>@s z^y}P)n3Trtr&L;G{9wtv4ZD4sGEMWx<8INPUN!`7{>FT0=nOSz-7!9*cxJcSl}B<> z;I~f5#t#v27z@6hxmxQ#KkU-g;1Xc{MLGv}x#8ahfc*g#Ck9ly!CtJ_wZ)(&x_x>_ z#Yju252tslAmn}W*kT%}CH-@NZNKGTi1c|jmpR|zEDrU|@ebYOCQ&+Z%mMLzLo>w8 z+AKn<{3Z@`63|@=>6`HR&T?ERIM@MsdVlJt8#~y?QK%c}4Cx$0!hBGi{^rZMg@qgU zk_x&BO*>j4%vV`{Ti^6S;b%Kl&G6z^_tWDnFp5DSp$GTuh%=$T5z7Oo4Q$#PLKZ1Y zJN-y-xC064V7+{zW~$LE>}vyfgHIS5pQ@HiTuZDzVmxnTTh#tFpipV*R7-+|YzRCM z8*T~A5PJ=(M#8gt>waB=9sZq;w!H}UG-qPpb2Q7>G0poj*t>1ePVKm3g`W*&YmIqB z7BeDqda1#?zkfz9TG{KEZ|ZMA6_=DJ9hf2R_=tzr#7a)- z*QxcnaN3+ceOf)>lmCd@IdE@f}ZOGT1)5X!c`o55MG4OK{;o1#)+xddp z;nEnTunC5)o>!!^%R>9RT)npUjNQShJH%Uxfs|_vTZYU zd-AK}UzGnGjwgGE<0YTiX#K#5#UeojZ1qOjxxfztCjYk}QxY`ipRp;fAK$$dK3y`EsuC3px zm_F|_?PD+v$6e{oq=+(JJcw_GtT5*tBDTgVXE-_3uz10LA}uXLLt>Ep~Nd9_Odv;kV0W*(dSL) zwfTkE4HW_n)*$P5iBfUIWz!?_-1r;l-VZdw@5KkmFO^*?9>ume6x6^jusaFg{U!oB z55gYe_2p*>I5UHMBhao@oRboZ5b53hb_&7c2rp!=tf6ik%o3%vCcto> z&p@;4suCg0Bxp`)JVzz&l$rKSNpA=tx(|_wwOUVjNXeyug%!`C&uBYqn0q)(&E7qhySISAda z6S9qpHT3k(p6kXLxxQ|{CWZ2L;m9^XWW$cl;8L1S?G4$4wPv~k%XAHxzPXevlm#j|Js%pr7Qd+_ABvOT`QsLuvM>LwdTa=?adu97my%@6^|)s-|H)RlWh?3z0v ztD?kX)6Gyd-6B=r*ctuOd3D06hj5!$i-CuJNztO7A1hlu?{)SjhT9t`2O8?cclhfv zc;+=#G0VRVb>_albZL#_Rz;{(4EB`&ybyL(7vAd+Absk1e#$3#G^ z8|*yPOvTa?Rg$-Kux=D|h<>7~v3`~dy2N~xTue3XT$?LP{&RSWuPQ-xP^cr&w1}G|w8Hc(6w++i# z1+$x3r>Py|PJm)gJxuHGZ+Fu+`e80vE!C@2PsS@4n!5!~`_}`{IF;gjiNM~mlD@r{ z*QGhKbQs&IU7j+&!AZpOHH$QL%D%BCpD2?%3Csn|PG3}%>;YUXk$!`8W{Upg9wN92 z)fr4?7b#8sO6)HXjl7p++PI~;KsrlBesg$5U%QKeSA96%=plp45 z!>W@g8P;uc-mgt)L|*{B7l0X!nI$&{TiFhZZd!~XN6=tXK;=^uiL(V2x~kJdh0Bi; z|LlT3z5kXj4LBh6561+XM;?t^2ERPLC3l|&RuMW)qXDHwJn%ZaK_MW@uNZtkf$sKf zO54*-11w;3h;U=7R6Rb+<<9NlG>*NomzF$^_4nrk^^hCn0(3=FlLMH1JsL;6uL)MhVcGO4Q$0k>lC{F z)OwB%M z^_{}zz<{=Me($H^qY8!>>8AwdgoQ&|6)S=_3N<00wgNskLwgQSR?^7RN*4vX-DxJ> z2EZjRZ$k+TqHUz-NHB+IE2Ma`qOHC+LtN2$@;S0x19z#nyvNFwVI%b`I%u}G^x|C0 zb-pXp4s(Mg1wn$IJ;3gd9G5K4NL$0rH-e&tmz(}W0c5}w9~r&5<>x{g`P$k8S|i%? zu4hXdRsQKydsM8L9V6i;UJScjjhHxV{37n{3X9vC}S{;526~b?a``D zX9n|cR&a)h&1q;3!YbI^sgZOWkSP$ldN-V1kj#xXzh-Wc%l8nP_L1vjzeE|Bh7SV= z*9#w+MyUGr;9Vx+5efqviv#m75n^*)x)1U-C8p&wV7pbLn0Gg=vy~b%(+DQ(b+BS- z^Z`0IiL=rN-=^-~dd2eC46mwzlKM9dc-OcFkH9)=@6`8I?466q8m)*+?}bOb7^{ZY zlaGwtO}H{{Uf!4-KTR3Z2xFg2iJ^Z8e%;iTI96@@Ur47Ybc-uYSIdb#R>28JZ6U|% zi5g@O(B-KPMlQC-h?hv`yq`jO2BAB6h6;lig=r`;<{-Y9>DE&hPy`BYyUR8>A1>DhYv##H4-=l>}pkUd8U4BSQH% zXbF0-mxr4CyI`kFH4U0#q9Rq*k9d^MX5hR=uQz0oZ+=W%oEY9Hw}Q|bY) zEZcRfTk(Da_K5?2>GK6+5g+U$gT6RSRGV7mY>?tm%-r@lgbiN1am(}jd}bYFc=jPR zJMJ{O!IpDRa{@m#QG0ad;c#jB4ca_LYJVzfWRjMpIuaD_)$dVGBmoB-kyEiFPnwK1 z0L=>Jch$j%cQ_^Om zOO|8hamq1P`o}@}t6CoC69{;usu&ITZZ)a4H3TGj8v^EOHS6YNzrlM;u_bR>MB_Bw zt)@5hk&bSa=571#Dl@p+3Sz4MZH6}@@16Vq4kYUrSHW%H389ZcsW$dY;ulqO%hfl( zmhd#2jj;!Yb7&{%wd2VpZ@GL*rd{?3b#0xEN{vyy&8n`zy2s&%_{3A9)il?mP%wqn zbJ(*M4vOkKf1>D8TU1SB%mKO!t$n2AQ?lsV;ZIk>`+W7a7kjsPn3;3k4Oi#pg=1Y< zT#+5Q`4@sX#9}Vj{ZCke*l9V@13Dz2_Sw561A}swA}&1Y?%I8#%*0hHpGX74u|-a& z>9Oaxbs;n!+C-X&*a5N=Oo7=g4r}C3_aI_fn{d}PDc|3sB7KJN3cf(bOBhJ;{E{c- zz2aD^h=pu};}=3(uc*)FqF*;w;D5Hf&;zS%>C%=M#r04rm7>-SzrMmErR|q9Wzm-&WH7_Udae!KbzW|?l;)GBPN7R zTXcEOyc>k3$dj3$KOgk+Kp@FoI|-I^&w1{-`xgQB&f05zy}VzU`$YZ}tTJ?3=!7G6 zN(86bg@iYy@=kaQ@&$Eaym=;Ju=wc=ze2avqn8-rkX8g(Rf9IQ#H0o*Ynj^n9r3p} z-m(fi+%eOmmF}=p)sLH|cbil@qawSKz>aVj$5CDSWV6W1+M_$S1$Rr9^t) z%Z`~@jsrNYiQZ%OSxNXxJx;1crvQUGu)29QdqRoaxO@zD_ zWP_VEjy%`nNNh{=BO)&$a7tOP49j9>voi=iO?b)ulB3Wygcn*GrEVg0z%4n zW~yEZ>h1wRj>2`rJOQ>k<0tU&JKmgaX92{C|Zsfke8TW15JUxtluKdF7T$Vt4n@J|A;wN7S=S_0_21T+%q^ z@l`{~s}keJ72|2lDiy@=FwN(~*}dV(SeA;^B8#!)#zTqnXG-Ow0F-4;wm1Si_(0fA zDR}ViQ#e;tWx+}M6e1GVi9S=$co{%1cKL{PB(oJP5;ChB?Lk-d#xW~p=5_MI>x_(& zVX*3o1km;c$33YKR368S3o(yggCwA#H%UAMq4%74bz^oNc40=R)eC z@$5=KO_|RNkKr-UTrUOM%JA9KlZx)v%b8)QFA=;<05F|#xaZ?X2?2qLi*fmdg#hXh z)+{qv!~t+EAbc! zeS-DT7!6a+{GHKLr!c+Y=J8g466@?sa|N+RRElwz zG%kottSxkFSn6Iv*#|*??%K;vCSDfFd-%`|d=@&aRPSiuS2)RVgYMVLfTjSfU+JQ( zcn;^|;sI}NmbkgmhwQ}62hgjLlObahq-&&ASypU;71{*4?fe~oKjxS7I1+aBEvB=g zaIVNO9n)|g%hG(y8IVE&0SN0+WrVY*XFG12i6W?>;96A74eE}l=H(xOH)3G=B}V|3 z3|J6CXKy-qrYi@58`UQ!ee%QR|A_5EkcqEgjWGM$(EjT>u+ zb_zpUVP{ujxnWdIfg;1VGT7QWm12fkRA_mx8-T3bP4Sv54my@FMkFgKkX7LgqS`kG5Z^qrH|St}uS`r`JDAN{TmLZo z{IT!rGxV@w0{@1`O62g3z0X~YvWGW1W79z+H@F%P)YyVkzIp;ElW`w_LXn2Od-ij) z%sjN&3?C3&uW}+Ad`9v1iCr@#vDa`LS_6c<>hly0e{(OPTA;ucxZYe}-AW0u*SBoA z$&y=-A8=@t_Q>pZ7vLKtnQ3R$W%{K5Z0g6mcY2+MhVtQ;l-04Rj- zsv<-#V$so{1p{0+`Vzgg%}&-9TL)#Vk=`+5=63yNzR=z~0im8dnd9$uvZVYO9Vnyp zvgla@p>O&Un|Ea|7Q>)NgfYUQve*Zwf%LIDM9OgzdQn^JnamL^;eqsUsc?UevS3SO zPC#AglCg0%KpVI>#Tpg>z@j+vV>w>;NBME%qItlT#=0Mr+fCd^%dSirV{2;}0Ncem zuwh!y{ev`4enSu-LEDNMX2HH+YIlXiR@}sd1DjE*4HoN@0?|z9@Rf~Q>(?jQl z=RVCfGY?5iOJ77X;#9mGE`F2G`}IaR@>!nsFm_2W#cgPfdYfeT4jguc z6}|~fbNb!LwC=+v8wj)4UQj3*!clt;xRmnkcy{URr2m*C^n_A$BE%-TAJNf3?xs5a zJu6R#J5m06^9Fz&Vr!lDO*;h=0jg((f?GjhNzUEahgO_SXNIotDjy(0ErwMB<;=j^ zYxs%aksA=O28to|Kq3Jfi_7MSvVKDHw6U5}M*HrMuxoBG95Y$k4CC z822G!)-}4TBRoyD1e(2z?!Y7zMUYw9%?JA-y83c{^cG5lsD1NXY#p=n*B0Se*`BBl z^34z~E@gq#5HkXy=F0QKtr9Bl=<7xTD~EnEC3x^Cln@p>c>}}xHg<+-Q&u9vxpPRx z9laa0MLEtWj1eHNBRu!V^;zlSIn*WaZa#%K`HIEr%&fa~df4Ec(VWGYrf z>cu`SXFzIVj+mE`aq9Vt7nw5SHlf!pA$S3jc{0VzyR{!{@dI2~2Td7^-GSUO?zLB-~TJGlUq zHni?VLl#|VUD*v#4_3-X{}bJK6bFK)81Sg=LtfB*>3(dh=8;G|ei-NEVt~X1`&Nxa zB}=T5cztU$xwxKw)zBs@1Y$k}Md8@%*8M%-9SvypQ)IVvnne#t%r8iR6)e+vp(l0) zL4|{2+zS0By6W(}Vn3hSAJnHfk^Kg+13-O+DFeUjWpi6R8;)asYFAV%79CpiQhKmy za>jiq=LbHGA=qYYVNf_!yOa9|rfa$_gg!DSrl4@e*(KBCeNmxXI7$T6t9q?@GCb)M zAymq4p~y1sVO)2+;Kk;gBnr{n17qs_5_L4x3(7H(DO^i z;$PvR9Brk|Dx>)SyEZ6P+h~+ZV8#{AK{uy>U0jc{L+xb^*NyjD#>)_T)cv1KsTvip z@%QugZMAigcn)u5hRWv5RlOL+7MLHf0-!FU&HUs1*r<=-X1`T7#e}mAif>??h+2z= zBUb*tAQZuJZIlr^S7@K96u|J{q}Z|Paq$+{uN_nO%}&79+N$N1ntCIwOi_(;_E60) zw1)=)LrWDg0SZ|~4u~OcMFqc|{o_(~5aM5oOAMrCeoOEJz326qtq=cs9SN$LblNP2 z58ur{AfnD#hGl1GADq0Yk8Ie}N6XL8KLLQ~zn>Df;Lwqf=a(6b3F4>}Y(-CNyAcwT ztYjE3V>KxUi{>~rJ&+iIU=yznp!z`Z2ySap>~4>OnQmVnAtl+hi&|E5+IJ8tD&`mC z;1EXqqs6?|-v0jYt_45Ju}`DSl&b2$^E~>14(+J^;*YBAZQ_SFWy9Bn>ZRq51dEkC zYtS5{aBRtDO78d+o&?G>eEP1;FAqlrrICU`Qk$PkRqwxcS7tH*_Og)@!9R2NFY@@% zq?OMS-^wqbVtXKf5+)K5jNw&$$P%7V%2j!!OLrst4>Knr+5^XSQ1atmco_TV@~<0y z|5lFxtUA9BV%JWbpHAgs@{9W1?`S5VjL z$>{y^_L>n_G6`&4NIWwB$=~?<4AQd4X;OlG{(DD4 z!g1RS1`f=o)AjN3LALR?w=5fd-5|H1Jv3n~LNu1X!8<9y%q?^jWL^Yy-Z?eO>h5hfe3;dIsx907>rki+y68Pg*cmwHN2p zR~_ih!?+;+72*7jCITHWi`s*Ng`RB)R%KFg9?0(8b6YlS;G*^YC?A3fzzVPK}*xs8(UR7+3uQ4s;;bDan-@PxWP*WZ&h*!wI>|!KOne!_ih63tW%pHb$)%T zDo9aiLIb1u4TrMW`g`bUjh7v;R;;X>iyEr>lNuIZZ#{_(80b&2tca(t68}J&u0+V~ zD+DIsw;3`Acx4AsE8fEZ#^NU`ecNAnkkI}>x9o6WcdACv{&B~1$=l)-Tb}r~oS(PL zlCO}`yCb1jDWQKy!VgZr!EunV#9~+r{LWhg07TwjuS?d0h%_t}0)z!4Z1f!Nu)(1w zObSl}hkgb4HzQymN|~S)y;jHTP06bXP>AwrRoBBU{#iujiIV(_-Gl13`U+CHtqUIY z(r(k@vNF=3%^|B5fLx3wxhS>p*{F$~F6VtewCkUce%RC0Kl%hzx}U`CF}fcaVrFWp z!(o@d>lj%M+jc7@20ix0uGF4ISIt}mA+yz?H`m#I4wov#{+#&UfRL7grTEpRRHmxr zr(C`l&cFvNbaTG*;=;I%Z@3>GzzjbiIGP8<4X>HC5(8EXFButK(|`dyxov{-y4^|1 z5|x$ayjZ@+wedxdq4MofsC?TDj(lerg{*2aA!CtG4!HH#krAQE>L||_7#cBI$&%Ne zKR*76Jp6(_zY`axvvb{CJ7tY%Uk)s_Mo(WqRGf$yv(8$|8E}01rQUR+UVr>uAajAq zeZC|J;O78eid7}?Qdh{3UVC!EgDavR#H36DI?B4l(lrwD2KGQmw$-;T3u(Xcc~b=e zG4-j9*Xh40vYqVPmVmGIv*aTVf}%i+B#FYxvx7;I?{8y7WSOoS{Yi+n^j9Z7XYKA^ zC@XW`AuwIu5yX_g5KkX=BGa~B>dr#VJ?QO^*K2G1tJ^!vI;QNtSzCo>p(V%7mEBPc zgW5*VV3`0TNh`yX9zonvGbEDG6BJ#80kEOB12Ns>f&8Rj7d9rCZD2VMU1@A7^s)BT z!+Q=Vhh|eqqp6!`Dg})U?mTa)=sLQU(w2sRJ)d^wnq4LGTa7KDne|saTLwNW^_O8NARJpMpfDB4Xm9QV}o4*5al8zaEdGxK(Kv?sA?hCb$BAo6y z%o8f=PK>;N7KW;@+7!7i0lewqBO*5j6OpabN=)zy&E(J{FRc0J?(D#6oRVWKrrPl{ z;^N(x9CAtZ=gIK;0DdUW7{-u9MNa_TUOY>FeYAT9bAG!KT*+fF-T8J{sp2DdT$KSZ z$^_@1kXlc91+L1^E?{DkzoeA2m zmP%DMFVJ{oOwfx9$EZt^+tf)E!_L6-+IS?;5mS~jNvmNue`QQ)oF6|cw8rw&msy=O zh^-p{PQ@=9CY23UWnvQvpyT8h z2Fp&wvfaRscRWfraYL{_3K@fU!c-;G6)P@C%TRqcKlgUkN)d%);VR}EN8)y;&a0S9 z=|}9Jlksx?bj2b!F$qO4zcv*Ui&N+OC~SW8&>^^qpWoo}wBfi_C_D~BJ12zRyltPD zPNa7O?7-#q()MVLcS0bu}S*?G6HP*tszq)0t<` z$+H%M$kvfzfhC4`!^@4Td|oOX|X6r;C%*FEo);_MbS0TQS-O;ZARn z-CxYa%9?#uPEGS=){H0Kx(Ry2+XD9bk4-ED$pm#-IFNb02j-RPG30up(!*mP>zf~~ z=v1e%R$31kU0s;wP4Xuj&Fr%Ra`-j;L2*>23)Z5?X>wn(Qtzs|SAjDBrp85!lqZtRs!%nak84nq`w5+ZlPx4457t*wPpne9*d=SV?X$oo0O7_&FlP2DZiN7 zDCaOJE+&COg(-sQ>4=X!JUsoEh0yegy4o2vu{*qcF}f>`>)Rq5T?7l{^F=X`-@#&} z7ef1O`+Mz}0jU@WdCOK9f{K|<-9E`UJl8!fXqBQ{ly*!uWy5R-1U;evycoQ9U z#R3rk!jjBAOf;G%9weZANCo+dp|a){5=uvB+p(Ud=ie+>x#8+;uO+fDSgZskH$u2i zP+Bb9o9>B{vU7|q+29-d+f4j@>{JXtO!aK2*Qzi#Y4-)tvB5$`p?=mO*|mS&G9R(4 zxwZclPrveQ5QfcC;;HrHt;Mo3Mu>P$s0hRpUV&=+zXp!m_frl^Zf!cG{|>FM-eXi0 zL1eV6Gmn?N1_)~3GJTuMotmr<<>znNw_vz2NOD;z;ASf2*e$K{_O3D%AKt`c4y{8Y zo~Dyaq4#HdKHGJE1v%GtIa^7J)CH>no=n?o@T!M{m8)8f^SNmq6!;mXL|KPz(z&P~ zawk$YEmsdC%tFuj?pOa4wC_*9jO1lhSQ>?V^^&qMsV;3e+&1XoaRa5Jir0t4h}Z{~ z0)(PxNH7Y6cd!TLP6;G*@9`9HTkD@I+BVJT%s)AV{#;vMB$@8Me$JB=seK(o zu>kX9RO8mG`URN;N1q*mz?ZP#2at7Z=JsCNZNo3lWmhK#ff#1v$!i|9pldyyc3IT6XsFU9UG?f#!{VTqM>c%vSHB?K>GL+#scbv#(PlK zzFi zByl7q*UEn~7>v)U%sW~2WTsSvHnfS`M>xnY4aLXzC)I9GI$>)^$VGDWIdWnk`O%07 zJI5o|H?0Ibd+|2bxIX<1L3AE$6Zd_-3;cslg%LzBa)_YqBD}Fpex0BTa)+3z7fE}+1$FZc{$ma&^Nyv(`-k1{Kvd>jozM)?MKA&hFA1-X311+(Vl?9 z^7iLvqgvowtHb{V52Gk6=Uh&zU#08NV$ovGwWSO7Y|74n!VX$b*&`Qt!N`TpoRJHT zD0M+W^+)&TEj6j$E{@yw9n*^3uX0@jd(Xp-s~Tg>(ika9vZ$~;W8Q7+N_dne2jDP; zi-}5jX2MX-Cueh;D}R26mPic!4lUt=?{*W?Sdi$k$hB+MPP>UJJSZze$FXWnZV$`MC!sTKO6%dwWATE8+=p{JE$Y(t2Z zLWC??2RLRp1~8j^Q5qs`-LZKIVVEYHGYR zpeGKOHt1h?ebun(pTM!dm>AmnTD*{o8tvil*S}YxZ;SuSyv#dhsHCyHDDq)8 z->`tW`K60x29mq|QCV^obG6j>(P7%NMgqzlQyVh2Rx8y8Nr;LffT)ZQWqP8P5@yQi za?IO2yI9A{3ZpchwI97=f^|r$zlK@tDYzSV#QJMBBKb&ho$A*UJaUPX1B+SS#~Icz79@Phjw+UpSW2Wvg8^wRp%(`eQV7x9a=veGtaPN@k*LWx z@Qs6GpJf)VurP_43+MwQacFygY;_f}S3<>n;F6`EnS_Eyy8GF6POWDse+WzA1s&p+ zuVC3rMm^Jc1WSsD8mL2ZVJGv3Sb?*>Q~7z10px$pcUXI)iG}oGp21C)vI+i&L=SIm zY7K=0Q29t+H@AI;aA#!Myz|N{eoK3^TaNWS#OKkQ$!@W8Dk?E1ep;7$PSoL?oDJes zJAxAH_MZQ|! zHby8Nnm-&uW9%rZtBFcFA-T*7h=w;UA%JE~H+>`u8xZWAD9=rae;iboT{>9GeO1op zo??G%V~)0-%YyfP?9-=*F=$HF{&tXOo)jASni*BqT4YgqPTS7Dbss$Xe_>@u)(0(F z7_TeMFBB;S+dPR3Ka;|;95vtI*UVcGwMuMaEI@MwxV3D16OM18_~rde({YUBUWNZ0 p_Q_n3(i5K}Q)9WrAU@RF&J+#ZR9IfYrJTe1eD=bbqEpvy{|^{8crgF~ diff --git a/voidcrew/modules/ship_upgrades/previews/ship_nano_phalanx_b.png b/voidcrew/modules/ship_upgrades/previews/ship_nano_phalanx_b.png index 4ba6c0406769ef630ac4ce08e51686e350786b7d..fa9805686eba7d41793fa4ad5ea9751535dad909 100644 GIT binary patch delta 193961 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 delta 192423 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 tlA2csBBog1+ZPtHe9 zZV5@3jwi`b%JtT|aDE_1EXWzVPy#A>Hm*MP>Fmd>pY=tR>ZdFW+3w;?88Ac$Sd zVaW^UH`8yF#E4DmNS5c~Cy0WE2%~;NY2Vl!{>?OTO)>EuPe@)p69>Uy$tJ!f7P`ZK z;_myL^#YxzWb8o=aNIHy&gjgHrLcd@5yq#0g4M3HYk>!k%R?$Lz((wfA3*2DIR^@A zx~A@oTOrAW+{zzw1R5}7NM{vUnx;aNq#)l1XqdY@SfybJvy{e{l;O_h29zmZgU9u0 zgek&)EGaE`s-G!GaoyK3L6k3OKQ2T!>-++hSlujILu=dX;$8&3_HnsU|85@Eg?hY? z$oieHwlRvbj6*c4s<1jg4G?%?v7GBGVnS(qt&f%2L0+&0V{oNX5rw)QR`-Ycjp!E~ ziD-hr0dMF*p8Ko)+^NW`{@Up%n1!*xL;WE0V$Qd$AH7JvbL;Qklk;ZNwz2 zxN>6KQDL=^XUhjSec|}8e(GPCZVL>moZWJv)0`e(X4Qrp7JzKdi!0PRVqEz9TrW^$ z7L;e_;UIY@F$S|l&ZJe&wt6$5c0SZ;h-Al5ltFO#F(H{!{);|b0E}cq-+#;O4^|~D z^w$H4O8u)9b3{7AeDnFiZ)#6@Suc};<+%Caths9HX+}&GMC(I4PC7jztWeaxDDldH z{@jpJoG=W4*Ybq{b#KB<3Qk4jg_pJ|4r~Cm=&oGRXd%$tTj3T<*=9Q1IV#!NZ@jv> z9)ewsQPnNkwXE*Nk?5DT|4Q@iiJ`|PKEHfr;4xcZS8|C(X`JHZ@Z%Xb9)hFIt&fcy zldvOu4jXC=>Q7?R2K3$A*|+ubT?)8tXW^1+LbDe@*Kf#d)2z9}m*El=pK;R%LTgwzPcMUlYe1Ry7D=~`gkJ7sd(f#z7y_!WV*6a>dcrnpC) zf0!OXKU|))J7PHiBRO+WA1uDx=bHGUjQewz4<|)TbEC=8Vru4qW_Iy25E?9N=fVnumJ`j%kGqRXhi^g*IteSy^pwR{CZr z;B9agY~gI`6w*v&a3WT>Wt8s6pAlblkre{SRO>uGQ1t~k#WNr#Tlin8%|UrjF}6nL zowhcARS~J2+TRtY>vZ6&tK;)s zW65lCe8*I?XeZSBB(fZNF68dz+hI-KlMuoBYv;Hydxni2TB#j_j+Z#`C(xe)KV3## z4*9})n5`F1={&jU3>!37~5976Y_lT;E$*v~kK25hL$eSNj5 zX&(p+$Q-@c!Qyx(yryU26dFnglNmZWK~ihG?*1%|#6@UX@>{L~bu}KUT~OaAl~pZ) z))J`z7_ei1=z~ZfJ?slmZrGKH7U_V>@l%;PvwaB9BKck)>utm^2%t#67F_sVJ+G!| zEC0^)y}bP}A!CggRk63?gQ(oWsGKlDm{4q-m;w<8Z*SAt0opI2#IWrE3O0OMv0K*^ z@m*usdcu=ZlY|x9O1LMs_i`_e3n`Uxz=r&2sUKDUZ{%C0&-@sFuEM)yW^eyAUoEg* zl-;h&pTalZ?xu+vJ^&?4aUq|+6YP_s)S18CBZR#XLDfH(PJqg>8WDeiH1_ly96mn2 zqIxygj^i|-(ER13P>e`X1GYls}^ow+6rnSQhSz?uhb`s-rz7WrSn_W~IiY)(%Ds zg%wqUOEozv?NBXKqbB$3`k0RA<=ZCj4mYm&b%xhmYT{QZEcwF&-PWVpKjXoMAolER z!I6I{xj-1dz43Hp#Q_vTSrCtMeW~oH_|b5r*!B5A{`=#bW3+Daf6_ANrxZ}f^>>>3y5@wq;$ss zGxOelpXc|i_fHmU!CG_9oOAZx*Y&x!Xs03hQ9p%D*oo4b7HMoV+f_lKhKMVor~`KFq*Klv3*WTq-_(_Z-ZWll{WYI|E6m z%$FnC)zgZ`+{SaC_@DJt)n4{szy?Qj(Du-N9&G*cL05>CmPM(7#fCImFEN_Oa%7hapFxzP8@HF zU4ZntnI0cA*R+shxY>`%m2cct{@QG&EgRLyTE4uS5Qe4Z{KiI#w(G`?zULwyw+0gW zWW!=I@+hBjyFSLr2>I#z$mRyvP^+hZ9wjREdXwFRY$W`m)xGpf_rSpo!#+E#batFA z`ti=GL@V-1|7^rmMhie;k5Bmq>2#p!E59r;kg!feJ21$COJ$C+=qahSd?s8-Ur2)l zX@4YdZ?KE=YE_SkuzetR6f)P24}rej4EQGWWbS z?0+6{pofhW8KisyNPDuNWE;o-37QK^fm4d148wQN2Gs$N`wB?!8(~#}yPzANPP;)x zi7z@~n1Y>k0v#-BIT#%7ubn)%_AkVoFz(z>)%hUS9QdGf5~ z9c=S8lCheOU4WA%m^i0+lCAslXNH&s7fu2viZ(C=cFt0MQ6-&UU=^I!G4f=dyo+KI z&DzWY_)hYJQzWhOGG<@St|^p|VW8_^tURN}Ra_S>%B=`SULi_n&7}VH-(0w}<;YHC zsCRPjTuY=@<;nFyNCTj)+I7FRBLX^t*pAK?e0XB>2tdk%2P0x|GGk=)NkKG;-npz339gUnC8(iO$1@w1C-rl|it^)+# z-aZ@W>c9GbpSsI37JH?p>=+=@U)~w&odLIbR-K*YH=VN2w7}vZ5z*nj^i35bS2B3? z&4cEqrr2+sj3MazUQ%QF$vOO(Z{bM+kH}!@$Np>uh>p}eq#_;ie_WEnbtn(JRDK)3 z$M4Uyo4%@`B>`%YCsd+}ZV5Rbm4BTk{SK0 zV={KD=o<+VqK&-|>Ze4c?;3W*dM%W+(3E~jVdu$u<1iPqBWq31FNSZxUGvMh_VI_) z+5g(Z`@*ok>c9fC zE(eKj2hn`H$hO2!@5*}}Ehs}8-o%oIJ?mw>rKg;C!D3oxCzq#=RcdKxHW(!p&$q;F zv-C{qvgB26aU&5(e!P(XPX}>!%_9~6YE_UpbrGfrAT;_9sJ;Pr9WeB5Va`9hNKM|i z)AGkqs?Qo(A$zJlXIOssDt891<{_g^v zLa#JcFbN+IM{^mUin7Vb7abkW`@UI}rKpDDUlM-Y5WsFMNq5quYzXYXqx$92Nfi|H z?rfy9`dMq}oWnbSKq+D40AkudX}jqw>JhwCu8ZW^J~=v!ZM$Ss?-(;Cu5mxu(TrU` z*gsUm8y5S^UCN&@$cmQege^Y&i#HoFnD>5I+q_mVRr?n4dNh&T5*e^-syaC6x!P+Z zKFEJBX}@HH)9dKRyza$HFIN0S>upi5BIJKJ&2l1eee}X>MTiJ4`*zKCH;iv<7MMIy zuc1jV+X-D`H{;sCw-vSB(dB+(=p#Bi9@QqP*E4o6zR?_`-`5K^)9f9f?=kD`v|0|v zZw4cB!l@4~AQhLK*^CLv+9%(Yve=k@oY_E@5>8zEn@)YKgAudM=BdMR=!Cjo;8f~x z?GgZS)3rv_?TBjT--i*3A4weC77$Pi#$Rbvd{wJ}r>Fd~kaIJKyn7cgL5G{)W24GK zHAeZxL6O#IN-Fm1DuH6T{Zq?8!VN;odYO(dUAQ38c=-IX{42?Da!aO3OK~=}e)jDv z^=J8kWQKx(^8s{=LBa49&Ap4Clm$`d`Uil9sDiZS`#OzpuSI>qG-b#FNt`hX*#jwS zpnTU}Lodns`|f*=dTE*98l1Rciq`jcKGfV3q^`5qK-;Q(f*hlnsoZc z>W{n}Eqt-IhLr^SD*bYA>vQwH>(SFlt4q~EQUCKRz9mDAQ16!^YH z=Iv8ut7tCS5cNUuo7q^ruB=quK>#oe7yP=8CfW+P=AOc}`*JehJI&N~xu=)dgRgs| zE0fZ32g1$1ey_(RR~Vm8(#URa(+6_HL2|_fUW9^&`cop9?{Da*>)XtVmyMAAI*#+( z*Z(nOw=z)z=U{UibmmA7X=&~5<2=X=yMF==>~IH;ZOR%?bd2n=*5Q&5K)3Fq!T9}#&! z#}C%|5}YNpa-rA)$0A4n0(L6%kX8;M7Hm&=uZp++j(Y3Yb_?tI*!2 zW%J$MeJLWHSelD-P{IdTF9{TK9F)8!JKRO_bVq}@#-FhvD@(YZp2vI`y~ zFh?4MM!GIdzMM8GIp#UK1&B8P#tSH+G|jCHT{A3eS16_OJM|B*X$UO$Z3dp}$EL^0 zNVVciw?EWYBa>>lt4?+sXx7he|A;QF6QOa$F#M{ce(s#y@1@3e-V=5x>(*Wb)$kkCTM~ z@~K=n1%I26QQ6FdO(oEHelyTyqUG=h#qidHWP(#+xy0X#mVEE=-l4-0pwquOYkwqv2wF^;_B}MH`dwo#MA5#7{9;Pm8Eqo8;L_714Xd$BYMM+ zSuB-H<0siiyj+opCsAu^|75XvMo8Uuq)!t=I5Ta}%xm+gr27+XnoG~;DR{}La1N)Z zq~}4Q_9=VV(QhMhB6?fy7J1Lcfd_OUfSU7AL_U6%AHgNswFq}i zJjxJN$x=dzC^K1X8xDJ7|CbeNrOxr8$j)#PK&H#`rJqO{ct65N zmJTp^_s@PR4ci%+S2q}J85o<(7HwiD5NR#$j_Z97CN(y~szrX&bw9zUaK49h$}p_3 z$~oN#S`$Tzv?6mdnDDz0a}rj)GJBh!?a|VZ=dQLly(^*DH$Go%SMi<`c4@S@yuw_} zj(D-A_mOk%sGA1`XmF044o51uZgvEqT{CKDumxZAK7DwwygPT(B*SXCixnTGt^E?f z6uyr~wfgt9pK3Y9mTlrP(Mu3u`47<>!f`HX&gBj3Jh-wner`4Gols8jdby}_Tb8C8 z_%Y%q&E~{&Oyqs%UFC&)INuRxh!MTMBx@?5atyqLk~;wP72|(H+8a?jGL>suR3}5S z`QRsBc5KNNu%7)PtEjDLLlmNE{)o0Vs!u2QZ}4T0(NaW_IN%ZYzStSv?A`K*m?|&c zj}b%*zvmlXT)g$zII5C4?n!;!DY4yRGNoOGt3n&H7tcFv`@%5Cn||a>uv$WDdfy1F zYVjJM=Fb8V4RT;@P*;bt+!!R|KKA_ZhGC@b>}nAEr6@9Tp7n9UP-lP4!R9?E!W;w% zN*7%y$1PnSJL3>b);|^Kq6RnrhOgPY&j}>^HvVblg^@1bL_^|>f@Obc8(xWA+|185 zIP>*U+sF$8SYBMJIuEvT)I(${a?RAV@*%;;#{m!koI(%GBScloE6Y%5ND{9Y-`=H+ zTzjyLmlf@DhLp*%E9a+hZfkz2E7K_S2;|@&K$kG#x!sBnRq2Yz1;iclK*$;G7Vn;S znSvghBdK4I8q5%dKSGsC zwaxoC=5EMxIMN{d5n1bVwscxa7<=Q5=y&z6T)(a*W~$6_@y8dV^O7TE6mFcj2Z!I3 zMNWJtW)S4sx5cFmF_$bw>jX?sk*Zp7paZeZc7Afv*&%aG*06otW_bIJ6Oo~Sn1E-B zm7=*$=;_Lb@y%1kMl3(oG*N2U>0c>JeHu!0EuQQ%jay49r$BAtk&GRxk1w?Tq4+1- zrPGgKLL=+xTzg0oiBXr&ua{NktOJz~1hgTZBrvMmv+cthiWBK@w`T1@3a1-pAn(O@ z&g3S<4AYsTL7ltpCrlXmk; zXf$sTelOe6jeU35jM@Uu0ye{`_&@o7ZKRtEzHK+SpG3;LAdDn zsD~i^AT{Sa>-cM^OC5i|YZ?I0E7(0zK0{J3ue5iykVSZ~UR!Vk-L9#}Ud zEYoKXu>GRKIo7wV!&t3F6QE46bAB=J0mgbFW5gGuyaY;Q`MEma&^?1V=#P!Tq;7fo zySErG3`P~V^8Qll4db1HMTv*a@5pbaakn-{jt{@G_aUa>S7>pV6Hw?mAC1Oe?Npp0 z)5OOu<|C|%b>14-Yka2rc$uOQdY%0UE4C;2QOmdkgr21?32IqM~ z%^x|EV%w~)corMc-fho;P3rsPZ#vKNNqRc^ehR@62S-p{I!e_l?;$fk2djq8a(B3A z&SKdw#;O4!e8AJ(>gC1hDTzKZp~u;eQ~~ys9rU8$-X5g01K@A3RA+;4@6v0T2`WWH zlYq|ldsiib$rHM7UE{%TC4$@G#ge%5i>xcj>8pQ#`2*C3B&>v$!r2AkraC-XmFiZr z%ELVN;3#Ar27l5_aw1kNb4`K9wm=<==7 zQt>G+O&szS4NoQvbwtCuG=ZG{>y`UfYidcZq%b5ujm0kEf14;m0hA9^GVRlP7O~PV zEiElTx_75Gh)m_k@LKm4`y9Fq`_tpG_K85 z>_n4Ov1sv+{bir}E6Z|u8Cpg=+ySj>Y<1%Y=|4R(K5@Pad|JMis;@?VhYk#5(I8L60VOaXQ=K<0;!P;Y6ZGAb~?ko`5z z7DWt=m1gajmuxCg5O!I~gT(rKrf5GqB7h1Ca?x4qqj5dzlNVcjx8;Z zc+Gof1?;5bEWj9yqFUMe5kKP1Ac?eo(-$2FSuXyY!#3xtjN1PlRJqa4+XD_Na=p~* zd|SHRqV3MnE>kBep(DU+@J3ZW?4Ty7Lz8$SSf5w+PEV#X0Lt{vv z!Hzbed>_^!c{X^B$%2FZ-kq*U^bQWpEdk#VYgDYw4Hl1|0ws%A6-goVo{vvAD0r>R zqkM3YLC+%>)#^FOlp0VT$6jD zVsB$5)%^2{@GwJTrZ}p)R>ZJDu)vYqV^g4N`($A)I@PY^_+mks2_8wY8@| zGaYM)te24JqWWvc1|jbTag8iQZUHf*!61iqGU&km85^JGVl(|bF>g=>Plz!A2!v{K z<=oJBq@Fx^Fh-edNgZnU&H^&yl_^9~2FcVY)f|1wF(O3%2rE`B^_xuo-9ET7k3AAJ z%^S9Xrzapvt?|f1Ohi9b0>~kkUGC~Yel4_5#=onH3HpXRC5}%EcE0~jys z!a1mSwT3Ib|7$+To=Cu<(Cl`CAN(Nk_sqhu%9FZPnTjHeR3hy9X@Iq^YHd^gLoaUn z$opAFNG#q1!%=~CGoMRe$)_ZgDd{cRDHs!v4J*_0I`3{i%Hq5YlWR@&VPQE?S~k;LWQ{Z!D-%`v zeUdDlBeDLG!ZL%O(jR!HvxC*JW*6S;h^7;iRzt^OH)w)4Q3_ z*WNc3?Hi`d^gl}XR!})9beT?VOPe?^kkT9W4%HsWS zkS)6WvWBqiYc+WN8G`N$aZ?F)LbWO<{h{;v{$X@|=lk3S@0jEMCnZGdC5M$HkD0T- zXZ*dYHVSqI2tx;D3RF%ft|#AcZWhl}BsZYGmCe=SF*elo5rw;PEdE|p>SV9)kQ)7Q z@`o+&DS19J4*SPoLILk}+r-+h1}s%%b#oh)k4W)bH4j8`VZESFH(^p>(G?ZF5w7|| zc5R~Dt}Cia@@0_(*Za%+mN({ASs@_6s>(r9-xYNj=>KZ(!(ILCEyDrGU}|+6x{v?i zwg>9l>`4I`(doI3b@_6S&;AR8rwK^e$Yvg%)3#Uk`eM6l~=5Xp$N0vf~ zWB8KmmDFG25Rak6^Pkmk@a3G&qWXmNL%nZe=(2m7;tcLU97T+mX8i<{yL8kvIx{FKK$tNsij4^y z#1%@18hNki#eV9*SkD$d57mWCSuFvd`r(iG6|4|+Lu*)1b~Vr77{}qqI%9Ltj_;nB z{807620<-W^*o#OnDNzYi;(JD0i`%+pFbSl@QPH(6pDAigDM6jU$-eFu}PKgMeN{I zamDz=WoNc^TIi32;%BwM4V2W&HhzX|V;yDel7p7zmp)W-qq}TB?6GS&DQw|A9Oy0o?z>v z#a(Dwc^DHNrCfJ+Z-_z`GE?Hu@5bvZlFj%oH<-KCT${3v)RncX=hkc-p`Pbam)kgm zBJcfA0pfwHonNiKSY|*0Iplsau%RKo%dyJFhm|z1;hP%fVYNvaB0pv zJR*9R=hpC?mKbgJWn~vvKcro=3PqsdumkGu_F0vwte>3X5Ag#^)f0LPtw`3Ipd0b4YTJ0%yjcXVm_eQBaN}-Ko9Ba+YVk zPC0xDI5yS_;;i))8@auRUHm4pnCDtC4$^d1%8(gTgT2QgNE2J#N6@wTlLRq5>Lm6i$(Up1lUbSKE)j^}18- zPYdsCr$6*!FgSu!4!KlAOpfJKPwB{*JK1z>%l~+d; z$Lk}*j+{&yqX~m=+~z|Dq`cg>x={J5DxP^6Qz6c-;PajQ(QdL6B%L3v%AvIW994#3Wb|nW6?!RvYo`S$p49!mn)G?8k6*F65m82h)H_tOEn0gpXh_;6t23mAF(sSQ38r-LS#muL4j{mUrBGFk=C8(CYq?JFSh)08b>{2#i z;F}9$)X{K6A@m#kJ^4?V67vYO<3tjxP}u`!s4muD+A?^fde;W)(W^kxh}iZ4C zyrjW4f0_fv8K=iGLT6`Z{r!7Bv8$eaI^UDb1+xWm-Ee^6Cr}FVZy*shRGUpGmf>w{TL(YDTTrj%WC>4g6D?AaMO{S9 z-ANSSr*?rpte+PakB_$DOnqG)XgWn71sr-;b z3BC5U^-$be>-IUQS^sfiVAPQ(w*_IyuD3w75M`O32<;t=7si*T#Td(kLJpc;KTI6T z2@x11(9TcJTeVS{BR2RA344~?pSTxde`Wxb^)`R}xhV`BEb$-GG0UxdJhv~)2{pMVJ} zVDG}b5each?g>-I7BlSDkri91kGg%x+@Bkl-&!k$E_MeaVJDLc5Yob0lta2-t3jq6 zOu$_9cLSEU|AwGvgfwT$u1~`nQR$uZgKuK?UWs++@g?TQ@HZrvo<{lIYgKLS z#F7$@{|4*b%3n@TYh5c%Y9IYEBrMCE>00#FeB|$XWimIUb%M zgW%MZyX(Ola6aYQ`Zg@oeFt&4a9L=FSmW{(CT`^g{!ra)_a4%}&<+Mnz#=wc684wv zKhl#%a8Z!V!{N0#*Ky~=&x88tanldcye2A<`r%w5>cMVP@|r536yrZRrS3g>XLaig zwLHsbHucAKJggNWbt+D5%(66n-piQ9WMz=}5_rY7lo{NO?`NLM6|_7T(6J~Jh#t?Q z=s)U=Kj~S<#0S`T!}Mu z+L(W)O|1G1nto^x&UZe)(n5bs8=mAuN#;1dWtOrW@)J8d@QbQ6v3U!u{{ICCV!Z=R z7i3d!z63ey#~A%{yds&$IgJ^}+8-XKk%?;>Kt0A^##oEKgHS0lg`tdFzDLb2N?nJM zJy6-$KZ%M0m2cY^hjYBJ#*pdU^FO}C_aFu1}fv-!T@4xR|guiKsA6x z9DE{-q+?pVDlfNS`|`k8dncsg!(wzA+!5*o#K~&#?{LRP?AGmErO|ttIl{gsGEV$ycVMC3<8}yybSmvAq?qVHR+~g9!6knCs1EUV z!D+T5^)b%KtHKxG0{NNX@!pATXpRTCoDLs{#Bx(iaJd2SQ+xb9Wol&H4W1s+k1Hsm zLFvHV7r8`tz=rEW{a$P%tbQ^|O))dzx7>8(Cc33w`jVBaqUw#dBUB)rfyjywH#B4E zMInP$8}14tcFqn7X!vDI{_iGSM&3U#QkvBiFjhOqW~$@pyRt++6!MT(8u%v% z@7g$)^W(W^ixSn^u^VT9jSa^A`?JK^))o3G`lUzpvMeu|L&CVvl8P`RsiiDYv3}I( z8HNPA%;m|Qw?#Y)CR`|*%k>TXdE%%&lTAJWEG@)_7j`)(Wj%N3<`0pELsAGP5;~&n_x0$%4UH8DM z=k2Wg;cy`%0r5Wo$*}e@c!tJ`bMH&uZhK z;L|QCuj5};VQ7f*Rnvb59nvP;-YR3rZiD_bDoaaIg6_Yb%g}Yi9;Al>de1q47d8b= zX^L}lK?X)zQa@kg9sr@}09?Ci7h<^8sQ+;u&Q^Eww>wN|!C7Nu{I7eBOW1Ju&YXF~ zf~(#4;2jH+LHkoho4k<^X%ZkW5n;cy*H`=OQ$2myN_^9-zOAsN|2hhRMm8Vn*)qN% zQcrwaxkAAWzW;5QS9s7cnK^kjViKde>?B3&CQ6}L)t3M6#XA@bs0Qkp@v_J8%nj}y zH7pUxap43+q5gRhzK6zP0YY@%OORMr$p#5^S&DVhzefkZs)Jw?usZ`#w~tG^SW4KKl4 zu((2A4h}CX`d%_hE|HXbd_{bBuaza*nLi2>xD zoGcsJ3x3A!Wd8pq07G|wjq5h2)QMQ~Suk7DuF%@pSYCRnP`6=)=BRMsDo4~#W`dxA z^Xu0-R&?pte#7kP7Gm&7(!kZ$(!m5DKflf6<2Da~icOm)xfQX^bS{7}mUX{u`HA+C z+Vl6rNE31)n{FNdQsfhHh7r7ao;iL-@jRjO=$2ZWFc5K7%gNXcLScmjcb~nDddvCQ z$@$PoV^jNIaQ1KEcnpjGAb?7|x(N8~TJ3pCy`E{1ZOqyV{2Bd|taf84gLDaFw0g1z zfO`Sv={%9l_@nO(@e`Ij8xcg@z-7Vrh=+G%0gsTE9T$sw&rT6T zE1Oiy8pXAZ;iC%mvBiF0CwLYiINzHXdA?L1yNe5J>w2VG6NPxlbew~9rU6<}Kkg@p zk#yA$kaE-V&G$EEu_wq=Y}NZ~7n!be$z45Gv$glJW#2>xRWkyU1ZDqe!~b6E=x|o> zhcp{UxO;QGUwHE~{P5wW2oX_)L7CFI&fRrB>2!K(--yRO+gQJUD;}*)0p?4l9fMPJ zlrlV|!m7ByQ`CTjllVbDH-Pg~sJ1{`eVrU_oR+bGgKiZRd#mxmcl%m7{PT~oEj%e0 zr=N_GsVM^|VrLA~wf#ze*=Nr5c1ZbY4^EeV*1VMV*E>OPnACM=)w7}qBN|rNj&?ah zB54@PvK;(&Pck#mHGw^^8PnTBba|9xD5A}RgAbsN zc-a?S+h3`8t zDw^Z^M*h&6x*eT!I0Qz4Zz!e-jL>CY`>~idoq#&N;D?x)ml=~rOi^#%R3xMw(+)@< z*#j4UiTjqH(1tb!OmkucL=5`b^y13ZVSuK41S$A^Pb?>-2mq~Tu!U>rB+6yK7z(F0 zGFwC>|C=NS_3=-hcjDGu9?kusKmLw$T!k0}6gU85Sm$ zA099My*WOS$PVLp{hyWB=6*yOLJPPUG3cW2Y%(w$hH4SR1Xp~W$Z&6mwS!(Zk_rPe zv~=0Go+IpV`;ob+gR9c!yoW2u(_o=De>amG1D^yT_7g4%N0peUMc0Fxeb#Gb4&3_) zsIjotBMr~u!pV5^RS&+1Q7dvA;^BRf6vgn3P$+9$66Pu@_E=w>|ae)Tf`4?;d1P2PWn*}%HA{NDuva!kL%Fw7`ee%1p-URnZ zO0Ib)2v-Xw`WPA#W}(I#W(L$ z4lFjN0pYYfC#3oeN>0Xqk}r*+S4668NP7ZKPNaRMvUFhJ;c)k^8LlWY%hiP2kCo?B zz`5+qPk`yS)T7?pDQ9tO8@2$JH#TfCybe6d|Gc$UPJr4_1pShM+V{PT+sJ06cP&UT zeYfA-q~Jv*{gyzA8G)zhbj(jMCgy+kM${4@+4o^OWlfLUTpJvL$avaQxdNECzc6Jy zZoi<;t<8o4Ylab&kEbrMEaTeqhv>-Qz%c<<@mj4zr zVTy?79{0SQe^PYQ*7pypxc|aS<&_0o zk=N1H=E%M_Bt6jj{6}G?M}sb2`ye^Ss}es`=6v6yBBXL3W9z9N`hs0Eaq&nyMtY9P z`@+ZX6Vr!JB7SHo;uonnN3XH*0WC5mWvG8u&PMWWLfHg)SK1-GL)C!n$oMoO1?RhS zqWU{66rvN8h|OnYs@!Cud$?bsULpIzi5^_=6}tPzHIy_@hP8eB!v1Vs{U>F}xiBe2 zCT<}5sD` zMk$z^?z0N!9G6vBkHeP#&+R`B$&E;>10ifR+>=*sKSD)TuLP9PCP$uw?H}psu88*= ziSDv_bRc|M8SxL)#CY zX(jY?IWO%4-d>Ji5n#nhE;`FavByF>Js)ey9AP-m*W|AseZ=xK3H(e<)_On%!)E%% zH-;e$qSd&~QF$Q0XHw>cH;8K!IYLzO3e~dE)!qj}Tp$N(GnX&ac#o;35_5+tjhqJR zK+|FgB7rzu*jkBu$*nHaQdH+DX_pPEg1q89eH<=Oyb~_N0usIQ84N za5o|~&NvrAW$3>_h*D|ypcry%5dhP0zX(1ly?8Egxj!sT?5*65-eQWbU*;TIpVmpyt=|0y>zhCfoWlxz5Xyto z&mX>N{73Q{sQhOiL+$W=B`Pp??wQ56eJ}*k;2>w+05j1;m(0aBfb3ltWiDrn*#O9Q zUZvX=jzpm6B*IPDdY<(I1fhxJ=X|a{ctTJs`EYZ862CFw6enp!*3FQu)y-YXXZ7ag zLjP~qzpQck7Ly_B^f*7ED1t4g?~5o3)qayH6SeYwb@rC`oIp=1bvPK__r5y6FhDZ< z>oBNjpuv>yNZ8w-0+SPLPkz}yvc+D=@&`pnR-LE`gXp@F1kGzI&X6X0ydKNq^B^JR z9`_XY9-+v{Zk%SBiGd%e)=r+Whb|G7QNVOWphJjZfG~$y8 zr}@CbN4M{FK^(}($tPbMP-AUt!iG|e|}{Ct?|NoTMWjE~H7foaa0K4MiPRg2_g*ybzJ z3d9v5(!Zigdfc0r26*dNZ+>tdG(X4nXPJ%kFRW$M?DMLN-*956-=%wnK-R%m&^}`LtwgTvtSA)e$1FOF8 z^Gqa{a)@eYfBd_hzB#{OXFY{4XkoJ=%~v5X?11?TYyy7D1*Gx9!m!!XO(l+1pD3~A zPP(zc8wS8=1ru#+{Oe=NF|_OaE{mf)lO*8h6)hg-Wb(_YFtVFuC$2gTm97G6?PD@6 zjWq~$F~vvsEO@A}hKTA2C;iEj+@~FOiZF@L+}zrw1InEUtoxMLhF%1O#P8Xj-lPBF zHbuUJ(e95}piSqJtNCOKAQUT+U=kkT)X1j5AK59bvG2D(={Lns{0TpVEI%)tyay9j zEk=u)Q`?;erZ3e<_!E1$<1uGMQDAo7EFeC>u*5CS`4`YI2N74)dBq&Za5#W7m9c|^ z)mtY2s3Ve;NH_cg%Xe(_3`2*HP%A|}%SX@f?f1)7D$tovaISstNW_f(@Fba75#L;G z)Z2wy)Gd;p67<+Kc1vu9N|gjL5W)bGOEk(hQrp+KhsCKiMhrN&5yH!}AB*RLY3|ML zyngLz!%zLr+SZoMf8T)^h4EXs)S}%RqP=qHj6`bj5m1Cmedtw#NG(Uc@_MP0kEFP} z)6UWTT#r9F@xA2D4e~D~z2tXH^T4Au=e7O&<46dUB;Yw)yy~V>bTt;^ZVd4HTlB8* z=2pG?MFJuu7xDD+>dFe}q?+Qb5L%x5NP~AlDdTt8W3XOS%vmxDxGU7Y0AGcfO+ROz!z>@u3EADqP6$fmgV{A41yJH!AYWWjowtzkuyE z(Asf{keJDZJ}d}4J-{^~jxMPI5ZOx;YcjsH?5R_ZXJf`4y}t@cWEwMWnHu7NA}c9%>`ODHFw|8! z95!WsPGqFJuyRzca4%hC!KA=UilEi|6>8g6cB={MQCsp+TM^3fTp~9nf`}Q6tak~t z-(R$CIV-Y|hA%(EiQv{|B_ZlLVN_tF#TW`|TEJr6w)E(7t_~@*qI9mpQzRUc3KGhJ zP_gY&@X4a#XozB>dng=2%?(UOsIrfa6{aY z06~sx>+V1!QJkGetFt@O(spj?RjV!_)?$d!{w85!Mr>$i)ri2aC2a&{$9X)X8kk+Ecnj04F7PR;=gM1;0Vw@ z0q!n1p^4Cg{+qBOeTk%QWPEgVvU5)c$|5Vcu`cUK*Nvjb_Tjchr{u@D+1qx%c&DgQ1@;WZfW~Z@C99K1W zgi9YCRDaL2YizTPUMM06CsRWRh#0LQYW;nJ`=!s(mYJE1rQKA7U_yw1QYH|6(88m| zA`*=w9lt~c19cpyhZ%y#%4oZ-?5;Nra(vINri_h-^ims>4r6bpZni&&T z1!n@Df1+hPU6N>XzgS>lAas`fJqXTv{iHi?lYRAw(hEJmt9#v-o^-zi3b!&XdJ`#l zN0gj62xAqCYro1Q-od%k+?ujZ?`k(k4QgQ-#3H*|y-uW5iUHeu>A{bXh^f2~R##e# z&3f>s`h>(;`u=Q_)jTpFwOD+&6fDyS|} zLb8$k?bJTo%XxS23|U~T^!fLD=R}2&}ar z-9C+%sIPi?=)^%mdIfW(+2_x@+>J2Ee>eZa|6+RoV*H!o;1RuprKPCcz04GPG&P>6 z-!|D7tmn0ulysJ3JDLBCj&|S4J zNvbY;#e&{%U67i$ykaNKk~mH`Ji>VpQj50DZ+=wKpbc(Wuto!QIsjse>fEmVHkex5 z{P4$vm0Vn;BPi%mryPNK#Zex7w*Bg@`oh&K8L9f2RXX95>c#15j1b%8pmKe!W z@1t8wyY$tr9H~w3+>6$)s`U`Ss3-c)xWJ$cT$u*uH*}{Pcv&Svaq;#vC)s1$bXfZ1 z>w%t?w$*`?j(Zm+v;u5u=z7v&2tp#r(2h)7OkVcxG?lArR9$91&=Y7|vJXqx5{pJbECG7^ezZsdA>tIeJL= zN2~kb41nM`=@Jfa0PO`>NIb`k5P`?|+jAL?hCD43DL#AWy`eqWhZZ%E@S1Vs=WDS^ zt!2)ES5vpTp6EQ<;K%0QVoS~mynVYV1vUcy-wi>L2i>SQI|>q-VVcF=GkQ~+kXGrU z^gAoqF2E61fXURX3R5w)n*95@5G5XMTz2f{GCvo1+x?FD8oR-7{*@R?e;pg)pXG7z zzK4PjKMSUc79kTKiZl4P!FM_vbp>@VCl8VnWf$y3)QTDf74D-(aAVrREdx{j)&d6b?SHtjppTGkoM|g#o=fYIDP>fYEwOSGS zO~9J7;D@y*D1{TFlZnlP6GakBrkK^h+jmKUEdM-Pev75W)?#9F8@)Cc z?K94EmX<$kwNLD^P05p9$b1iq9yhOh09YqoR|%qosLnk7-aUE4&P!e#7-DvKNF&ch zq925qx=KiUh^bt{&XHv`a|`Z-WGnNK)*0%qik)9KSHH#C&C6mE5eeOJLT%$9yaD(u zB9%PqBo@$qztTx11FbU)Uba>|@zCcsStCi~yEb(H-8ELO|Fil;-e@m?f2)tqFF2Kz zMY{|j;r^Es$`c^x0+cX-qzFz_9}Uq&{0P{Emodf9WvGdl&g@=83zE$p|LM1)JQLy< zV_wsThUoTBauM|D<^&IamAis&P!m>?k0|zk3%6S21WQZH$mkdv;wB9C_Na`@6#i;1 z#QefJM2I4e&ZKNT1<-*u_GdD`KDT0wg+7sd$0uLo9(jTu6qWXFC6-eWUyh~4>}y4T zgF`v_?A}DFJ*t88oVEbMq;Jj8x=)KsC0NSxakfQmmW^VbFt;g_qs`rBVD#A0b>D_! zrkKU_38wRdeF}_;b8?&xP2D;YgX9{U|LyP27HJm)X}}_&v|kt zseJizvISgz0T=h?Lco66z>H)&wWB3!+K4s&S#;%_**|}3&jSgRWj$#^&eDX&ye^m4 zu(d{`lIRkPe%^bGrVuPU5bfbmQqFmZ{s^#%7Qf{%%ISoEi_ShR*601zgm$AkB)43|nPLn~rG`q^>Yw#s!%xQDGLUgC{bZ zH@BF4LEdO-1%hhegV_heNXwX{#CV=|@oDICZ5d4^t0j;!@`9j+pC+_RbIXq#H|`DB zXS@h^JZuzPfKToX1&0>f30@MX$zbUop`s!T zR%b|9D)4!zh$`smVq$L@M5fZm4ts0K{Cz9czUEd1uENpnG$GY0Bbq5I%JVwHF8}VV z>;nm~7otMrIT~9*>ymm{-UM5cAuc!dbvn)edWw?;excHM-)-Y^tAg+%rcnD5n?02#~cQ){bOtudRWdO3JE`a6WUUGbg~ zRVlRIX&3NdRglecca4x!wIZ$p^H$WWP5*9MFPy1gKiI*7LtBw+ zYDXCf$!gq4<9lOy-`p|_nJm|VlxV;mhOl=~Gx2<&ZfLuf{UBOwuJBT07@~9rcy>-N zWgeydwkO`(#sXC2MOOdgF}_1Q!PSl-;&v(}`GsWp^ejQ*;mn41BCjHk0;&BA?tIIq zgj99euF%*O=7-&XIaoV#&(7}FNdnZ7S_Tz;)Z)5U4c3hyLWL%6^)K%L*6*2dFF5{# zr=On(w;wqQcF|nmJCikagBzd*8KlpV6h_xLJzAfCUxS2JPW8AKIb^Enzn1{tH1o! zJ1#mB94y5I5lreG-tsYJ>D))Rxy-1nI495kwm(uV1~aDgu*LEc^S`em{ZnNSRpq_Q z=DwF=Uai`V7|jQx2A&<}Y#Y1D9u!+-InhkgdJ2e6^{O1e@6e0M&ADW3cyn4n6CDVlp@Gs?5s5a{W5RCcs&b8_ zZT55!zCf1bTD=(>lm&U>z8$R26{xJQpQ^CH#$C7vN+WuN+3kfUmzPnK6w)%omru+9 zhpf*ki9=G;^@z6b(?3VW*ZyrgpfG|fksPs1ydY}7h{S@Bd)H`7+49e*i-a(Labw2C z70ML$5C77BDL7K$FrN(#CRz>9AGHnU2tjlIt}Uh&wjtLIx{pAKUt&N@RWNLrB$$h! zC5!Jyo0tTR{^1Ffd{6q0p?Yz|h%0#$phzT^xPZLxlsZO+zu-S0=E>9CdSU3pLhSlR z-xz=BQ5mVhzBH&n^zCSa5CrGBc|rajoJcC&T<5!`Pg(daAAR5=HN4olzi?`Aen#Bb zL1r#!|7nZry4CV2a}dkLY*yshJ%0?d-oyTJWyk$GA_oN?t8VqM(h}K`RNx3t9gH~; zB*xmV$(Sl12Of4y$OGD-QdZ-e)kgM1SY>nN+CUp5LcO z#aItMOZfx6+PPqOjRHgAic7$jFH=4P#!P`mtvKyvm8*W~QxkMMB&TlLfl9cx-=yjz zd@Bd8_cZcaENQli%+T42>8FYDlDdVf7);jJ-Yqm#5i!3>O}Xx%$B&kksBQDQ8xC^p zK>yWb3BW2uc_B|{PFYWs7{Glm&A@7))fulkIPT9GL#Eal00{FK*_z(ER-8td&nWfii)AwRNxgA5$30zARO~DW+!f_pEXMs=*K$1c1!aj=Q!?G5 z%&GUaqvG2{(w zLZrSU=2fvcp#OXHJW^lqyHou5BZO8Y!$4Y7VL#v7Wn5-79pOqQ*}z~gThM<-5_Digu3lp|I$S3h>G}lP$B>0E=~4TSyP0c- zlc$NU-pd9?hIPrCx9+$vQE^`)(+PtbQ^&Z-BhY^Q1w4r46`~7zZ`+r(WmCQ28{ODl zBqlPaJ@?-qa|3f4I)i)`OT_p0%E!T9AX6q043sbP`dDI2J|9Nq8LuLU;y;arbO~PE z$uomRT)6?NGF?8|q@iozt&Qo#hHogbs#Fr+7 ztOcAbK*9E-vD|-DBRK?q@Pc?P5xs|}^J$Wi4YF&D+-z}ypBU9$JmwMu|6az2fQ1~2 z_`XZ3`^m?N98{prSmTZft5B#p*eLN;3h^I_26R-+%V?dvXN1X~orSnkRF)o_oY5*n zPZj~p(-}2(DNy z7T+Rn9~C&5{?c%FZ6yD+90$?k9mtXJEE{1X!d6pF*X4w|G&VMhY-c-iCvSQAgjwuY zG3-z)FP%}{_J_0=)5W@YBC6Q&q`lOKy{y>L8%kj-UQ+9 z6-p*rhOO`z_UZY5&*^4FoIJVV8foxgdSCyFYDzgeB=~qC64c_~e~_oTI0_K$_a$E6 zZ$?O`5F0h_SD}=Gof+pTg47`wx6FeFNF(PXMNQk!FZ)8om7m++g1o6l&T}^s1$2XL zUEtkE2V|CqAj_z4cTAzY^2q>@Tw#2fBAsL%TtSFrr*GD!X%q2sI6h)=@0d&t&OpkNB!#`5{`9D2H6sf8+lP; zp#*#Tf2f^&U}Kgx@*c2NrwId#2cf4ibn%M)UJe+~V(4Gs#MVj-7;4|wBZ4Y~p`?3v zqv?R~l?V8wh_mq5?ZR!Df2<&KHAd9Y7`~xceB1O)uod>Ok94ZfQbltHaT;hA(0*eg zwV5MXA$Raa$m-njeArw~!Qndi0WyZc_{pcMlQ3$!AyV4O8a_n$PJx#urT$F_|3~ld zEO-1C+{;$Ls8M9oC8~=wg4R?qljj0i$v!b5H*YZD^gTUK@cD)ZsbOTGF}Z<A)8# zQtQU)8B-h&@q_@6U-d*lHs>ZQr!j4BFPGw5R0Yn{CL#87>|1VQ&SM71|jncZhugVlV4 zN&Tl3h`nbDnSNETI&RS_OB2`+ zhccL3AdDlOJ`}eMhbP@fM}M}`HTSpPk@&}auOEAFO4VQF42SUDr% z&Cvk5LZTtu%PTYy$i1QIXP&f^A6y536-3pJ*U}>o_Q7w&=d$mbO6J#-8x5x8?GVG# zSow881M4jQ;rMl+k2O0QSjb`T+a4|gce4!&LbG}WTl2#3 z{7zg1YJE`e2!4sb0cqqEGBeGm=6YHuzv)nzBN;6|&wIGnji;#DnsKl4io4`rX{I}6QP9FRV;RYo)dAW;aCC~+{<#wl< zLh1ZN4|}D#1@5^bh_|sXwNKuV=Hep|V7nVuB_lMI5J<-%5PM0ejqSab zth%#Ehku*?ft;7f@HXP`0!UagVil{S)P|B7&b;gL*#C`fMGKv_1mTOmM_T&zq-MYo z({uLG1{K9mz6hBL$%pjiSAnm$CsimHGa~9oKXlgMkJUpG|JQrXhF=t&IN8%>T>sNW zYSz*#)usIsmJ~y8NbGRPPQiHJKZkTC1(|L1)P7vG?|0OQhTTp8?4Yp$MhtO&EO9*Z zdRfft$AK1yrY!mt61ee;=W~GEpt~M-`@gr^-$}aMd&-)B#Ux`xAIDBR^n1&?$%nY} z@d1YiswNt$a_}1dhXe?=CtpIJRP+j~r9LvuPM0PyNkly7`E1dwPcS+P<9k=74KD?50UE`2M>jFHUbNB3w2H)Ct5HMO@}zHsqIB+J_GolAd>#YN20}27$cAM$ zTD|L)&eA4)4^bMUwlsw0RUUSxskzIj;rjF+32ceRcbV_FQpTG9#wwgoMFFDFPa=7V zKa%u)k;es(Y|!XL>_s&U6&M9lK!rQB#?4X&3 zkezROR(a0PA@ZJMl{cA^s(ROSD>}b#A@pfG*2Q; z*P4y1w&@`!n|&`TJZ?+QIoo6#C{N8I*NW<_D&)@Ayf+&)iS7*pVt#-jB^wi*3VMLg z0N#qXF^Sj$ZqFDq>!Pq(R86z*^j#jfjBa%0-7j`S;M^+(o3`cT`q!%culC~Cd6!t> zlh)BY4_m<|zXu*C-Q7yP*EJ{t!<1yqd97~(9zK0tHy+m03FPKKEk|7sg zJ|X7g=jW~{(BlBfrCGuaS}#Oh{=POlUh1G~e#QMDkjLs#y)wO$&W+4B>=d=WwcrT^@Qmr?_tWfrA@3e6+=;f3w5T3JMBF=U&0rzK~^s zAl=kOuh5~cp>Qjy(xWL7^!-`tv4Wx={xSrHIto>DP^<7S02f>C6}Bn5><*32b$jz8 za-d`m<55>D882?;T-S7(g2H)+=6-c^SfP^1*{tnyqoo+l=`8D}q4J@ftgP|@#P;Q# z0Ngxjc_s1ETMQnb&8GtjZIwImPpZX8!`Euiu0g~#(DBw~iI-GNik2J^`PO_L8t*fo zk>lEaztIPd}XX!{ai7T2tmMY^)?qw)N^a=x1Hp3rqPwoM|k{#7)B8 zd@9YxO8j*B=03T@{^)g}^5?6$S79|bp?_kJ|QRy>$VMK~G;6D$R z0is#~0^xV=*)&%q9|wBLcHcgqht5pm@Ur3=)8+Iwput@k`K__URk*^V z-mrC#*J?P7@6vSJ!PfU3;FRE_AY7uVY=-#C9baY#xE_$JUw^0o&~vW`&TZ1z~hw}%NnF#q(9dC8$& zBDBikXsXjBgGZH-ap4Bge(zkjfP02ydL>dZ9Eo3OkCp#)fBb1(Ik3_8(3N#+bf!uV zYRHUoA*n{0rkQ??eDEK{h^ADbkjzA@#CoM#hLT;}Z_a?h#V0pU+Y-wIb5osn?eSA)Q5%4fNlRDHfeD{U}9n~H~zWz zb=!mD(w%jhw47unv_PPhwCuezy8g%?3~XT9E1^WtO-RLZ{saO`KD z9SJOE1PA(ai418LI!Dr-8QP?6d>A_F_M3R|Nr%O?0V(ku?U}JS=yj_`egoqwSXkQg z`9egAFHIUv7`Ho#zrMB?l-EN zDW%Dz5+T=-aikuu-Tcf2luaiq-w&@i2V&;`$WAEGjV!*KFoJlp^eLXaIp0+s3DW(h z(K4_&!gW6WSPt*;i+^Z3aW0?0@b~cf^>;%0XuG;?R_%aM;)KP&<&ljL0t7)fkB@3d z_J*E^!1JKCCFt_GVH60Tzt^yZ%CI@gG3a;xZ%PTzK+H2a6#riV&(6=+b;47TeynB+ zFOWr`YS-q9$LWK_@n%$bkeA-$wID~g> zmbfgIplQ<|UcUmA^e6KjL8#ln#bUm*hK=KAoEy)fTB_p}S{)Fzurr!@me1RNj~#(l zrg^vBHzcKZP1z&*5f~&By(=vdqwPhq(5bgNpx9TmO`v?|w)vguH#MYk#6G473v(^P z9Z|AyyRG30q!i@r$*iSJ@0Y#xv}PBv_hJ?M@5hzxUb(GshcMA|kXiz)+8c+EZ--)T zXxE~9#7v_3`;Blzx#{=xwoIN;n7`55zeb7n_}alXP;1<4X6byr&W(sGTc!hK?$!vS zypAfGUhR6#e{rihH#Q@ZJ&P7jMd{ZzTADtPTjs2K3BkxW-H)(9|T>B77r+zBrPbxjBv_OZ=>uw1H;2S7NKx6Q77`LedRfjGb_A4 zU-+2hBFH|FEI-Q>K4dBGC^TB`%vb$C!=)dA%5W)mPM*bvy?nr53&!BRy*)J@kh&+g z$|_NDWC&s^D4t>Fkh4Kh-s7vk>|+U53uQn&kMfcbpU~2)sijUlbydVcl1@WT;@2{A zU+|xwulRb#K>sZGAX5oG@R2-y-|4zMeB7= zXiFq|1<>~%_99&O;a97^h9_k_KWU5D&uMBqbG=W!@{K$2ZZyW}U^>cTt5Db&poTNj z6BK50Tf(1GwTZJPq?#>jK!od9^a!$nG_v9{&E S^7Yf5e*Cj*O)}8MP20!}fyPO855i1$+ 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�!a+k9 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 b-C;Fwd2E@`r17`Mx;H$E#T{ZD3{U?L)hdQ@ diff --git a/voidcrew/modules/ship_upgrades/previews/ship_nano_phalanx_c.png b/voidcrew/modules/ship_upgrades/previews/ship_nano_phalanx_c.png index 740c4fec8f16fe8e4c0ea1e6f4184c2d99e2ee4d..f4086c9a4c84ab46054e4e93be63d47fbc0af090 100644 GIT binary patch delta 215287 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

+0<(Bk3NHPq)7H9ozvq`?J^L+ko{U7nv8mE& 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 z

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 $5D@wQ{1W+CF#f>lKym2ZoOJ~MzQAvn7>EQX1 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�{O**Kb! z`eI}zgj!C5B=46X78##p5z9*NGS|9zR;ZD%;(&J}Y|nSOwKc`Eqr2ND^5-XO8-$<= zMFWAgk&$|IwqNIQSiq!M{CwQ+l2_W?s&vSwVDquLCf_g2eln*kJbk=Di%3iRX(=I~1>|=Uok{SjE_-VHoe`RmZG+uWtkWuP}pY7hl`7ih5Ey~6t+e6u3&%k z;CPP@a&q`w))H_a^dC^cd3~j2PVT?A%GkT7V|D$T+AJyGvODC2yU?O(RiouAqu&fOES`D+(ek~6^CVK2Cs04T*=Da)J)J7&0g*3qy6EB9j9(WWxlEQ z2^NPaQ$3|^!UMa_W5{|sO@qNo=1P!I5?^EofQPFCVOy@yZ(KHU!d z_mG6=C&rT8^MmG3YK)Y(c*uAb+G9B(@=C-JNHutI!RC@<&bbp>M)~Y6&>zjX%@nU% z4ZR<9kn`;tI%}P%NGErXesVMs;V^hGRZQ(KK3d7*$JKwY8d5WPhx53xD)?1@;VPHn ze3EO~)&*1m(wPn`~g<#cvd}2cmhB>@hGRH=rJE^2Nh9iQ1feKF{sCbtlqFp;?cp znI~E5Cr!LG4T)yC9fJpWmLHbFyH?T7Lm`1 zelyoU8SN6@m@XA3icRnJ9D4cHyV_P;ha97M9E$vb-SD`*1j`2Lf+n*eb$`7On=EU| zg_@?jsx%kKoU{qQSdGRx13d;{rZ6bk;n{n$(t-Y;6az7$t!CTyJY(h0urq~27M#|b|ofCg@Q3FOW%4D@6;S@9|C8aO!aX0#ks);H- zreyBT@`@9X+;H#VjdX@&8wuIv<55AT-$yM>^PR)e<_yR$Yb|}q>m2(*mH`}Mj4(4O zGP=g68fQz|3i{4Xmlobx&DlXI2kwhK%RMPRTzec!$#{NkIck?}#JH)%bJ+r4Gw(|1 z^4Nn^d{0CF&<9~9lwHZ(xg3L@A9N!60~zxWnnOws72bZoC3tODw=h?~#2XI}#a!!L zP>5w*ZpWVkn~_Z`ayO$k!YI&xu-5wM5l9KqJSeHnSKO|*=+C2&gj=T#4nFVi5%*c1 z{G9AnzZN-?R}WPosY3{_g_y({YS=m-pXfQMi+05D$7vaq$h=K{(Lq5Yc?;V?cZb5` z;N5_nGQs?vRo96h)MzAAr-K;aNF#) z!Kr)|_0`1Q3LTULkpb_N-*58O>+|+OKYTdH5PO_F^6Uw;a*udzaj|IL%+s`tCD-w` zp6B9jgoV+%2ZkAwlas?P_czLDBm+oD9Co3`pG-n3ekUB9rqWj-?1AfRHlO6kQh`ua zN7W6YNuCcZFdG>TVTY#=zSFkOzZK5^wU;5$kgwZzDF}Oro%>r5*tC+48;L%?-V)IH z`LmFGUi17cMew7K51E%(BkftJ=x&^|J~pm^Fn!)Y!>xK1_xsp~Db8QPZtT%sm|D5> zz1O?C_6IWq1Rm2HZAQo=qHj$!dv{ziXJu1t*&OA2>&Z;@7H7TlPCt@@yD*uWaxKVpxmNEq1 n$cp|&Y))V~0!9X4c|+)2E;7zj)v^ms@OLeBUA6r4xBmDq-rn!r delta 215359 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 i>TarIQ(Yc@sTD;KH7AYPexn`)d{h+F Date: Fri, 16 Oct 2026 13:48:32 -0700 Subject: [PATCH 019/105] Keep an exhausted vent's boulders collectable --- voidcrew/modules/mining/ore_vents.dm | 24 ++++- .../unit_tests/voidcrew_ore_balance.dm | 88 +++++++++++++++++++ 2 files changed, 109 insertions(+), 3 deletions(-) diff --git a/voidcrew/modules/mining/ore_vents.dm b/voidcrew/modules/mining/ore_vents.dm index a88e8bcf33e..f71f9d95a64 100644 --- a/voidcrew/modules/mining/ore_vents.dm +++ b/voidcrew/modules/mining/ore_vents.dm @@ -24,6 +24,17 @@ ore_reserve = new(ore_zone()) return ore_reserve +/datum/controller/subsystem/ore_generation + /// Vents that stopped producing but can still have boulders awaiting retrieval. + var/list/obj/structure/ore_vent/exhausted_vents = list() + +/datum/controller/subsystem/ore_generation/fire(resumed) + . = ..() + // The parent rebuilds stock from producing vents; exhausted vents only supply existing rocks. + for(var/obj/structure/ore_vent/vent in exhausted_vents) + for(var/obj/item/boulder/rock in vent.loc) + available_boulders |= rock + /obj/structure/ore_vent /// Binding is permanent, including if the source is subsequently deleted. var/ore_source_bound = FALSE @@ -37,6 +48,7 @@ bind_ore_reserve() /obj/structure/ore_vent/Destroy() + SSore_generation.exhausted_vents -= src ore_source_ref = null QDEL_NULL(unowned_ore_reserve) return ..() @@ -72,10 +84,16 @@ /obj/structure/ore_vent/proc/can_produce_ore() var/datum/planet_ore_reserve/reserve = bound_ore_reserve() if(boulders_remaining <= 0 || !reserve || reserve.sheets_remaining < 1) - SSore_generation.processed_vents -= src + stop_ore_production() return FALSE return !isnull(get_turf(src)) +/// Preserve discovery for vents whose boulders were available during automatic production. +/obj/structure/ore_vent/proc/stop_ore_production() + if(src in SSore_generation.processed_vents) + SSore_generation.exhausted_vents |= src + SSore_generation.processed_vents -= src + /// Truncate to whole sheets of contained material, before refinery efficiency bonuses. /// No sleeps between rechecking the shared balance, debiting it, and debiting the vent. /obj/structure/ore_vent/proc/commit_ore_payload(list/materials) @@ -97,11 +115,11 @@ reserve.sheets_remaining -= spent boulders_remaining-- if(!boulders_remaining) - SSore_generation.processed_vents -= src + stop_ore_production() if(reserve.sheets_remaining < 1) for(var/obj/structure/ore_vent/vent in SSore_generation.processed_vents.Copy()) if(vent.bound_ore_reserve() == reserve) - SSore_generation.processed_vents -= vent + vent.stop_ore_production() return TRUE /// The finite allocation pool stores counts, not just membership. diff --git a/voidcrew/modules/unit_tests/voidcrew_ore_balance.dm b/voidcrew/modules/unit_tests/voidcrew_ore_balance.dm index 47595d1b10d..d87c00d4880 100644 --- a/voidcrew/modules/unit_tests/voidcrew_ore_balance.dm +++ b/voidcrew/modules/unit_tests/voidcrew_ore_balance.dm @@ -275,6 +275,94 @@ TEST_ASSERT_EQUAL(red.ore_reserve.sheets_remaining, balance, "Failed manual extraction debited the reserve") TEST_ASSERT(!(other in SSore_generation.processed_vents), "A capped vent remained in automatic processing") +/datum/unit_test/voidcrew_ore_balance/vent_retrieval + var/list/old_processed_vents + var/list/old_exhausted_vents + var/list/old_available_boulders + +/datum/unit_test/voidcrew_ore_balance/vent_retrieval/New() + ..() + // Fire the real subsystem without producing or collecting any other site's stock. + old_processed_vents = SSore_generation.processed_vents + old_exhausted_vents = SSore_generation.exhausted_vents + old_available_boulders = SSore_generation.available_boulders + SSore_generation.processed_vents = list() + SSore_generation.exhausted_vents = list() + SSore_generation.available_boulders = list() + +/datum/unit_test/voidcrew_ore_balance/vent_retrieval/Destroy() + SSore_generation.processed_vents = old_processed_vents + SSore_generation.exhausted_vents = old_exhausted_vents + SSore_generation.available_boulders = old_available_boulders + return ..() + +/datum/unit_test/voidcrew_ore_balance/vent_retrieval/Run() + var/turf/vent_turf = run_loc_floor_bottom_left + var/turf/partner_turf = get_step(vent_turf, EAST) + var/turf/retrieval_turf = get_step(partner_turf, EAST) + var/obj/structure/overmap/planet/site = planet_at(vent_turf, get_step(vent_turf, NORTH), 1) + site.footprint.set_rect(vent_turf.x, vent_turf.y, 2, 1) + for(var/exhaust_reserve in list(FALSE, TRUE)) + // A unique vent is absent from possible_vents, but its stock must remain discoverable too. + var/obj/structure/ore_vent/vent = allocate(/obj/structure/ore_vent/starter_resources, vent_turf) + var/obj/item/boulder/old_rock = vent.produce_boulder() + TEST_ASSERT(old_rock, "The retrieval fixture failed to produce its initial boulder") + allocated += old_rock + var/obj/structure/ore_vent/partner + var/obj/item/boulder/partner_rock + if(exhaust_reserve) + partner = allocate(/obj/structure/ore_vent, partner_turf) + partner.mineral_breakdown = list(/datum/material/iron = 1) + partner.tapped = TRUE + SSore_generation.processed_vents |= partner + partner_rock = partner.produce_boulder() + TEST_ASSERT(partner_rock, "The shared-reserve fixture failed to produce its initial boulder") + allocated += partner_rock + site.ore_reserve.sheets_remaining = 1 + else + vent.boulders_remaining = 1 + + SSore_generation.fire(FALSE) + allocated |= SSore_generation.available_boulders + var/expected_stock = exhaust_reserve ? 3 : 2 + TEST_ASSERT(!(vent in SSore_generation.processed_vents), "An exhausted vent kept producing") + TEST_ASSERT(old_rock in SSore_generation.available_boulders, "Exhaustion hid a vent's existing boulder") + TEST_ASSERT_EQUAL(length(SSore_generation.available_boulders), expected_stock, "The exhaustion tick lost or duplicated a boulder") + if(exhaust_reserve) + TEST_ASSERT(!(partner in SSore_generation.processed_vents), "A shared-reserve vent kept producing") + TEST_ASSERT(partner_rock in SSore_generation.available_boulders, "Shared exhaustion hid another vent's stock") + var/remaining_sheets = site.ore_reserve.sheets_remaining + var/remaining_boulders = vent.boulders_remaining + for(var/iteration in 1 to 2) + SSore_generation.fire(FALSE) + TEST_ASSERT(old_rock in SSore_generation.available_boulders, "A later subsystem tick hid an exhausted vent's boulder") + TEST_ASSERT_EQUAL(length(SSore_generation.available_boulders), expected_stock, "A later tick lost stock or produced extra boulders") + TEST_ASSERT_EQUAL(site.ore_reserve.sheets_remaining, remaining_sheets, "Discovery debited an exhausted reserve") + TEST_ASSERT_EQUAL(vent.boulders_remaining, remaining_boulders, "Discovery debited an exhausted vent") + + var/obj/machinery/brm/retriever = allocate(/obj/machinery/brm, retrieval_turf) + retriever.set_machine_stat(NONE) + retriever.toggled_on = TRUE + retriever.boulders_processing_max = 1 + retriever.process() + var/obj/item/boulder/collected = locate() in retrieval_turf + TEST_ASSERT(collected, "A retrieval machine could not collect an exhausted vent's boulder") + TEST_ASSERT(!(collected in SSore_generation.available_boulders), "Collection left the boulder listed") + SSore_generation.fire(FALSE) + TEST_ASSERT(!(collected in SSore_generation.available_boulders), "A collected boulder was rediscovered") + TEST_ASSERT_EQUAL(length(SSore_generation.available_boulders), expected_stock - 1, "Collection hid the remaining boulders") + for(var/obj/item/boulder/rock in SSore_generation.available_boulders.Copy()) + qdel(rock) + TEST_ASSERT_EQUAL(length(SSore_generation.available_boulders), 0, "Deleted boulders remained listed") + SSore_generation.fire(FALSE) + TEST_ASSERT_EQUAL(length(SSore_generation.available_boulders), 0, "Deleted boulders were rediscovered") + qdel(collected) + qdel(retriever) + qdel(vent) + if(partner) + qdel(partner) + TEST_ASSERT_EQUAL(length(SSore_generation.exhausted_vents), 0, "Deleted vents remained in boulder discovery") + /datum/unit_test/voidcrew_ore_balance/vent_weights/Run() var/list/old_pool = SSore_generation.ore_vent_minerals var/obj/structure/ore_vent/vent = allocate(/obj/structure/ore_vent) From 5644f5ebe0429217a749cea39063a11aaa7cba3a Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:56:53 -0700 Subject: [PATCH 020/105] Single-node disks and accountable research rewards --- code/modules/research/techweb/_techweb.dm | 30 +- .../outpost_checkpoint_construction.dm | 6 + .../outpost_checkpoint_snapshot.dm | 4 + .../modules/research/edits/_experiments.dm | 34 +- voidcrew/modules/research/edits/_techweb.dm | 39 +++ .../modules/research/edits/_techweb_node.dm | 8 + voidcrew/modules/research/research_notes.dm | 17 +- voidcrew/modules/research/server.dm | 24 +- .../unit_tests/voidcrew_research_lifecycle.dm | 321 ++++++++++++++++++ 9 files changed, 447 insertions(+), 36 deletions(-) diff --git a/code/modules/research/techweb/_techweb.dm b/code/modules/research/techweb/_techweb.dm index 589cdf310e6..96406664344 100644 --- a/code/modules/research/techweb/_techweb.dm +++ b/code/modules/research/techweb/_techweb.dm @@ -307,22 +307,12 @@ available_experiments -= completed_experiment completed_experiments[completed_experiment.type] = completed_experiment - var/result_text = "[completed_experiment] has been completed" - var/refund = skipped_experiment_types[completed_experiment.type] || 0 - if(refund > 0) - add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = refund)) - result_text += ", refunding [refund] points" - // Nothing more to gain here, but we keep it in the list to prevent double dipping - skipped_experiment_types[completed_experiment.type] = -1 - var/points_rewarded - if(completed_experiment.points_reward) - add_point_list(completed_experiment.points_reward) - points_rewarded = ",[refund > 0 ? " and" : ""] rewarding [completed_experiment.get_points_reward_text()]" - result_text += points_rewarded - result_text += "!" - - log_research("[completed_experiment.name] ([completed_experiment.type]) has been completed on techweb [id]/[organization][refund ? ", refunding [refund] points" : ""][points_rewarded].") - return result_text + // VOIDCREW EDIT ADDITION START - research: paid-discount receipts and owner-scoped completion rewards. + var/list/refunded_points = refund_experiment_discounts(completed_experiment) + var/list/rewarded_points = award_experiment_completion(completed_experiment) + log_research("[completed_experiment.name] ([completed_experiment.type]) has been completed on techweb [id]/[organization], refunding [json_encode(refunded_points)] and rewarding [json_encode(rewarded_points)].") + return "[completed_experiment] has been completed!" + // VOIDCREW EDIT ADDITION END /datum/techweb/proc/printout_points() return techweb_point_display_generic(research_points) @@ -374,17 +364,15 @@ var/log_message = "[id]/[organization] researched node [node.id]" if(auto_adjust_cost) var/list/node_cost = node.get_price(src) + var/list/points_before = research_points.Copy() // VOIDCREW EDIT - research: capture the actual debit. remove_point_list(node_cost) + record_node_payment(node, points_before) // VOIDCREW EDIT - research: only paid nodes earn discount refunds. log_message += " at the cost of [json_encode(node_cost)]" //Add to our researched list researched_nodes[node.id] = TRUE - // Track any experiments we skipped relating to this - for(var/missed_experiment in node.discount_experiments) - if(completed_experiments[missed_experiment] || skipped_experiment_types[missed_experiment]) - continue - skipped_experiment_types[missed_experiment] = node.discount_experiments[missed_experiment] + // VOIDCREW EDIT - research: skipped discounts are recorded only with their payment above. // Gain the experiments from the new node for(var/id in node.unlock_ids) diff --git a/voidcrew/modules/player_outposts/outpost_checkpoint_construction.dm b/voidcrew/modules/player_outposts/outpost_checkpoint_construction.dm index 77b236cf2f4..d528935455d 100644 --- a/voidcrew/modules/player_outposts/outpost_checkpoint_construction.dm +++ b/voidcrew/modules/player_outposts/outpost_checkpoint_construction.dm @@ -38,6 +38,8 @@ var/obj/structure/overmap/dynamic/player_outpost/home var/datum/outpost_berth/ship_bay/bay var/datum/ship_checkpoint/snapshot + /// Retained after the checkpoint is consumed, and shared with its original crew. + var/list/research_reward_ledger var/datum/weakref/panel_ref /// Only used to reapply console upgrade disks while the hidden copy is prepared. var/datum/weakref/operator_ref @@ -113,6 +115,7 @@ panel_ref = terminal ? WEAKREF(terminal) : null operator_ref = WEAKREF(user) snapshot = blueprint + research_reward_ledger = blueprint.research_reward_ledger home = blueprint.outpost captain_ckey = blueprint.captain_ckey ship_name = blueprint.ship_name @@ -158,6 +161,7 @@ home = null bay = null snapshot = null + research_reward_ledger = null port = null vessel = null // A load still writing into the shipyard lets it go itself when it returns (load_source()). @@ -396,6 +400,8 @@ if(!record.setup_from_template(template)) qdel(record) return null + if(!isnull(research_reward_ledger)) + record.ship_team.research_reward_ledger = research_reward_ledger return record /// Names the record and its hull. A rebuild keeps the saved ship's name. diff --git a/voidcrew/modules/player_outposts/outpost_checkpoint_snapshot.dm b/voidcrew/modules/player_outposts/outpost_checkpoint_snapshot.dm index aad06503529..07b364b7b24 100644 --- a/voidcrew/modules/player_outposts/outpost_checkpoint_snapshot.dm +++ b/voidcrew/modules/player_outposts/outpost_checkpoint_snapshot.dm @@ -83,6 +83,8 @@ GLOBAL_LIST_INIT(outpost_checkpoint_refused_terrain, typecacheof(list( /datum/ship_checkpoint var/obj/structure/overmap/dynamic/player_outpost/outpost var/datum/weakref/source_ship + /// Live crew entitlement, never a snapshot copy: awards after capture must survive recovery. + var/list/research_reward_ledger var/captain_ckey var/ship_name var/saved_at @@ -105,6 +107,7 @@ GLOBAL_LIST_INIT(outpost_checkpoint_refused_terrain, typecacheof(list( original.checkpoint_ref = null outpost = null source_ship = null + research_reward_ledger = null tgm = null rooms = null machines = null @@ -248,6 +251,7 @@ GLOBAL_LIST_INIT(outpost_checkpoint_refused_terrain, typecacheof(list( if(!valid) return "The hull design could not be read back. No payment was taken." source_ship = WEAKREF(ship) + research_reward_ledger = ship.ship_team?.research_reward_ledger captain_ckey = owner_ckey ship_name = ship.name saved_at = world.time diff --git a/voidcrew/modules/research/edits/_experiments.dm b/voidcrew/modules/research/edits/_experiments.dm index 934bda9f289..74abcc21a2b 100644 --- a/voidcrew/modules/research/edits/_experiments.dm +++ b/voidcrew/modules/research/edits/_experiments.dm @@ -2,6 +2,23 @@ /// code/__DEFINES/research.dm: one experiment funds exactly one tier-5 node. #define RESEARCH_POINTS_PER_EXPERIMENT 200 +/// Both scanner callbacks and ordnance publications complete through this path. +/datum/techweb/complete_experiment(datum/experiment/completed_experiment) + if(QDELETED(completed_experiment) || completed_experiments[completed_experiment.type] || !(completed_experiment in available_experiments)) + return null + return ..() + +/// Claim before granting either reward. Completion state and paid-node refunds remain web-local. +/datum/techweb/proc/award_experiment_completion(datum/experiment/experiment) + var/list/ledger = experiment_reward_ledger() + if(isnull(ledger) || ledger[experiment.type]) + return list() + ledger[experiment.type] = TRUE + var/list/reward = experiment.points_reward?.Copy() || list() + reward[TECHWEB_POINT_TYPE_GENERIC] += RESEARCH_POINTS_PER_EXPERIMENT + add_point_list(reward) + return reward + /datum/experiment/finish_experiment(datum/component/experiment_handler/experiment_handler) if(QDELETED(experiment_handler) || !experiment_handler.validate_research_site()) return FALSE @@ -11,9 +28,6 @@ return FALSE var/metric_points_before = metric_web_points(web) // round metrics, voidcrew/modules/metrics/research_metrics.dm . = ..() - web.add_point_list(list( - TECHWEB_POINT_TYPE_GENERIC = RESEARCH_POINTS_PER_EXPERIMENT), - ) record_experiment_completed(web, type, metric_web_points(web) - metric_points_before, experiment_handler.parent) return TRUE @@ -49,12 +63,8 @@ /** * Ordnance experiments never pass through finish_experiment() - they are finished off from - * /datum/techweb/add_scientific_paper(), which flips the experiment's completed flag and calls - * complete_experiment() on us directly, so publishing a paper paid none of the flat experiment bonus above. - * - * Pay it here when (and only when) the publication is what actually completed the experiment. Papers that - * complete nothing pay nothing: publishing a further tier of an already-completed experiment finds it in - * completed_experiments, so add_experiment() refuses to re-add it and complete_experiment() is never reached. + * /datum/techweb/add_scientific_paper(), which calls complete_experiment() directly. + * Keep publication metrics here; both routes award points through the same completion hook. */ /datum/techweb/add_scientific_paper(datum/scientific_paper/paper_to_add) var/experiment_path = paper_to_add?.experiment_path @@ -66,7 +76,6 @@ return if(isnull(completed_experiments[experiment_path])) // paper published, but it didn't complete the experiment return - add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = RESEARCH_POINTS_PER_EXPERIMENT)) record_experiment_completed(src, experiment_path, metric_web_points(src) - metric_points_before) #undef RESEARCH_POINTS_PER_EXPERIMENT @@ -152,8 +161,7 @@ if(linked_web) examine_text += span_notice("It is linked to the R&D server network of [linked_web.organization].") return - examine_text += span_warning("It has no R&D server link, so it cannot run experiments or bank any points.") - examine_text += span_notice("Copy a techweb from an R&D server with a [EXAMINE_HINT("multitool")], then use the multitool on this.") + examine_text += span_warning("It has no R&D server link.") /** * Handlers with no server link have no network to announce on. Without this they'd all match each @@ -198,7 +206,7 @@ if(isnull(linked_web) && !(config_flags & EXPERIMENT_CONFIG_SILENT_FAIL)) playsound(user, 'sound/machines/buzz/buzz-sigh.ogg', 25) var/atom/scanner = parent - to_chat(user, span_warning("[scanner] has no R&D server link. Copy a techweb from an R&D server with a multitool, then use the multitool on [scanner].")) + to_chat(user, span_warning("[scanner] has no R&D server link.")) return return ..() diff --git a/voidcrew/modules/research/edits/_techweb.dm b/voidcrew/modules/research/edits/_techweb.dm index ab95ee1e529..2875169cc94 100644 --- a/voidcrew/modules/research/edits/_techweb.dm +++ b/voidcrew/modules/research/edits/_techweb.dm @@ -3,6 +3,9 @@ var/list/connected_machines = list() /// Research data collected from a survey console. Used to restrict tech behind surveys var/datum/survey_research/survey_data + /// Node id -> remaining actual payment by currency and the discounts still owed to that purchase. + /// These receipts belong only to this web; research transfers never copy them. + var/list/experiment_payment_receipts = list() /datum/techweb/Destroy() survey_data = null @@ -43,6 +46,42 @@ /datum/techweb/can_unlock_node(datum/techweb_node/node) return can_afford(node.get_price(src)) && have_experiments_for_node(node) && have_surveys_for_node(node) +/// Called immediately after a successful purchase's debit, before the node is marked researched. +/datum/techweb/proc/record_node_payment(datum/techweb_node/node, list/points_before) + if(node.starting_node || researched_nodes[node.id]) + return + var/list/pending_discounts = list() + for(var/experiment_type in node.discount_experiments) + if(!completed_experiments[experiment_type] && node.discount_experiments[experiment_type] > 0) + pending_discounts[experiment_type] = node.discount_experiments[experiment_type] + if(!length(pending_discounts)) + return + var/list/paid_points = list() + for(var/point_type in points_before) + var/paid = points_before[point_type] - research_points[point_type] + if(paid > 0) + paid_points[point_type] = paid + if(length(paid_points)) + experiment_payment_receipts[node.id] = list("remaining" = paid_points, "discounts" = pending_discounts) + +/// Each missing experiment may refund its discount once per paid node, capped in each currency. +/datum/techweb/proc/refund_experiment_discounts(datum/experiment/experiment) + var/list/refund = list() + for(var/node_id in experiment_payment_receipts) + var/list/receipt = experiment_payment_receipts[node_id] + var/list/discounts = receipt["discounts"] + var/discount = discounts[experiment.type] + if(!discount) + continue + discounts -= experiment.type + var/list/remaining = receipt["remaining"] + for(var/point_type in remaining) + var/amount = min(discount, remaining[point_type]) + remaining[point_type] -= amount + refund[point_type] += amount + add_point_list(refund) + return refund + /** * The survey requirement has to be enforced here as well as in can_unlock_node. That proc only * drives the console UI's button states, whereas research_node is what every path that actually diff --git a/voidcrew/modules/research/edits/_techweb_node.dm b/voidcrew/modules/research/edits/_techweb_node.dm index a4aa68ad6f5..97628bfa042 100644 --- a/voidcrew/modules/research/edits/_techweb_node.dm +++ b/voidcrew/modules/research/edits/_techweb_node.dm @@ -8,3 +8,11 @@ // stars = 0, // ) var/list/required_surveyed_objects + +/// Prices are per-web copies: discounts must never make a debit negative or alter global nodes. +/datum/techweb_node/get_price(datum/techweb/host) + var/list/prices = ..() + prices = prices.Copy() + for(var/point_type in prices) + prices[point_type] = max(0, prices[point_type]) + return prices diff --git a/voidcrew/modules/research/research_notes.dm b/voidcrew/modules/research/research_notes.dm index 1a5813c7015..ab5f4859b89 100644 --- a/voidcrew/modules/research/research_notes.dm +++ b/voidcrew/modules/research/research_notes.dm @@ -1,5 +1,20 @@ /obj/item/research_notes - desc = "Valuable scientific data. Use it in an RD console to generate research points." + desc = "Valuable scientific data." + +/obj/item/research_notes/attackby(obj/item/attacking_item, mob/living/user, list/modifiers, list/attack_modifiers) + if(istype(attacking_item, /obj/item/research_notes)) + merge(attacking_item) + return + return ..() + +/// Combining papers conserves their value, regardless of their origin or merge order. +/obj/item/research_notes/merge(obj/item/research_notes/new_paper) + if(QDELETED(new_paper) || new_paper == src) + return FALSE + value += new_paper.value + change_vol() + qdel(new_paper) + return TRUE // Research notes for ruins. Priced against the node ladder in code/__DEFINES/research.dm, // where a node runs 40 (tier 1) to 200 (tier 5): a tiny note is worth about two cheap nodes diff --git a/voidcrew/modules/research/server.dm b/voidcrew/modules/research/server.dm index 3b23530ba12..d75e366b199 100644 --- a/voidcrew/modules/research/server.dm +++ b/voidcrew/modules/research/server.dm @@ -17,12 +17,34 @@ */ GLOBAL_LIST_EMPTY(ship_research_servers) +/datum/team/voidcrew + /// Shared entitlement across every source disk and replacement server owned by this crew. + var/list/research_reward_ledger = list() + +/obj/structure/overmap/dynamic/player_outpost + /// Site research retains its entitlement across server replacements and ownership changes. + var/list/research_reward_ledger = list() + /datum/techweb /// Physical disk webs must not become unscoped fallback webs when uninstalled. var/requires_physical_server = FALSE +/// Relays expose the physical source web, so only its installed server determines who earns rewards. +/datum/techweb/proc/experiment_reward_ledger() + for(var/obj/machinery/rnd/server/ship/server in techweb_servers) + if(QDELETED(server) || server.stored_research != src || !server.source_code_hdd || server.source_code_hdd.loc != server || server.source_code_hdd.stored_research != src) + continue + var/obj/structure/overmap/site = get_research_service_site(server) + if(istype(site, /obj/structure/overmap/ship)) + var/obj/structure/overmap/ship/ship = site + return ship.ship_team?.research_reward_ledger + if(istype(site, /obj/structure/overmap/dynamic/player_outpost)) + var/obj/structure/overmap/dynamic/player_outpost/home = site + return home.research_reward_ledger + return null + /obj/machinery/rnd/server/ship - desc = "A computer system that hosts a physical R&D source disk and shares its research with linked machinery on the same ship or outpost. Use a multitool to connect local research equipment." + desc = "A computer system with a removable research drive." circuit = /obj/item/circuitboard/machine/rdserver/ship ///Installed source code files that hosts our research. var/obj/item/computer_disk/ship_disk/source_code_hdd diff --git a/voidcrew/modules/unit_tests/voidcrew_research_lifecycle.dm b/voidcrew/modules/unit_tests/voidcrew_research_lifecycle.dm index 48467bfef6a..8e3a7ab0e06 100644 --- a/voidcrew/modules/unit_tests/voidcrew_research_lifecycle.dm +++ b/voidcrew/modules/unit_tests/voidcrew_research_lifecycle.dm @@ -1,5 +1,9 @@ /// Revoking an experiment link must cancel pending physical callbacks and rewards. +/datum/unit_test/voidcrew_relay_experiment_lifecycle + parent_type = /datum/unit_test/voidcrew_experiment_reward_fixture + /datum/unit_test/voidcrew_relay_experiment_lifecycle/Run() + make_reward_ship(run_loc_floor_bottom_left) var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human/consistent) var/obj/machinery/rnd/server/ship/server = allocate(/obj/machinery/rnd/server/ship) var/obj/item/computer_disk/ship_disk/disk = allocate(/obj/item/computer_disk/ship_disk) @@ -202,3 +206,320 @@ TEST_ASSERT_EQUAL(length(printer.current_unlocked_designs), 0, "Disk removal retained component designs") remote_disk.forceMove(run_loc_floor_bottom_left) TEST_ASSERT_NULL(fabricator.stored_research, "Removing the current disk retained the exofab's link") + +/// One-tile ships exercise real service-site ownership without loading a fleet of maps. +/datum/unit_test/voidcrew_experiment_reward_fixture + parent_type = /datum/unit_test/voidcrew_outpost_management + abstract_type = /datum/unit_test/voidcrew_experiment_reward_fixture + var/list/reward_ports = list() + var/list/reward_areas = list() + +/datum/unit_test/voidcrew_experiment_reward_fixture/Destroy() + for(var/obj/docking_port/mobile/voidcrew/port in reward_ports) + if(port.current_ship) + port.current_ship.shuttle = null + port.current_ship = null + port.shuttle_areas = list() + qdel(port, force = TRUE) + for(var/turf/tile as anything in reward_areas) + var/area/shuttle/voidcrew/room = get_area(tile) + tile.change_area(room, reward_areas[tile]) + room.shuttle_port = null + qdel(room) + return ..() + +/datum/unit_test/voidcrew_experiment_reward_fixture/proc/make_reward_ship(turf/tile) + var/area/shuttle/voidcrew/room = new + reward_areas[tile] = get_area(tile) + tile.change_area(get_area(tile), room) + var/obj/docking_port/mobile/voidcrew/port = new(tile) + reward_ports += port + port.width = 1 + port.height = 1 + port.dwidth = 0 + port.dheight = 0 + port.shuttle_areas = list((room) = TRUE) + room.shuttle_port = port + port.register() + var/obj/structure/overmap/ship/ship = allocate(/obj/structure/overmap/ship) + SSovermap.simulated_ships |= ship + ship.shuttle = port + port.current_ship = ship + ship.state = "idle" + ship.ship_team = new /datum/team/voidcrew + ship.ship_team.ship = ship + return ship + +/datum/unit_test/voidcrew_experiment_reward_fixture/proc/install_reward_disk(obj/machinery/rnd/server/ship/server, mob/living/user) + var/obj/item/computer_disk/ship_disk/disk = allocate(/obj/item/computer_disk/ship_disk) + server.attacked_by(disk, user) + return disk.stored_research + +/// A real physical callback, including an intrinsic reward in addition to the flat 200. +/datum/unit_test/voidcrew_experiment_reward_fixture/proc/complete_arcade(datum/techweb/web, turf/tile) + var/obj/item/experi_scanner/scanner = allocate(/obj/item/experi_scanner, tile) + var/datum/component/experiment_handler/handler = scanner.GetComponent(/datum/component/experiment_handler) + var/datum/experiment/physical/arcade_winner/experiment = allocate(/datum/experiment/physical/arcade_winner) + experiment.points_reward = list(TECHWEB_POINT_TYPE_GENERIC = 37) + web.available_experiments |= experiment + handler.link_techweb(web, TRUE) + handler.link_experiment(experiment) + var/obj/machinery/computer/arcade/arcade = allocate(/obj/machinery/computer/arcade, tile) + TEST_ASSERT(handler.action_experiment(null, arcade), "Physical reward fixture could not register its callback") + SEND_SIGNAL(arcade, COMSIG_ARCADE_PRIZEVEND) + TEST_ASSERT(experiment.completed && web.completed_experiments[experiment.type] == experiment, "Physical completion was not restored on this disk") + TEST_ASSERT(!experiment.finish_experiment(handler), "A duplicate physical callback was accepted") + +/// Publish through the ordnance route, which bypasses experiment.finish_experiment(). +/datum/unit_test/voidcrew_experiment_reward_fixture/proc/publish_reward_paper(datum/techweb/web) + var/experiment_type = /datum/experiment/ordnance/explosive/lowyieldbomb + web.add_experiment(experiment_type) + for(var/datum/experiment/experiment as anything in web.available_experiments) + if(experiment.type == experiment_type) + experiment.points_reward = list(TECHWEB_POINT_TYPE_GENERIC = 37) + var/datum/scientific_paper/paper = allocate(/datum/scientific_paper) + paper.experiment_path = experiment_type + paper.tier = 1 + paper.partner_path = /datum/scientific_partner/mining + paper.gains = list(1, 1) + TEST_ASSERT(web.add_scientific_paper(paper), "The ordnance reward fixture could not publish") + TEST_ASSERT_NOTNULL(web.completed_experiments[experiment_type], "Publication did not restore experiment completion") + var/points = web.research_points[TECHWEB_POINT_TYPE_GENERIC] + paper.tier = 2 + TEST_ASSERT(web.add_scientific_paper(paper), "A later publication tier was refused") + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC], points, "A later paper tier paid another completion reward") + +/datum/unit_test/voidcrew_experiment_reward_fixture/crew_entitlement/Run() + var/obj/structure/overmap/ship/first_ship = make_reward_ship(run_loc_floor_bottom_left) + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human/consistent) + var/obj/machinery/rnd/server/ship/server = allocate(/obj/machinery/rnd/server/ship) + var/datum/techweb/web = install_reward_disk(server, user) + TEST_ASSERT_EQUAL(web.experiment_reward_ledger(), first_ship.ship_team.research_reward_ledger, "The physical source did not resolve its crew's ledger") + complete_arcade(web, get_turf(server)) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC], 237, "Physical completion did not pay the flat and intrinsic rewards once") + publish_reward_paper(web) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC], 474, "Ordnance and physical reward routes disagree") + server.source_code_hdd.forceMove(run_loc_floor_bottom_left) + web = install_reward_disk(server, user) + complete_arcade(web, get_turf(server)) + publish_reward_paper(web) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC] || 0, 0, "A fresh source disk repaid the same crew") + // A simultaneous second server and a later replacement both use the same entitlement. + var/obj/machinery/rnd/server/ship/second = allocate(/obj/machinery/rnd/server/ship) + web = install_reward_disk(second, user) + complete_arcade(web, get_turf(second)) + publish_reward_paper(web) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC] || 0, 0, "A second server multiplied one crew's rewards") + qdel(server) + qdel(second) + server = allocate(/obj/machinery/rnd/server/ship) + web = install_reward_disk(server, user) + complete_arcade(web, get_turf(server)) + publish_reward_paper(web) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC] || 0, 0, "Replacing the physical servers reset entitlement") + var/obj/structure/overmap/ship/other_ship = make_reward_ship(run_loc_floor_top_right) + TEST_ASSERT(other_ship.ship_team.research_reward_ledger != first_ship.ship_team.research_reward_ledger, "Separate crews share one ledger") + server = allocate(/obj/machinery/rnd/server/ship, run_loc_floor_top_right) + web = install_reward_disk(server, user) + complete_arcade(web, get_turf(server)) + publish_reward_paper(web) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC], 474, "A separate crew could not earn its own experiment rewards") + +/datum/unit_test/voidcrew_experiment_reward_fixture/relay_entitlement/Run() + var/obj/structure/overmap/dynamic/player_outpost/home = allocate(/obj/structure/overmap/dynamic/player_outpost) + home.shell_template = allocate(/datum/map_template/player_outpost/test_fixture) + home.founder_ckey = "researchledgerowner" + TEST_ASSERT(home.load_level(), "The reward-ledger outpost could not load") + var/mob/living/carbon/human/owner = make_player(home.arrival_turf, home.founder_ckey) + var/obj/machinery/rnd/server/ship/server = allocate(/obj/machinery/rnd/server/ship, home.arrival_turf) + server.set_machine_stat(NONE) + var/datum/techweb/web = install_reward_disk(server, owner) + TEST_ASSERT_EQUAL(web.experiment_reward_ledger(), home.research_reward_ledger, "Outpost research did not resolve its site ledger") + for(var/turf/tile as anything in list(run_loc_floor_bottom_left, run_loc_floor_top_right)) + var/obj/structure/overmap/ship/ship = make_reward_ship(tile) + ship.docked = home + var/mob/living/carbon/human/crew = make_player(tile, "researchrelay[tile.x][tile.y]") + ship.ship_team.add_member(crew.mind) + var/obj/machinery/rnd/server/relay/relay = allocate(/obj/machinery/rnd/server/relay, tile) + relay.set_machine_stat(NONE) + var/datum/outpost_research_link/link = home.propose_research_link(owner, server, ship, server.source_code_hdd) + TEST_ASSERT_NOTNULL(link, "The reward fixture could not propose a relay") + TEST_ASSERT(link.approve(crew, relay), "The reward fixture could not approve a relay") + TEST_ASSERT_EQUAL(relay.stored_research.experiment_reward_ledger(), home.research_reward_ledger, "A relay used the consuming crew's ledger") + TEST_ASSERT_EQUAL(length(ship.ship_team.research_reward_ledger), 0, "Sharing outpost research consumed the visitor's entitlement") + complete_arcade(web, run_loc_floor_bottom_left) + publish_reward_paper(web) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC], 474, "Relay-backed research did not award exactly once to the source site") + var/obj/item/experi_scanner/other_scanner = allocate(/obj/item/experi_scanner, run_loc_floor_top_right) + var/datum/component/experiment_handler/other_handler = other_scanner.GetComponent(/datum/component/experiment_handler) + other_handler.link_techweb(web, TRUE) + var/datum/experiment/completed = web.completed_experiments[/datum/experiment/physical/arcade_winner] + TEST_ASSERT(!other_handler.can_select_experiment(completed), "A second relay could select already-completed work") + TEST_ASSERT(!completed.finish_experiment(other_handler), "A second relay accepted a stale completion") + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC], 474, "A second relay multiplied the source reward") + // Repeat on a new disk and server at the site, then expose it through both relays again. + qdel(server) + server = allocate(/obj/machinery/rnd/server/ship, home.arrival_turf) + server.set_machine_stat(NONE) + web = install_reward_disk(server, owner) + for(var/obj/docking_port/mobile/voidcrew/port in reward_ports) + var/obj/structure/overmap/ship/ship = port.current_ship + var/datum/mind/member = ship.ship_team.members[1] + var/obj/machinery/rnd/server/relay/relay = locate() in get_turf(port) + var/datum/outpost_research_link/link = home.propose_research_link(owner, server, ship, server.source_code_hdd) + TEST_ASSERT_NOTNULL(link, "The replacement source could not invite an existing relay crew") + TEST_ASSERT(link.approve(member.current, relay), "An existing relay could not reconnect to the replacement source") + TEST_ASSERT_EQUAL(relay.stored_research.experiment_reward_ledger(), home.research_reward_ledger, "Reconnecting a relay replaced the site ledger") + TEST_ASSERT_EQUAL(length(ship.ship_team.research_reward_ledger), 0, "Outpost rewards consumed a visitor crew's entitlement") + complete_arcade(web, run_loc_floor_top_right) + publish_reward_paper(web) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC] || 0, 0, "Replacing an outpost server reset its shared entitlement") + // A disk without an installed physical owner has no completion entitlement. + server.source_code_hdd.forceMove(home.arrival_turf) + TEST_ASSERT_NULL(web.experiment_reward_ledger(), "A removed source disk retained a reward owner") + +/// Synthetic nodes isolate payment accounting while using real purchase, import and completion procs. +/datum/unit_test/voidcrew_experiment_refunds + var/node_number = 0 + +/datum/unit_test/voidcrew_experiment_refunds/Destroy() + SSresearch.point_types -= "receipt_test" + return ..() + +/datum/unit_test/voidcrew_experiment_refunds/proc/refund_node(list/costs, list/discounts) + var/datum/techweb_node/node = allocate(/datum/techweb_node) + node.id = "receipt_test_[++node_number]" + node.research_costs = costs + node.discount_experiments = discounts + SSresearch.techweb_nodes[node.id] = node + return node + +/datum/unit_test/voidcrew_experiment_refunds/proc/finish(datum/techweb/web, experiment_type) + var/datum/experiment/experiment = allocate(experiment_type) + experiment.completed = TRUE + web.available_experiments |= experiment + web.complete_experiment(experiment) + return experiment + +/datum/unit_test/voidcrew_experiment_refunds/Run() + SSresearch.point_types["receipt_test"] = "Test" + var/first_type = /datum/experiment/physical/arcade_winner + var/second_type = /datum/experiment/physical/meat_wall_explosion + var/datum/techweb/web = allocate(/datum/techweb) + web.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = 1000, "receipt_test" = 1000)) + var/datum/techweb_node/node = refund_node(list(TECHWEB_POINT_TYPE_GENERIC = 100, "receipt_test" = 40), list((first_type) = 20, (second_type) = 50)) + var/costs_before = json_encode(node.research_costs) + web.boost_techweb_node(node, list(TECHWEB_POINT_TYPE_GENERIC = 70, "receipt_test" = 10)) + TEST_ASSERT(web.research_node(node, FALSE, TRUE, FALSE), "The boosted paid node could not be researched") + var/datum/techweb_node/another = refund_node(list(TECHWEB_POINT_TYPE_GENERIC = 80), list((first_type) = 15)) + TEST_ASSERT(web.research_node(another, FALSE, TRUE, FALSE), "A second paid node could not be researched") + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC], 890, "Boosts did not reduce the actual debit") + TEST_ASSERT_EQUAL(web.research_points["receipt_test"], 970, "The second point currency was not charged correctly") + var/datum/techweb/imported = allocate(/datum/techweb) + web.copy_research_to(imported) + TEST_ASSERT(imported.researched_nodes[node.id] && imported.researched_nodes[another.id], "The transfer fixture did not import its nodes") + TEST_ASSERT_EQUAL(length(imported.experiment_payment_receipts), 0, "Research transfer copied another web's payment receipts") + finish(imported, first_type) + finish(imported, second_type) + TEST_ASSERT_EQUAL(imported.research_points[TECHWEB_POINT_TYPE_GENERIC] || 0, 0, "Imported nodes created discount refunds") + var/datum/experiment/first = finish(web, first_type) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC], 925, "One experiment did not refund both paid nodes' discounts") + TEST_ASSERT_EQUAL(web.research_points["receipt_test"], 990, "The discount did not refund its own point currency") + var/datum/experiment/second = finish(web, second_type) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC], 935, "Several discounts exceeded the node's remaining actual payment") + TEST_ASSERT_EQUAL(web.research_points["receipt_test"], 1000, "Refunds exceeded actual payment in the second currency") + web.complete_experiment(first) + web.complete_experiment(second) + // Even restoring completion from scratch must not refill consumed receipts. + web.completed_experiments -= first_type + finish(web, first_type) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC], 935, "Repeated completion refunded a consumed discount") + TEST_ASSERT_EQUAL(web.research_points["receipt_test"], 1000, "Repeated completion refilled another currency's receipt") + var/list/price = node.get_price(web) + TEST_ASSERT_EQUAL(price[TECHWEB_POINT_TYPE_GENERIC], 0, "Discounts and boosts returned a negative price") + TEST_ASSERT_EQUAL(price["receipt_test"], 0, "Experiment discounts returned a negative price in another currency") + TEST_ASSERT_EQUAL(json_encode(node.research_costs), costs_before, "Pricing mutated a shared node's base costs") + price = node.get_price(null) + price[TECHWEB_POINT_TYPE_GENERIC] = -10 + TEST_ASSERT_EQUAL(json_encode(node.research_costs), costs_before, "Unhosted pricing returned the shared cost list") + var/datum/techweb/unpaid = allocate(/datum/techweb) + var/datum/techweb_node/free_node = refund_node(list(TECHWEB_POINT_TYPE_GENERIC = 100), list((first_type) = 50)) + unpaid.boost_techweb_node(free_node, list(TECHWEB_POINT_TYPE_GENERIC = 200)) + TEST_ASSERT(unpaid.research_node(free_node, FALSE, TRUE, FALSE), "The fully boosted free node could not unlock") + var/datum/techweb_node/starting = refund_node(list(TECHWEB_POINT_TYPE_GENERIC = 100), list((first_type) = 50)) + starting.starting_node = TRUE + TEST_ASSERT(unpaid.research_node(starting, TRUE, FALSE, FALSE), "The starting-node fixture could not unlock") + var/datum/techweb_node/failed = refund_node(list(TECHWEB_POINT_TYPE_GENERIC = 100), list((first_type) = 50)) + TEST_ASSERT(!unpaid.research_node(failed, FALSE, TRUE, FALSE), "An unaffordable purchase succeeded") + TEST_ASSERT_EQUAL(length(unpaid.experiment_payment_receipts), 0, "A free, starting or failed purchase created refund entitlement") + finish(unpaid, first_type) + TEST_ASSERT_EQUAL(unpaid.research_points[TECHWEB_POINT_TYPE_GENERIC] || 0, 0, "An unpaid node created a refund") + +/// Crew reward claims must not suppress legitimate web-local refunds on replacement disks. +/datum/unit_test/voidcrew_experiment_reward_fixture/refund_after_reward/Run() + var/obj/structure/overmap/ship/ship = make_reward_ship(run_loc_floor_bottom_left) + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human/consistent) + var/obj/machinery/rnd/server/ship/server = allocate(/obj/machinery/rnd/server/ship) + var/datum/techweb/web = install_reward_disk(server, user) + ship.ship_team.research_reward_ledger[/datum/experiment/physical/arcade_winner] = TRUE + web.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = 100)) + var/datum/techweb_node/node = allocate(/datum/techweb_node) + node.id = "rewarded_experiment_refund_test" + node.research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 100) + node.discount_experiments = list(/datum/experiment/physical/arcade_winner = 60) + TEST_ASSERT(web.research_node(node, FALSE, TRUE, FALSE), "An already-rewarded experiment's node could not be paid for") + complete_arcade(web, get_turf(server)) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC], 60, "An existing crew reward either suppressed a paid refund or paid the completion bonus again") + +/datum/unit_test/voidcrew_research_note_conservation/Run() + var/obj/item/research_notes/notes = allocate(/obj/item/research_notes, run_loc_floor_bottom_left, 60, "biology") + TEST_ASSERT(!notes.merge(notes), "A paper merged with itself") + TEST_ASSERT(!QDELETED(notes) && notes.value == 60, "A self-merge changed or consumed its paper") + var/obj/item/research_notes/incoming = allocate(/obj/item/research_notes, run_loc_floor_bottom_left, 50, "physics") + TEST_ASSERT(notes.merge(incoming), "Different-origin papers could not merge") + TEST_ASSERT(QDELETED(incoming), "Merging retained the incoming paper") + TEST_ASSERT_EQUAL(notes.value, 110, "A mixed-origin merge created a bonus") + TEST_ASSERT_EQUAL(notes.icon_state, "paperslip_words", "Merging did not update the paper's appearance") + incoming = allocate(/obj/item/research_notes, run_loc_floor_bottom_left, 2390, "biology") + notes.attackby(incoming, null, list(), list()) + TEST_ASSERT(QDELETED(incoming), "The item interaction retained the incoming paper") + TEST_ASSERT_EQUAL(notes.value, 2500, "The item interaction did not conserve note value") + TEST_ASSERT_EQUAL(notes.icon_state, "paper_words", "The item interaction did not update appearance") + notes.attackby(notes, null, list(), list()) + TEST_ASSERT(!QDELETED(notes) && notes.value == 2500, "The item interaction accepted a self-merge") + incoming = allocate(/obj/item/research_notes, run_loc_floor_bottom_left, 0, "chemistry") + TEST_ASSERT(notes.merge(incoming), "A zero-value incoming paper could not merge") + TEST_ASSERT(QDELETED(incoming) && notes.value == 2500, "A zero-value paper changed the total or survived merging") + +/// Exercise the real reconstruction after the original ship and crew datum have been deleted. +/datum/unit_test/voidcrew_checkpoints/research_reward_ledger + destroy_original = TRUE + +/datum/unit_test/voidcrew_checkpoints/research_reward_ledger/build_hull(datum/checkpoint_construction/job, obj/structure/overmap/dynamic/player_outpost/registry_test/home, datum/outpost_berth/ship_bay/bay, mob/living/carbon/human/captain, obj/structure/overmap/ship/original, datum/ship_checkpoint_ui/registry_test/panel, datum/ship_checkpoint/snapshot) + var/list/ledger = snapshot.research_reward_ledger + TEST_ASSERT_NOTNULL(ledger, "Deleting the original crew lost the checkpoint's ledger") + TEST_ASSERT_EQUAL(job.research_reward_ledger, ledger, "Reconstruction copied or replaced the saved ledger") + ledger[/datum/experiment/physical/arcade_winner] = TRUE + job.fast_forward(1) + TEST_ASSERT(QDELETED(snapshot), "The checkpoint was not consumed at the first piece") + TEST_ASSERT_EQUAL(job.research_reward_ledger, ledger, "Consuming the checkpoint lost the ledger") + ledger[/datum/experiment/ordnance/explosive/lowyieldbomb] = TRUE + job.fast_forward() + var/obj/structure/overmap/ship/rebuilt = bay.ship + TEST_ASSERT_NOTNULL(rebuilt, "The reward-ledger checkpoint did not finish reconstruction") + TEST_ASSERT_EQUAL(rebuilt.ship_team.research_reward_ledger, ledger, "The rebuilt crew restored an older reward entitlement") + var/obj/machinery/rnd/server/ship/server = allocate(/obj/machinery/rnd/server/ship, get_turf(rebuilt.shuttle)) + var/obj/item/computer_disk/ship_disk/disk = allocate(/obj/item/computer_disk/ship_disk) + server.attacked_by(disk, captain) + var/datum/techweb/web = disk.stored_research + TEST_ASSERT_EQUAL(web.experiment_reward_ledger(), ledger, "The reconstructed physical server did not resolve the continued ledger") + for(var/experiment_type in list(/datum/experiment/physical/arcade_winner, /datum/experiment/ordnance/explosive/lowyieldbomb)) + var/datum/experiment/experiment = allocate(experiment_type) + experiment.completed = TRUE + web.available_experiments |= experiment + web.complete_experiment(experiment) + TEST_ASSERT_EQUAL(web.research_points[TECHWEB_POINT_TYPE_GENERIC] || 0, 0, "Reconstruction repaid a reward claimed after snapshot capture") + // The inherited checkpoint checks still require the reconstructed hull to contain no added stock. + qdel(disk) + qdel(server) + return captain From dfd1c1d28e328be7955c016bf6d2a605756ed080 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:06:51 -0700 Subject: [PATCH 021/105] Merge #464 and integrate planet generation --- voidcrew/_DEFINES/overmap_zones.dm | 18 +- voidcrew/datums/mapgen/PlanetGenerator.dm | 36 ++-- voidcrew/datums/mapgen/planet_anomalies.dm | 13 +- .../objects/items/event_horizon_rifle.dm | 4 +- voidcrew/modules/trade/anomaly_charts.dm | 18 +- .../trade/shop_catalog_outfitter_vendors.dm | 2 +- voidcrew/modules/unit_tests/_unit_tests.dm | 1 + .../unit_tests/voidcrew_anomaly_trade.dm | 52 +++-- .../unit_tests/voidcrew_planet_anomalies.dm | 195 ++++++++++++++++++ 9 files changed, 276 insertions(+), 63 deletions(-) create mode 100644 voidcrew/modules/unit_tests/voidcrew_planet_anomalies.dm diff --git a/voidcrew/_DEFINES/overmap_zones.dm b/voidcrew/_DEFINES/overmap_zones.dm index 7b9e7e3458f..5c7bd5dbd6d 100644 --- a/voidcrew/_DEFINES/overmap_zones.dm +++ b/voidcrew/_DEFINES/overmap_zones.dm @@ -118,8 +118,8 @@ #define ZONE_PLANET_SPAWNER_SPACING 24 /** - * Percent chance a planet seeds an anomaly, per zone. At most one per planet: they are - * meant to be a rare find, and a planet rebuilds with a fresh roll each time it reloads. + * Natural anomalies seeded per planet, by zone. Purchased charts add their own anomaly + * separately when the buying ship arrives. * * Anomalies used to be a ship-scoped dynamic event, which made them something that * happened TO a crew in their own corridors with nowhere to stand back to. On a planet @@ -127,20 +127,18 @@ * open ground, and the crew chose to walk over there. Approaching one is a decision, and * a crew carrying a neutralizer (Anomaly Research, tier 3) gets a core out of it. * - * Green gets the occasional one, deeper bands more often. + * Deeper bands have more sites to investigate. */ -#define ZONE_PLANET_ANOMALY_CHANCE_GREEN 5 -#define ZONE_PLANET_ANOMALY_CHANCE_YELLOW 15 -#define ZONE_PLANET_ANOMALY_CHANCE_RED 25 +#define ZONE_PLANET_ANOMALY_BUDGET_GREEN 1 +#define ZONE_PLANET_ANOMALY_BUDGET_YELLOW 2 +#define ZONE_PLANET_ANOMALY_BUDGET_RED 3 -/// Minimum tiles between two planet anomalies, should a planet ever seed more than one +/// Minimum tiles between two natural planet anomalies. #define ZONE_PLANET_ANOMALY_SPACING 20 -/// Cap on random turf draws while placing a planet's anomaly. A planet whose open ground -/// is nearly all taken simply goes without rather than spinning. +/// Random draws before scanning the remaining ground for safe anomaly sites. #define PLANET_ANOMALY_PLACEMENT_ATTEMPTS 400 /// Multiplier on ore mined per planet rock wall (mineralAmt), per zone, green stays baseline (x1). Applied in /turf/closed/mineral/proc/zone_scaled_ore_amount() #define ZONE_PLANET_ORE_MULT_YELLOW 1.5 #define ZONE_PLANET_ORE_MULT_RED 2 - diff --git a/voidcrew/datums/mapgen/PlanetGenerator.dm b/voidcrew/datums/mapgen/PlanetGenerator.dm index 4b3ab8e1531..9907985c0fa 100644 --- a/voidcrew/datums/mapgen/PlanetGenerator.dm +++ b/voidcrew/datums/mapgen/PlanetGenerator.dm @@ -397,7 +397,7 @@ var/mob_chance_mult = 1 var/mob_upgrade_prob = 0 var/spawner_budget = ZONE_PLANET_SPAWNER_BUDGET_GREEN - var/anomaly_chance = ZONE_PLANET_ANOMALY_CHANCE_GREEN + var/anomaly_budget = ZONE_PLANET_ANOMALY_BUDGET_GREEN // Megafauna are apex content and stay out of the shallow end entirely - a green-zone // planet is where a crew takes its first landing. var/megafauna_allowed = FALSE @@ -418,13 +418,13 @@ mob_chance_mult = ZONE_PLANET_MOB_CHANCE_MULT_YELLOW mob_upgrade_prob = ZONE_PLANET_MOB_UPGRADE_PROB_YELLOW spawner_budget = ZONE_PLANET_SPAWNER_BUDGET_YELLOW - anomaly_chance = ZONE_PLANET_ANOMALY_CHANCE_YELLOW + anomaly_budget = ZONE_PLANET_ANOMALY_BUDGET_YELLOW megafauna_allowed = TRUE if(ZONE_RED) mob_chance_mult = ZONE_PLANET_MOB_CHANCE_MULT_RED mob_upgrade_prob = ZONE_PLANET_MOB_UPGRADE_PROB_RED spawner_budget = ZONE_PLANET_SPAWNER_BUDGET_RED - anomaly_chance = ZONE_PLANET_ANOMALY_CHANCE_RED + anomaly_budget = ZONE_PLANET_ANOMALY_BUDGET_RED megafauna_allowed = TRUE // Structure spawners and megafauna are placed after the pass, not during it. Both are @@ -562,8 +562,6 @@ var/spawners_placed = place_budgeted_spawners(spawner_candidates, spawner_budget) var/megafauna_placed = place_planet_megafauna(megafauna_candidates) - // One anomaly at most, and only on a successful roll: they are a rare find - var/anomaly_budget = prob(anomaly_chance) ? 1 : 0 var/anomalies_placed = place_budgeted_anomalies(turfs, anomaly_budget) log_world("[name] terrain population finished in [(REALTIMEOFDAY - start_time)/10]s! \ @@ -618,29 +616,28 @@ * instead: pick() is O(1), where walking the list in order would put every anomaly in the * low corner of the map, get_block() handing out turfs row-major. * - * The draw is attempt-bounded rather than exhaustive. A planet whose open ground is - * nearly all spoken for seeds fewer anomalies than its budget, which is the right way to - * fail: this is optional scenery, not something worth stalling a build over. + * If random sampling misses safe ground, scan the supplied planet turfs to fill the + * remainder. Both passes yield to the worldgen budget and use the same safety checks. * * The landing strip is off limits, the same as it is to spawners and megafauna. A rejected - * draw costs one of PLANET_ANOMALY_PLACEMENT_ATTEMPTS attempts and the budget is re-spent - * on the next roll, so this moves anomalies off the berths rather than losing any. The - * strip is the bottom 54 rows of a 123-row planet, so a bit under half the draws land in it - * - against 400 attempts for a budget of at most three, which is not close to tight. + * draw is re-spent on another tile. If the geometry cannot fit the budget safely, report + * the shortfall rather than relaxing the spacing or putting a hazard on reserved ground. */ /datum/map_generator/planet_generator/proc/place_budgeted_anomalies(list/turfs, budget) - if(!length(turfs) || budget <= 0) + if(budget <= 0) return 0 var/list/placed_at = list() var/placed = 0 - for(var/attempt in 1 to PLANET_ANOMALY_PLACEMENT_ATTEMPTS) + var/random_attempts = length(turfs) ? PLANET_ANOMALY_PLACEMENT_ATTEMPTS : 0 + for(var/attempt in 1 to random_attempts + length(turfs)) if(placed >= budget) break + SSovermap.worldgen_yield(throttled) - var/turf/candidate = pick(turfs) - if(!isturf(candidate) || candidate.density) + var/turf/candidate = attempt <= random_attempts ? pick_anomaly_turf(turfs) : turfs[attempt - random_attempts] + if(!isturf(candidate) || candidate.density || candidate.planet_river) continue // Reserved ground: the planet's landing strip (reserve_dock_strip() flags the berth @@ -673,10 +670,15 @@ new anomaly_type(candidate) placed_at += candidate placed++ - CHECK_TICK + if(placed < budget) + log_world("[name] anomaly placement shortfall: [placed]/[budget] safe sites.") return placed +/// Samples the planet's supplied turf list before the exhaustive placement pass. +/datum/map_generator/planet_generator/proc/pick_anomaly_turf(list/turfs) + return pick(turfs) + /// Places a single megafauna from the banked candidates. One per planet, and only where /// the zone band allows them at all - see megafauna_allowed in populate_terrain(). /datum/map_generator/planet_generator/proc/place_planet_megafauna(list/candidates) diff --git a/voidcrew/datums/mapgen/planet_anomalies.dm b/voidcrew/datums/mapgen/planet_anomalies.dm index 8339c6c92de..d2b5c747912 100644 --- a/voidcrew/datums/mapgen/planet_anomalies.dm +++ b/voidcrew/datums/mapgen/planet_anomalies.dm @@ -41,8 +41,8 @@ /** * Weighted table of anomaly types a planet may seed, in three rarity bands that match - * the price bands Boffin sells their cores and charts in. Whether a planet gets one at - * all is a per-zone roll (ZONE_PLANET_ANOMALY_CHANCE_*, see planet_anomaly_chance()). + * the price bands Boffin sells their cores and charts in. The per-zone natural count + * is set by ZONE_PLANET_ANOMALY_BUDGET_* in PlanetGenerator.dm. */ GLOBAL_LIST_INIT(voidcrew_planet_anomalies, list( // Common @@ -59,15 +59,6 @@ GLOBAL_LIST_INIT(voidcrew_planet_anomalies, list( /obj/effect/anomaly/bhole/planetary = 5, )) -/// Percent chance a planet in `zone_band` seeds its one anomaly -/proc/planet_anomaly_chance(zone_band) - switch(zone_band) - if(ZONE_YELLOW) - return ZONE_PLANET_ANOMALY_CHANCE_YELLOW - if(ZONE_RED) - return ZONE_PLANET_ANOMALY_CHANCE_RED - return ZONE_PLANET_ANOMALY_CHANCE_GREEN - /obj/effect/anomaly /// Whether this anomaly is leashed to the site it formed on (see anomaly_site_leash) var/site_bound = FALSE diff --git a/voidcrew/edits/objects/items/event_horizon_rifle.dm b/voidcrew/edits/objects/items/event_horizon_rifle.dm index 4f366f7d38a..47adda3eb4a 100644 --- a/voidcrew/edits/objects/items/event_horizon_rifle.dm +++ b/voidcrew/edits/objects/items/event_horizon_rifle.dm @@ -21,7 +21,7 @@ /obj/item/gun/energy/event_horizon/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread) if(!COOLDOWN_FINISHED(src, shot_cooldown)) - balloon_alert(user, "ready in [round(COOLDOWN_TIMELEFT(src, shot_cooldown) / (1 SECONDS))]s!") + balloon_alert(user, "still cycling") return . = ..() if(.) @@ -30,7 +30,7 @@ /obj/item/gun/energy/event_horizon/examine(mob/user) . = ..() if(!COOLDOWN_FINISHED(src, shot_cooldown)) - . += span_notice("It is still cycling. It can fire again in [DisplayTimeText(COOLDOWN_TIMELEFT(src, shot_cooldown))].") + . += span_notice("It is still cycling.") /obj/item/ammo_casing/energy/event_horizon e_cost = LASER_SHOTS(3, STANDARD_CELL_CHARGE) diff --git a/voidcrew/modules/trade/anomaly_charts.dm b/voidcrew/modules/trade/anomaly_charts.dm index a11b91b0b6d..a0265dec6e1 100644 --- a/voidcrew/modules/trade/anomaly_charts.dm +++ b/voidcrew/modules/trade/anomaly_charts.dm @@ -161,7 +161,7 @@ return FALSE var/turf/spawn_turf = find_spawn_turf(site) if(!spawn_turf) - buyer.ship_notify("Faint anomalous readings near [site.name], too unsteady to fix. They may settle on your next approach.", "SENSORS", SHIP_NOTIFY_WARNING, 'voidcrew/sound/warn.ogg', 25) + buyer.ship_notify("Faint anomalous readings near [site.name].", "SENSORS", SHIP_NOTIFY_WARNING, 'voidcrew/sound/warn.ogg', 25) return FALSE surfaced = TRUE @@ -288,14 +288,14 @@ buyer = null revealed = FALSE ship.pending_rumors |= src - ship.ship_notify("The site on the \"[name]\" chart has dropped off the scopes. The chart is sealed again and can be revealed from the helm for a new fix.", "HELM", SHIP_NOTIFY_WARNING, 'voidcrew/sound/warn.ogg', 25) + ship.ship_notify("The site on the \"[name]\" chart has dropped off the scopes.", "HELM", SHIP_NOTIFY_WARNING, 'voidcrew/sound/warn.ogg', 25) /** * # Anomaly chart SKU * * Sold on Boffin's chart rotation. No goods change hands: the sealed chart goes * straight to the buyer's ship, and its reveal and arrival do the rest. Stock is - * one, and a sold chart's slot turns over to a different anomaly at the next + * two, and an exhausted slot turns over to a different anomaly at the next * convoy rather than refilling (see /datum/shop_rotation). */ /datum/shop_sku/anomaly_chart @@ -303,8 +303,8 @@ icon_override = 'icons/obj/scrolls.dmi' icon_state_override = "blueprints" is_chart = TRUE - stock_min = 1 - stock_max = 1 + stock_min = 2 + stock_max = 2 contract_reward = FALSE /// The site-bound anomaly the chart surfaces var/obj/effect/anomaly/anomaly_type @@ -318,14 +318,14 @@ var/anomaly_name = initial(anomaly_type.name) var/band_name = spawn_zone == ZONE_RED ? ZONE_NAME_RED : ZONE_NAME_YELLOW name = "anomaly chart: [anomaly_name]" - desc = "Sensor logs on \a [anomaly_name] settling somewhere in the [band_name], either aboard a derelict or out on a planet. Uploaded sealed to your helm. The readings only firm up once your own ship is docked at the site." + desc = "Sensor logs on \a [anomaly_name] somewhere in the [band_name]." /datum/shop_sku/anomaly_chart/get_denial_reason(mob/living/user) . = ..() if(.) return if(!get_crew_ship(user)) - return "No crew registration, you need a ship to upload the chart to." + return "No crew registration." /datum/shop_sku/anomaly_chart/try_purchase(mob/living/user, mob/living/basic/outpost_trader/vendor) if(stock <= 0) @@ -348,7 +348,7 @@ stock-- ship.add_pending_rumor(create_chart()) - to_chat(user, span_notice("The chart is encrypted and beamed to [ship]'s helm console. Reveal it when your crew is ready to move.")) + to_chat(user, span_notice("The chart is beamed to [ship]'s helm console.")) return TRUE /// A fresh sealed chart for one purchase @@ -356,7 +356,7 @@ var/datum/rumor_chart/anomaly/chart = new var/anomaly_name = initial(anomaly_type.name) chart.name = capitalize(anomaly_name) - chart.desc = "[capitalize("\a [anomaly_name]")] in the [spawn_zone == ZONE_RED ? ZONE_NAME_RED : ZONE_NAME_YELLOW]. Nothing will show on the site until your ship docks there." + chart.desc = "[capitalize("\a [anomaly_name]")] in the [spawn_zone == ZONE_RED ? ZONE_NAME_RED : ZONE_NAME_YELLOW]." chart.anomaly_type = anomaly_type chart.spawn_zone = spawn_zone return chart diff --git a/voidcrew/modules/trade/shop_catalog_outfitter_vendors.dm b/voidcrew/modules/trade/shop_catalog_outfitter_vendors.dm index 44d0d6dbedc..b18bdb65d93 100644 --- a/voidcrew/modules/trade/shop_catalog_outfitter_vendors.dm +++ b/voidcrew/modules/trade/shop_catalog_outfitter_vendors.dm @@ -289,7 +289,7 @@ ) /datum/shop_rotation/skunk_anomaly_charts - slots = 2 + slots = 4 pool = list( /datum/shop_sku/anomaly_chart/flux = 6, /datum/shop_sku/anomaly_chart/grav = 6, diff --git a/voidcrew/modules/unit_tests/_unit_tests.dm b/voidcrew/modules/unit_tests/_unit_tests.dm index 306835028b8..e59bdc52456 100644 --- a/voidcrew/modules/unit_tests/_unit_tests.dm +++ b/voidcrew/modules/unit_tests/_unit_tests.dm @@ -169,6 +169,7 @@ #include "voidcrew_outpost_yard_droids.dm" #include "voidcrew_overmap_management.dm" #include "voidcrew_pandora_links.dm" +#include "voidcrew_planet_anomalies.dm" #include "voidcrew_planet_cleanup.dm" #include "voidcrew_planet_definitions.dm" #include "voidcrew_planet_shared_air.dm" diff --git a/voidcrew/modules/unit_tests/voidcrew_anomaly_trade.dm b/voidcrew/modules/unit_tests/voidcrew_anomaly_trade.dm index 9e1b8883aa8..d729e916581 100644 --- a/voidcrew/modules/unit_tests/voidcrew_anomaly_trade.dm +++ b/voidcrew/modules/unit_tests/voidcrew_anomaly_trade.dm @@ -24,7 +24,7 @@ if(ispath(item, /obj/item/raw_anomaly_core)) TEST_FAIL("[pack.type] sells [item] over cargo") -/// Boffin's core and chart rotations: every type, the right price band, one unit, +/// Boffin's core and chart rotations: every type, the right price band and stock, /// no discounts, and sold slots turn over instead of refilling. /datum/unit_test/voidcrew_anomaly_boffin_shelves/Run() var/list/core_prices = list( @@ -61,6 +61,9 @@ TEST_ASSERT_NOTNULL(cores, "Boffin has no raw core rotation") TEST_ASSERT_NOTNULL(charts, "Boffin has no anomaly chart rotation") + TEST_ASSERT_EQUAL(cores.slots, 2, "Boffin must keep two core slots") + TEST_ASSERT_EQUAL(charts.slots, 4, "Boffin must stock four chart slots") + var/list/cores_seen = list() for(var/datum/shop_sku/sku_type as anything in cores.pool) var/item = initial(sku_type.item_path) @@ -68,6 +71,7 @@ TEST_ASSERT_EQUAL(initial(sku_type.price_credits), core_prices[item], "[sku_type] is in the wrong price band") TEST_ASSERT(!initial(sku_type.fixed_price), "[sku_type] ignores favor and specials") TEST_ASSERT(!initial(sku_type.contract_reward), "[sku_type] can be paid out by contracts") + TEST_ASSERT_EQUAL(initial(sku_type.stock_min), 1, "[sku_type] does not always stock one core") TEST_ASSERT_EQUAL(initial(sku_type.stock_max), 1, "[sku_type] stocks more than one unit") cores_seen[item] = cores.pool[sku_type] TEST_ASSERT_EQUAL(length(cores_seen), 9, "Boffin's core rotation does not cover all nine types") @@ -85,6 +89,9 @@ TEST_ASSERT_NOTNULL(base_type, "[sku_type] points at [anomaly], which is not one of the nine anomaly types") TEST_ASSERT_EQUAL(initial(sku_type.price_credits), chart_prices[base_type], "[sku_type] is in the wrong price band") TEST_ASSERT(!initial(sku_type.fixed_price), "[sku_type] ignores favor and specials") + TEST_ASSERT_EQUAL(initial(sku_type.stock_min), 2, "[sku_type] must always stock two charts") + TEST_ASSERT_EQUAL(initial(sku_type.stock_max), 2, "[sku_type] must stock at most two charts") + TEST_ASSERT(!initial(sku_type.contract_reward), "[sku_type] can be paid out by contracts") var/obj/effect/anomaly/anomaly_path = anomaly TEST_ASSERT(initial(anomaly_path.immortal) && initial(anomaly_path.site_bound), "[sku_type] surfaces an anomaly that times out or can leave its site") charts_seen[base_type] = TRUE @@ -95,9 +102,11 @@ for(var/datum/shop_sku/sku as anything in shop.skus) if(sku.rotation == rotation) on_shelf += sku - TEST_ASSERT(length(on_shelf) >= 1 && length(on_shelf) <= rotation.slots, "[rotation.type] put [length(on_shelf)] SKUs on the shelf") + TEST_ASSERT_EQUAL(length(on_shelf), rotation.slots, "[rotation.type] put [length(on_shelf)] SKUs on the shelf") var/datum/shop_sku/sold = on_shelf[1] - TEST_ASSERT_EQUAL(sold.stock, 1, "[sold.type] stocked [sold.stock] units") + var/expected_stock = rotation == charts ? 2 : 1 + for(var/datum/shop_sku/sku as anything in on_shelf) + TEST_ASSERT_EQUAL(sku.stock, expected_stock, "[sku.type] stocked the wrong number of units") sold.discount_pct = 30 TEST_ASSERT_EQUAL(sold.get_credit_price(), round(sold.price_credits * 0.7, 5), "A special did not discount [sold.type]") var/sold_type = sold.type @@ -108,6 +117,7 @@ for(var/datum/shop_sku/sku as anything in shop.skus) if(sku.rotation == rotation) after += sku.type + TEST_ASSERT_EQUAL(sku.stock, expected_stock, "The convoy changed [sku.type] stock") TEST_ASSERT_EQUAL(length(after), length(on_shelf), "The convoy did not replace the sold slot") TEST_ASSERT(!(sold_type in after), "The sold slot came back as the same [sold_type]") TEST_ASSERT_EQUAL(length(unique_list(after)), length(after), "The rotation shelved the same SKU twice") @@ -139,7 +149,9 @@ /// Buying a chart takes the money and puts a sealed anomaly rumor on the ship. /datum/unit_test/voidcrew_anomaly_chart_purchase/Run() var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) - shop.add_sku(/datum/shop_sku/anomaly_chart/grav, "rotating") + var/datum/shop_rotation/rotation = new /datum/shop_rotation/skunk_anomaly_charts + shop.live_rotations += rotation + shop.add_rotation_sku(rotation, /datum/shop_sku/anomaly_chart/grav) var/datum/shop_sku/anomaly_chart/sku = shop.skus[1] var/obj/structure/overmap/ship/ship = allocate(/obj/structure/overmap/ship) var/mob/living/carbon/human/buyer = allocate(/mob/living/carbon/human/consistent) @@ -149,24 +161,42 @@ team.ship = ship buyer.mind.ship_teams = list(team) var/datum/bank_account/account = allocate(/datum/bank_account, "Anomaly chart test", null, 1, FALSE) - account.account_balance = 20000 + account.account_balance = 40000 var/obj/item/card/id/advanced/id_card = allocate(/obj/item/card/id/advanced) qdel(id_card.registered_account) id_card.registered_account = account TEST_ASSERT(buyer.put_in_hands(id_card), "Buyer could not carry their paying ID") TEST_ASSERT(sku.try_purchase(buyer, null), "Chart purchase failed") - TEST_ASSERT_EQUAL(account.account_balance, 7500, "The chart charged the wrong amount") + TEST_ASSERT_EQUAL(account.account_balance, 27500, "The chart charged the wrong amount") TEST_ASSERT_EQUAL(length(ship.pending_rumors), 1, "Purchase did not upload a sealed chart") var/datum/rumor_chart/anomaly/chart = ship.pending_rumors[1] TEST_ASSERT(istype(chart), "The sealed chart is not an anomaly chart") TEST_ASSERT_EQUAL(chart.anomaly_type, /obj/effect/anomaly/grav/planetary, "The chart names the wrong anomaly") TEST_ASSERT(!chart.revealed && !chart.surfaced, "A fresh chart is already revealed") - TEST_ASSERT(!sku.try_purchase(buyer, null), "A one-unit chart sold twice") - TEST_ASSERT_EQUAL(account.account_balance, 7500, "A refused purchase took money") + TEST_ASSERT_EQUAL(sku.stock, 1, "The first purchase did not leave one chart") + shop.convoy_restock() + TEST_ASSERT(sku in shop.skus, "The convoy replaced a partially sold chart slot") + TEST_ASSERT_EQUAL(sku.stock, 1, "The convoy refilled a partially sold chart slot") + sku.discount_pct = 0 // The convoy rerolls the special independently of stock. + TEST_ASSERT(sku.try_purchase(buyer, null), "The second chart purchase failed") + TEST_ASSERT_EQUAL(sku.stock, 0, "The second purchase did not exhaust the slot") + TEST_ASSERT_EQUAL(account.account_balance, 15000, "The second chart charged the wrong amount") + TEST_ASSERT_EQUAL(length(ship.pending_rumors), 2, "Two purchases did not upload two charts") + var/datum/rumor_chart/anomaly/second_chart = ship.pending_rumors[2] + TEST_ASSERT(second_chart != chart, "Two purchases shared a chart datum") + TEST_ASSERT(!sku.try_purchase(buyer, null), "An exhausted chart slot sold a third unit") + TEST_ASSERT_EQUAL(account.account_balance, 15000, "A refused purchase took money") + TEST_ASSERT_EQUAL(length(ship.pending_rumors), 2, "A refused purchase uploaded a chart") + shop.convoy_restock() + TEST_ASSERT(!(sku in shop.skus), "The convoy did not replace the exhausted chart slot") + TEST_ASSERT_EQUAL(length(shop.skus), 1, "The convoy lost the exhausted chart slot") + var/datum/shop_sku/replacement = shop.skus[1] + TEST_ASSERT(replacement.type != /datum/shop_sku/anomaly_chart/grav, "The exhausted chart refilled in place") + TEST_ASSERT_EQUAL(replacement.stock, 2, "The replacement chart slot did not stock two units") qdel(ship) - TEST_ASSERT(QDELETED(chart), "Hull loss left its sealed chart alive") + TEST_ASSERT(QDELETED(chart) && QDELETED(second_chart), "Hull loss left a sealed chart alive") buyer.mind.ship_teams = null team.ship = null @@ -271,10 +301,6 @@ TEST_ASSERT(weights[base_type], "[base_type] never seeds on planets") TEST_ASSERT(weights[/obj/effect/anomaly/pyro] > weights[/obj/effect/anomaly/dimensional], "Uncommon planet anomalies are not rarer than common ones") TEST_ASSERT(weights[/obj/effect/anomaly/dimensional] > weights[/obj/effect/anomaly/bhole], "Rare planet anomalies are not rarer than uncommon ones") - // Literals 1/2/3 = ZONE_GREEN/YELLOW/RED: every band can roll one, deeper bands more often - TEST_ASSERT_EQUAL(planet_anomaly_chance(1), 5, "Wrong green planet anomaly chance") - TEST_ASSERT_EQUAL(planet_anomaly_chance(2), 15, "Wrong yellow planet anomaly chance") - TEST_ASSERT_EQUAL(planet_anomaly_chance(3), 25, "Wrong red planet anomaly chance") /// The planetary pyroclastic anomaly burns whoever is next to it and never touches the air. /datum/unit_test/voidcrew_planet_pyro_jets/Run() diff --git a/voidcrew/modules/unit_tests/voidcrew_planet_anomalies.dm b/voidcrew/modules/unit_tests/voidcrew_planet_anomalies.dm new file mode 100644 index 00000000000..11c647045fa --- /dev/null +++ b/voidcrew/modules/unit_tests/voidcrew_planet_anomalies.dm @@ -0,0 +1,195 @@ +/// A deterministic miss on every random sample, followed by the real exhaustive pass. +/datum/map_generator/planet_generator/anomaly_test + var/turf/forced_sample + var/sample_calls = 0 + +/datum/map_generator/planet_generator/anomaly_test/pick_anomaly_turf(list/turfs) + // Deliberately replace random sampling; placement and all safety checks remain real. + sample_calls++ + return forced_sample + +/// Small, reversible ground fixtures on the unit-test level, with harmless anomaly types. +/datum/unit_test/voidcrew_planet_anomalies + abstract_type = /datum/unit_test/voidcrew_planet_anomalies + var/datum/biome/ground_biome + var/list/original_turfs = list() + var/list/remembered_turfs = list() + var/list/original_anomalies + var/list/obj/structure/overmap/planet/planets = list() + +/datum/unit_test/voidcrew_planet_anomalies/New() + . = ..() + ground_biome = allocate(/datum/biome) + ground_biome.open_turf_types = list(/turf/open/floor/plating = 1) + ground_biome.flora_spawn_chance = 0 + ground_biome.feature_spawn_chance = 0 + ground_biome.mob_spawn_chance = 0 + original_anomalies = GLOB.voidcrew_planet_anomalies + GLOB.voidcrew_planet_anomalies = list(/obj/effect/anomaly/grav/planetary = 1) + +/datum/unit_test/voidcrew_planet_anomalies/Destroy() + GLOB.voidcrew_planet_anomalies = original_anomalies + original_anomalies = null + for(var/obj/structure/overmap/planet/planet as anything in planets) + // These fixtures borrow the test level, never its teardown authority. + planet.footprint = null + planet.mapzone = null + planets.Cut() + QDEL_LIST(allocated) + for(var/list/snapshot as anything in original_turfs) + var/turf/target = locate(snapshot[1], snapshot[2], snapshot[3]) + for(var/obj/effect/anomaly/anomaly in target) + qdel(anomaly) + if(target.type != snapshot[4]) + target = target.ChangeTurf(snapshot[4]) + target.change_area(get_area(target), snapshot[8]) + target.turf_flags = snapshot[5] + target.generating_biome = snapshot[6] + target.planet_river = snapshot[7] + target.density = snapshot[9] + original_turfs.Cut() + remembered_turfs.Cut() + ground_biome = null + return ..() + +/datum/unit_test/voidcrew_planet_anomalies/proc/remember_turf(turf/target) + var/key = "[target.x],[target.y],[target.z]" + if(remembered_turfs[key]) + return + remembered_turfs[key] = TRUE + original_turfs += list(list(target.x, target.y, target.z, target.type, target.turf_flags, target.generating_biome, target.planet_river, get_area(target), target.density)) + +/datum/unit_test/voidcrew_planet_anomalies/proc/ground(x, y) + var/turf/target = locate(x, y, run_loc_floor_bottom_left.z) + remember_turf(target) + target = target.ChangeTurf(/turf/open/floor/plating) + target.change_area(get_area(target), get_area(run_loc_floor_bottom_left)) + target.generating_biome = ground_biome + target.turf_flags &= ~NO_RUINS + target.planet_river = FALSE + return target + +/datum/unit_test/voidcrew_planet_anomalies/proc/anomalies_on(list/turfs) + var/list/found = list() + for(var/turf/target as anything in turfs) + for(var/obj/effect/anomaly/anomaly in target) + found += anomaly + return found + +/// Drive populate_terrain itself, so a correct define behind a leftover chance roll fails. +/datum/unit_test/voidcrew_planet_anomalies/counts/Run() + var/list/turfs = list(ground(40, 40), ground(60, 40), ground(80, 40)) + var/datum/map_generator/planet_generator/generator = allocate(/datum/map_generator/planet_generator) + generator.throttled = FALSE + // Literals 1/2/3 are ZONE_GREEN/YELLOW/RED; fork defines are included after tests. + for(var/band in 1 to 3) + generator.populate_terrain(turfs, get_area(turfs[1]), band) + var/list/spawned = anomalies_on(turfs) + TEST_ASSERT_EQUAL(length(spawned), band, "Band [band] did not seed its natural anomaly count") + QDEL_LIST(spawned) + +/// Exhaustive placement recovers all missed sites, while keeping every rejection intact. +/datum/unit_test/voidcrew_planet_anomalies/sampling_misses/Run() + var/turf/river = ground(40, 40) + river.planet_river = TRUE + var/turf/dense = ground(41, 40) + dense.density = TRUE + var/turf/no_biome = ground(42, 40) + no_biome.generating_biome = null + var/turf/wrong_ground = ground(43, 40) + var/datum/biome/other_biome = allocate(/datum/biome) + other_biome.open_turf_types = list(/turf/open/space = 1) + wrong_ground.generating_biome = other_biome + var/turf/structure = ground(44, 40) + allocate(/obj/structure, structure) + var/turf/occupied = ground(45, 40) + allocate(/mob/living/basic, occupied) + var/list/rejected = list(river, dense, no_biome, wrong_ground, structure, occupied) + var/list/legal = list(ground(40, 60), ground(60, 60), ground(80, 60)) + var/datum/map_generator/planet_generator/anomaly_test/generator = allocate(/datum/map_generator/planet_generator/anomaly_test) + generator.throttled = FALSE + generator.forced_sample = river + TEST_ASSERT_EQUAL(generator.place_budgeted_anomalies(rejected + legal, 3), 3, "Sampling misses lost a safely placeable anomaly") + TEST_ASSERT_EQUAL(generator.sample_calls, 400, "The fixture did not exhaust PLANET_ANOMALY_PLACEMENT_ATTEMPTS") + TEST_ASSERT_EQUAL(length(anomalies_on(legal)), 3, "The fallback did not fill all legal sites") + TEST_ASSERT_EQUAL(length(anomalies_on(rejected)), 0, "The fallback put an anomaly on unsafe ground") + dense.density = FALSE + +/// Geometry may leave a shortfall; 19 tiles is too close, exactly 20 is legal. +/datum/unit_test/voidcrew_planet_anomalies/shortfall/Run() + var/turf/first = ground(40, 40) + var/turf/too_close = ground(59, 40) + var/turf/boundary = ground(60, 40) + var/datum/map_generator/planet_generator/anomaly_test/generator = allocate(/datum/map_generator/planet_generator/anomaly_test) + generator.throttled = FALSE + generator.forced_sample = first + TEST_ASSERT_EQUAL(generator.place_budgeted_anomalies(list(first, too_close, boundary), 3), 2, "A shortfall forced an anomaly inside the separation limit") + TEST_ASSERT_NULL(locate(/obj/effect/anomaly) in too_close, "An anomaly was placed within 20 tiles") + TEST_ASSERT_NOTNULL(locate(/obj/effect/anomaly) in boundary, "An anomaly exactly 20 tiles away was refused") + TEST_ASSERT_EQUAL(generator.place_budgeted_anomalies(list(), 1), 0, "Empty ground filled an anomaly budget") + TEST_ASSERT_EQUAL(generator.place_budgeted_anomalies(list(first), 0), 0, "A zero budget placed an anomaly") + +/// Real landing-strip flags and leashes stay local to two neighbouring footprints. +/datum/unit_test/voidcrew_planet_anomalies/landing_neighbours/Run() + var/datum/space_level/level = SSmapping.z_list[run_loc_floor_bottom_left.z] + var/list/sites = list() + var/list/strips = list() + for(var/index in 1 to 2) + var/obj/structure/overmap/planet/planet = allocate(/obj/structure/overmap/planet) + planets += planet + var/datum/map_footprint/footprint = allocate(/datum/map_footprint, null, "planet", index, planet) + footprint.attach_level(level) + footprint.set_rect(40 + (index - 1) * 10, 40, 5, 60) + planet.footprint = footprint + var/strip_top = planet.get_dock_strip_top_y(level) + strips += ground(footprint.low_x, strip_top) + sites += ground(footprint.low_x, strip_top + 1) + for(var/turf/target as anything in footprint.get_block()) + remember_turf(target) + + var/datum/map_generator/planet_generator/anomaly_test/generator = allocate(/datum/map_generator/planet_generator/anomaly_test) + generator.throttled = FALSE + for(var/index in 1 to 2) + var/obj/structure/overmap/planet/planet = planets[index] + planet.reserve_dock_strip(level) + var/turf/strip = strips[index] + TEST_ASSERT(strip.turf_flags & NO_RUINS, "The landing-clearance boundary was not reserved") + if(index == 1) + var/turf/neighbour_strip = strips[2] + TEST_ASSERT(!(neighbour_strip.turf_flags & NO_RUINS), "Reserving one strip changed its neighbour") + generator.forced_sample = strip + TEST_ASSERT_EQUAL(generator.place_budgeted_anomalies(list(strip, sites[index]), 1), 1, "The strip consumed a planet's anomaly budget") + TEST_ASSERT_NULL(locate(/obj/effect/anomaly) in strip, "An anomaly formed in the landing clearance") + + TEST_ASSERT(get_dist(sites[1], sites[2]) < 20, "The fixture must put the two sites within natural separation distance") + for(var/index in 1 to 2) + var/obj/effect/anomaly/anomaly = locate(/obj/effect/anomaly) in sites[index] + TEST_ASSERT_NOTNULL(anomaly, "A neighbour's anomaly consumed this planet's allowance") + var/datum/component/anomaly_site_leash/leash = anomaly.GetComponent(/datum/component/anomaly_site_leash) + TEST_ASSERT_NOTNULL(leash, "The natural anomaly has no site leash") + TEST_ASSERT(leash.allows(sites[index]), "The anomaly cannot stand on its own site") + TEST_ASSERT(!leash.allows(strips[index]), "The anomaly can enter its landing strip") + TEST_ASSERT(!leash.allows(sites[3 - index]), "The anomaly can enter the neighbouring footprint") + +/// A purchased arrival adds one anomaly alongside the already-filled natural allowance. +/datum/unit_test/voidcrew_planet_anomalies/chart_budget/Run() + var/list/natural_sites = list(ground(40, 40), ground(60, 40), ground(80, 40)) + var/turf/chart_site = ground(100, 40) + var/datum/map_generator/planet_generator/generator = allocate(/datum/map_generator/planet_generator) + generator.throttled = FALSE + generator.populate_terrain(natural_sites, get_area(natural_sites[1]), 3) // ZONE_RED + TEST_ASSERT_EQUAL(length(anomalies_on(natural_sites)), 3, "The natural budget was not filled before arrival") + var/obj/structure/overmap/ship/buyer = allocate(/obj/structure/overmap/ship) + var/obj/structure/overmap/space_ruin/site = allocate(/obj/structure/overmap/space_ruin) + var/datum/rumor_chart/anomaly/unit_test/chart = new + chart.anomaly_type = /obj/effect/anomaly/grav/planetary + chart.test_site = site + chart.test_turf = chart_site + buyer.add_pending_rumor(chart) + TEST_ASSERT_EQUAL(buyer.reveal_pending_rumor(chart), site, "The purchased chart did not reveal") + buyer.docked = site + SEND_SIGNAL(buyer, "voidcrew_ship_docked") + TEST_ASSERT_EQUAL(length(anomalies_on(natural_sites + list(chart_site))), 4, "The chart shared the natural budget") + SEND_SIGNAL(buyer, "voidcrew_ship_docked") + TEST_ASSERT_EQUAL(length(anomalies_on(natural_sites + list(chart_site))), 4, "A spent chart surfaced twice") + buyer.docked = null From da0fd04b74f1528a055715d75e99b27974e1c41e Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:04:14 -0700 Subject: [PATCH 022/105] Restrict procurement to eligible field goods --- .../modules/missions/missions/delivery.dm | 33 +-- voidcrew/modules/trade/outpost_missions.dm | 104 +++++++-- .../trade/shop_catalog_black_market.dm | 4 - .../modules/trade/shop_catalog_general.dm | 3 - .../modules/trade/shop_catalog_outfitter.dm | 8 +- .../modules/trade/shop_catalog_suit_vendor.dm | 12 +- .../unit_tests/voidcrew_shop_catalog.dm | 199 ++++++++++++++++++ 7 files changed, 287 insertions(+), 76 deletions(-) diff --git a/voidcrew/modules/missions/missions/delivery.dm b/voidcrew/modules/missions/missions/delivery.dm index a951bd45fc7..2b05aebd61b 100644 --- a/voidcrew/modules/missions/missions/delivery.dm +++ b/voidcrew/modules/missions/missions/delivery.dm @@ -6,7 +6,7 @@ */ /datum/mission/delivery name = "Delivery Contract" - weight = 10 + weight = 0 /// The rolled ask (kept for UI keys) var/required_type = /obj/item/stack/ore/iron @@ -14,32 +14,8 @@ var/required_amount = 1 /datum/mission/delivery/generate_details() - // Each target defines its own difficulty, amount, and value range - var/static/list/delivery_targets = list( - // Easy - common ores, low amounts - list("type" = /obj/item/stack/ore/iron, "name" = "iron ore", "amount" = 10, "value_min" = 400, "value_max" = 600, "difficulty" = MISSION_DIFFICULTY_EASY), - list("type" = /obj/item/stack/ore/glass, "name" = "sand", "amount" = 15, "value_min" = 300, "value_max" = 500, "difficulty" = MISSION_DIFFICULTY_EASY), - list("type" = /obj/item/stack/sheet/iron, "name" = "iron sheets", "amount" = 10, "value_min" = 500, "value_max" = 700, "difficulty" = MISSION_DIFFICULTY_EASY), - list("type" = /obj/item/stack/sheet/glass, "name" = "glass sheets", "amount" = 10, "value_min" = 400, "value_max" = 600, "difficulty" = MISSION_DIFFICULTY_EASY), - // Medium - uncommon ores, moderate amounts - list("type" = /obj/item/stack/ore/plasma, "name" = "plasma ore", "amount" = 10, "value_min" = 800, "value_max" = 1200, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = /obj/item/stack/ore/silver, "name" = "silver ore", "amount" = 8, "value_min" = 700, "value_max" = 1000, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = /obj/item/stack/ore/titanium, "name" = "titanium ore", "amount" = 8, "value_min" = 800, "value_max" = 1100, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = /obj/item/stack/sheet/plasteel, "name" = "plasteel sheets", "amount" = 5, "value_min" = 1000, "value_max" = 1400, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - // Hard - rare ores, higher amounts - list("type" = /obj/item/stack/ore/gold, "name" = "gold ore", "amount" = 8, "value_min" = 1200, "value_max" = 1800, "difficulty" = MISSION_DIFFICULTY_HARD), - list("type" = /obj/item/stack/ore/uranium, "name" = "uranium ore", "amount" = 6, "value_min" = 1400, "value_max" = 2000, "difficulty" = MISSION_DIFFICULTY_HARD), - list("type" = /obj/item/stack/ore/diamond, "name" = "diamond ore", "amount" = 4, "value_min" = 2000, "value_max" = 3000, "difficulty" = MISSION_DIFFICULTY_HARD), - list("type" = /obj/item/stack/ore/bluespace_crystal, "name" = "bluespace crystals", "amount" = 2, "value_min" = 2500, "value_max" = 3500, "difficulty" = MISSION_DIFFICULTY_HARD), - ) - - var/list/ask = pick(delivery_targets) - required_type = ask["type"] - required_name = ask["name"] - required_amount = ask["amount"] - value_min = ask["value_min"] - value_max = ask["value_max"] - difficulty = ask["difficulty"] + // Suspended until compliant replacement rows receive their own reward design. + generation_failed = TRUE /datum/mission/delivery/build_objectives() var/datum/mission_objective/deliver/ask = new @@ -50,9 +26,8 @@ /datum/mission/delivery/update_text() var/item_text = required_amount > 1 ? "[required_amount] [required_name]" : required_name - var/datum/mission_objective/deliver/ask = objectives[1] name = "Delivery Contract: [item_text]" - desc = "Deliver [item_text] to the mission pad to complete this contract.[ask.get_delivery_instructions()]" + desc = "[author] wants [item_text]." /datum/mission/delivery/get_ui_data() var/list/data = ..() diff --git a/voidcrew/modules/trade/outpost_missions.dm b/voidcrew/modules/trade/outpost_missions.dm index c4796a995c8..e9ee22306ac 100644 --- a/voidcrew/modules/trade/outpost_missions.dm +++ b/voidcrew/modules/trade/outpost_missions.dm @@ -16,6 +16,73 @@ /// How many contracts an outpost keeps posted at once #define OUTPOST_SHOP_OFFER_COUNT 4 +/// Exact request types; fish and bear hides are deliberate owner exceptions. +/proc/is_outpost_procurement_type(item_type) + var/static/list/eligible_types = list( + /obj/item/fish, + /obj/item/stack/sheet/animalhide/bear, + /obj/item/stack/sheet/animalhide/goliath_hide, + /obj/item/stack/sheet/sinew, + /obj/item/stack/spice_pods, + /obj/item/sea_crystal, + /obj/item/stack/telecrystal_raw, + /obj/item/organ/monster_core/regenerative_core/legion, + /obj/item/stack/glacial_core, + // Eligibility only: suit-vendor rows still need reward-design inputs. + /obj/item/mod/construction/broken_core, + /obj/item/mod/control/pre_equipped, + /obj/item/mod/module/springlock, + /obj/item/mod/module/visor/rave, + /obj/item/mod/module/balloon, + /obj/item/mod/module/stamp, + ) + return item_type in eligible_types + +/// Fail closed on unsupported types or incomplete request rows. +/datum/outpost_shop/proc/get_procurement_requests() + var/list/eligible_requests = list() + for(var/list/request as anything in mission_requests) + if(!islist(request) || !is_outpost_procurement_type(request["type"])) + continue + if(!istext(request["name"]) || !length(request["name"])) + continue + var/amount = request["amount"] + if(!isnum(amount) || amount < 1 || amount != round(amount)) + continue + if(!(request["difficulty"] in list(MISSION_DIFFICULTY_EASY, MISSION_DIFFICULTY_MEDIUM, MISSION_DIFFICULTY_HARD))) + continue + if(ispath(request["type"], /obj/item/stack)) + var/obj/item/stack/stack_type = request["type"] + if(amount > initial(stack_type.max_amount)) + continue + eligible_requests += list(request) + return eligible_requests + +/// Procurement validates the configured ask again when goods are handed over. +/datum/mission_objective/deliver/procurement + +/datum/mission_objective/deliver/procurement/matches_ask(obj/item/item) + if(QDELETED(item) || !is_outpost_procurement_type(required_type) || !..()) + return FALSE + if(istype(item, /obj/item/mod/control/pre_equipped)) + var/obj/item/mod/control/pre_equipped/control = item + return isnull(control.wearer) + // A loot module's descendants may be manufactured or have different sources. + if(istype(item, /obj/item/mod/module)) + return item.type == required_type + return TRUE + +/datum/mission_objective/deliver/procurement/can_turn_in(obj/item/item) + if(completed || !matches_ask(item)) + return FALSE + return ..() + +/datum/mission_objective/deliver/procurement/accept_item(obj/item/item, atom/reward_anchor) + if(!can_turn_in(item)) + return MISSION_ITEM_REFUSED + // The parent forgets the quest atom before consuming stacks or loose goods. + return ..() + /** * # Outpost Supply Mission * @@ -58,17 +125,18 @@ /// Rolls the ask off the shop's request table. Override for themed asks. /datum/mission/outpost_supply/proc/pick_request() - var/list/request = length(shop.mission_requests) ? pick(shop.mission_requests) : null + var/list/eligible_requests = shop.get_procurement_requests() + var/list/request = length(eligible_requests) ? pick(eligible_requests) : null if(!request) generation_failed = TRUE return required_type = request["type"] required_name = request["name"] - required_amount = request["amount"] || 1 - difficulty = request["difficulty"] || MISSION_DIFFICULTY_MEDIUM + required_amount = request["amount"] + difficulty = request["difficulty"] /datum/mission/outpost_supply/build_objectives() - var/datum/mission_objective/deliver/ask = new + var/datum/mission_objective/deliver/procurement/ask = new ask.required_type = required_type ask.required_name = required_name ask.required_amount = required_amount @@ -76,10 +144,8 @@ /datum/mission/outpost_supply/update_text() var/item_text = required_amount > 1 ? "[required_amount] [required_name]" : required_name - var/datum/mission_objective/deliver/ask = objectives[1] name = "Supply Request: [item_text]" - desc = "[author] is paying in kit: deliver [item_text] to your ship's mission pad or any outpost trader.[ask.get_delivery_instructions()] \ - Pays [get_contract_pay_summary()], straight off the shelf." + desc = "[author] wants [item_text]." /** * # Angler's Request @@ -123,8 +189,7 @@ /datum/mission/outpost_supply/angler/update_text() var/item_text = required_amount > 1 ? "[required_amount] [required_name]" : required_name name = "Angler's Request: [item_text]" - desc = "[author] wants [item_text]. Any species is accepted, alive or dead. \ - Hand in each fish separately at any outpost trader or your own mission pad. Pays [get_contract_pay_summary()], off the shelf." + desc = "[author] wants [item_text]." /** * # Kitchen Order @@ -177,17 +242,8 @@ /datum/mission/outpost_supply/cook/update_text() var/item_text = required_amount > 1 ? "[required_amount] [required_name]" : required_name - var/obj/item/food/example_dish = /obj/item/food/pizza/mushroom - switch(min_complexity) - if(FOOD_COMPLEXITY_3) - example_dish = /obj/item/food/pizza/donkpocket - if(FOOD_COMPLEXITY_4) - example_dish = /obj/item/food/pizza/pineapple name = "Kitchen Order: [item_text]" - desc = "[author] at the diner is buying [item_text], cooked or crafted by a player. \ - Each dish needs recipe complexity [min_complexity] or higher; a player-made [initial(example_dish.name)] qualifies. \ - Factory food and meals bought from the outpost diner do not qualify. \ - Hand in each dish separately at any outpost trader or your own mission pad. Pays [get_contract_pay_summary()], off the shelf." + desc = "[author] at the diner wants [item_text]." // ===== OFFER MANAGEMENT (lives on the outpost) ===== @@ -206,11 +262,13 @@ /datum/mission/recovery/outpost = 20, /datum/mission/outpost_courier = 15, ) - var/list/mix = offer_mix + var/list/mix = offer_mix.Copy() if(length(shop.extra_offer_mix)) - mix = offer_mix.Copy() for(var/offer_type in shop.extra_offer_mix) mix[offer_type] = shop.extra_offer_mix[offer_type] + var/has_procurement = length(shop.get_procurement_requests()) > 0 + if(!has_procurement) + mix -= /datum/mission/outpost_supply // Prune offers that died on the board (e.g. their pinned target vanished // before anyone accepted) so they don't hold a slot or count against caps for(var/datum/mission/posted as anything in shop_offers.Copy()) @@ -218,9 +276,9 @@ shop_offers -= posted var/safety = 12 while(length(shop_offers) < OUTPOST_SHOP_OFFER_COUNT && safety-- > 0) - // Always keep at least one plain supply request on the board + // Keep a plain supply request on the board only when its pool is eligible. var/offer_type = /datum/mission/outpost_supply - if(has_posted_offer_type(/datum/mission/outpost_supply)) + if(!has_procurement || has_posted_offer_type(/datum/mission/outpost_supply)) offer_type = pick_weight(mix) // Capped types (drug runs) count live missions AND posted offers; the // ship-board roll enforces this in SSmissions, boards must match diff --git a/voidcrew/modules/trade/shop_catalog_black_market.dm b/voidcrew/modules/trade/shop_catalog_black_market.dm index 542719d825d..330001cb658 100644 --- a/voidcrew/modules/trade/shop_catalog_black_market.dm +++ b/voidcrew/modules/trade/shop_catalog_black_market.dm @@ -174,10 +174,6 @@ ) // Vex's supply requests want the rare stuff. The free item makes it worth it mission_requests = list( - list("type" = /obj/item/stack/ore/uranium, "name" = "uranium ore", "amount" = 8, "difficulty" = MISSION_DIFFICULTY_HARD), - list("type" = /obj/item/stack/ore/diamond, "name" = "diamond ore", "amount" = 4, "difficulty" = MISSION_DIFFICULTY_HARD), - list("type" = /obj/item/stack/ore/bluespace_crystal, "name" = "bluespace crystals", "amount" = 2, "difficulty" = MISSION_DIFFICULTY_HARD), - list("type" = /obj/item/stack/sheet/mineral/plasma, "name" = "plasma sheets", "amount" = 20, "difficulty" = MISSION_DIFFICULTY_MEDIUM), list("type" = /obj/item/stack/telecrystal_raw, "name" = "raw telecrystal", "amount" = 10, "difficulty" = MISSION_DIFFICULTY_HARD), list("type" = /obj/item/organ/monster_core/regenerative_core/legion, "name" = "legion core", "amount" = 1, "difficulty" = MISSION_DIFFICULTY_HARD), ) diff --git a/voidcrew/modules/trade/shop_catalog_general.dm b/voidcrew/modules/trade/shop_catalog_general.dm index 3e504607310..44923bb2990 100644 --- a/voidcrew/modules/trade/shop_catalog_general.dm +++ b/voidcrew/modules/trade/shop_catalog_general.dm @@ -163,9 +163,6 @@ /datum/mission/outpost_supply/cook = 15, ) mission_requests = list( - list("type" = /obj/item/stack/ore/iron, "name" = "iron ore", "amount" = 15, "difficulty" = MISSION_DIFFICULTY_EASY), - list("type" = /obj/item/stack/sheet/glass, "name" = "glass sheets", "amount" = 10, "difficulty" = MISSION_DIFFICULTY_EASY), - list("type" = /obj/item/stack/ore/plasma, "name" = "plasma ore", "amount" = 8, "difficulty" = MISSION_DIFFICULTY_MEDIUM), list("type" = /obj/item/fish, "name" = "fish", "amount" = 1, "difficulty" = MISSION_DIFFICULTY_EASY), list("type" = /obj/item/stack/sheet/animalhide/bear, "name" = "bear hide", "amount" = 1, "difficulty" = MISSION_DIFFICULTY_MEDIUM), list("type" = /obj/item/stack/spice_pods, "name" = "wild spice pods", "amount" = 6, "difficulty" = MISSION_DIFFICULTY_MEDIUM), diff --git a/voidcrew/modules/trade/shop_catalog_outfitter.dm b/voidcrew/modules/trade/shop_catalog_outfitter.dm index 63bbe27e028..d6756543a7b 100644 --- a/voidcrew/modules/trade/shop_catalog_outfitter.dm +++ b/voidcrew/modules/trade/shop_catalog_outfitter.dm @@ -168,14 +168,8 @@ /datum/shop_buyback/outfitter/sinew, /datum/shop_buyback/outfitter/glacial_core, ) - // Depot resupply runs: industrial quantities, decent free kit + // Field harvests for depot resupply mission_requests = list( - list("type" = /obj/item/stack/sheet/plasteel, "name" = "plasteel sheets", "amount" = 10, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = /obj/item/stack/ore/titanium, "name" = "titanium ore", "amount" = 12, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = /obj/item/stack/ore/silver, "name" = "silver ore", "amount" = 10, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - // Stack asks are settled from ONE stack, so never ask above max_amount - - // cable coil caps at MAXCOIL (30) and a bigger ask can never be paid - list("type" = /obj/item/stack/cable_coil, "name" = "cable coil", "amount" = 30, "difficulty" = MISSION_DIFFICULTY_EASY), list("type" = /obj/item/stack/sheet/animalhide/goliath_hide, "name" = "goliath hide plates", "amount" = 4, "difficulty" = MISSION_DIFFICULTY_HARD), list("type" = /obj/item/stack/sheet/sinew, "name" = "beast sinew", "amount" = 4, "difficulty" = MISSION_DIFFICULTY_MEDIUM), list("type" = /obj/item/stack/glacial_core, "name" = "glacial cores", "amount" = 5, "difficulty" = MISSION_DIFFICULTY_MEDIUM), diff --git a/voidcrew/modules/trade/shop_catalog_suit_vendor.dm b/voidcrew/modules/trade/shop_catalog_suit_vendor.dm index 9787ef08644..eafb9961b9a 100644 --- a/voidcrew/modules/trade/shop_catalog_suit_vendor.dm +++ b/voidcrew/modules/trade/shop_catalog_suit_vendor.dm @@ -198,16 +198,8 @@ /datum/shop_buyback/fitter/salvage_spacesuit, /datum/shop_buyback/fitter/salvage_space_helmet, ) - // A suit shop eats refined metal and very little else - mission_requests = list( - list("type" = /obj/item/stack/sheet/mineral/titanium, "name" = "titanium sheets", "amount" = 10, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = /obj/item/stack/sheet/mineral/plasma, "name" = "plasma sheets", "amount" = 15, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = /obj/item/stack/sheet/mineral/silver, "name" = "silver sheets", "amount" = 8, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = /obj/item/stack/sheet/mineral/gold, "name" = "gold sheets", "amount" = 6, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = /obj/item/stack/sheet/mineral/uranium, "name" = "uranium sheets", "amount" = 6, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = /obj/item/stack/sheet/plasteel, "name" = "plasteel sheets", "amount" = 14, "difficulty" = MISSION_DIFFICULTY_HARD), - list("type" = /obj/item/stack/ore/bluespace_crystal, "name" = "bluespace crystals", "amount" = 4, "difficulty" = MISSION_DIFFICULTY_HARD), - ) + // Salvage requests await quantities and difficulties from the reward design. + mission_requests = list() // Never on a shelf: two chassis Nakamura doesn't retail, and the two // anomaly modules that come with their core already seated exclusive_rewards = list( diff --git a/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm b/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm index 9f0881b9cd1..23e91ed0af6 100644 --- a/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm +++ b/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm @@ -56,6 +56,8 @@ continue if(!ispath(request["type"], /atom/movable)) TEST_FAIL("[shop_type] requests [request["type"]], which is not a spawnable movable") + if(!is_outpost_procurement_type(request["type"])) + TEST_FAIL("[shop_type] requests unsupported procurement goods [request["type"]]") if((request["amount"] || 0) < 1) TEST_FAIL("[shop_type] requests [request["amount"]] of [request["type"]]") // A stack ask is settled off ONE stack (deliver/can_turn_in), so an @@ -67,7 +69,204 @@ var/ceiling = initial(asked.max_amount) if(request["amount"] > ceiling) TEST_FAIL("[shop_type] requests [request["amount"]] of [request["type"]], but that stack caps at [ceiling] - the contract can never be turned in") + TEST_ASSERT_EQUAL(length(shop.get_procurement_requests()), length(shop.mission_requests), "[shop_type] has procurement rows that fail eligibility") qdel(shop) TEST_ASSERT(shops_checked >= 5, "only [shops_checked] shops with a category list were checked") TEST_ASSERT(skus_checked >= 100, "only [skus_checked] SKUs were checked. The catalog walk is not seeing the shelves") + +/// Existing field-good quantities and difficulties, including owner exceptions. +/datum/unit_test/voidcrew_procurement_catalog/Run() + // Difficulty literals are EASY/MEDIUM/HARD (1/2/3); fork defines compile later. + var/list/expected_catalogs = list( + /datum/outpost_shop/general = list( + list(/obj/item/fish, 1, 1), + list(/obj/item/stack/sheet/animalhide/bear, 1, 2), + list(/obj/item/stack/spice_pods, 6, 2), + list(/obj/item/sea_crystal, 1, 3), + ), + /datum/outpost_shop/black_market = list( + list(/obj/item/stack/telecrystal_raw, 10, 3), + list(/obj/item/organ/monster_core/regenerative_core/legion, 1, 3), + ), + /datum/outpost_shop/outfitter = list( + list(/obj/item/stack/sheet/animalhide/goliath_hide, 4, 3), + list(/obj/item/stack/sheet/sinew, 4, 2), + list(/obj/item/stack/glacial_core, 5, 2), + ), + ) + for(var/shop_type in expected_catalogs) + var/datum/outpost_shop/shop = allocate(shop_type) + var/list/expected_requests = expected_catalogs[shop_type] + TEST_ASSERT_EQUAL(length(shop.mission_requests), length(expected_requests), "[shop_type] has unexpected procurement rows") + for(var/list/expected as anything in expected_requests) + var/list/found + for(var/list/request as anything in shop.mission_requests) + if(request["type"] == expected[1]) + found = request + break + TEST_ASSERT_NOTNULL(found, "[shop_type] lost its [expected[1]] request") + TEST_ASSERT_EQUAL(found["amount"], expected[2], "[shop_type] changed its [expected[1]] quantity") + TEST_ASSERT_EQUAL(found["difficulty"], expected[3], "[shop_type] changed its [expected[1]] difficulty") + if(istype(shop, /datum/outpost_shop/general)) + TEST_ASSERT(shop.extra_offer_mix[/datum/mission/outpost_supply/angler] > 0, "The owner's angler exception must remain available") + TEST_ASSERT(shop.extra_offer_mix[/datum/mission/outpost_supply/cook] > 0, "The owner's Kitchen Orders must remain available") + + var/datum/outpost_shop/vendor/suit_fitter/fitter = allocate(/datum/outpost_shop/vendor/suit_fitter) + TEST_ASSERT_EQUAL(length(fitter.mission_requests), 0, "New suit salvage requests need reward-design inputs before activation") + var/datum/mission/delivery/delivery = allocate(/datum/mission/delivery) + TEST_ASSERT_EQUAL(delivery.weight, 0, "Ore-only ship deliveries must not roll") + TEST_ASSERT(delivery.generation_failed, "Explicit generation must also refuse suspended ship deliveries") + TEST_ASSERT_EQUAL(length(delivery.objectives), 0, "Suspended deliveries must not build an ore objective") + +/// Unsupported and malformed rows never enter the ordinary supply pool. +/datum/unit_test/voidcrew_procurement_filter/Run() + var/datum/outpost_shop/general/shop = allocate(/datum/outpost_shop/general) + var/list/valid = list("type" = /obj/item/stack/telecrystal_raw, "name" = "raw telecrystal", "amount" = 10, "difficulty" = 3) + shop.mission_requests = list( + "malformed", + list("type" = /obj/item/stack/ore/iron, "name" = "iron", "amount" = 10, "difficulty" = 1), + list("type" = /obj/item/stack/sheet/plasteel, "name" = "plasteel", "amount" = 10, "difficulty" = 2), + list("type" = /obj/item/stack/cable_coil, "name" = "cable", "amount" = 30, "difficulty" = 1), + list("type" = /obj/item/mod/control, "name" = "control", "amount" = 1, "difficulty" = 1), + list("type" = /obj/item/mod/module, "name" = "module", "amount" = 1, "difficulty" = 1), + list("type" = /obj/item/mod/module/storage, "name" = "module", "amount" = 1, "difficulty" = 1), + list("type" = /obj/item/stack/telecrystal_raw, "name" = "raw telecrystal", "amount" = 0, "difficulty" = 3), + list("type" = /obj/item/stack/telecrystal_raw, "name" = "raw telecrystal", "amount" = 31, "difficulty" = 3), + list("type" = /obj/item/stack/telecrystal_raw, "name" = "raw telecrystal", "amount" = 1.5, "difficulty" = 3), + list("type" = /obj/item/stack/telecrystal_raw, "name" = "raw telecrystal", "amount" = 10), + ) + var/datum/mission/outpost_supply/rejected = allocate(/datum/mission/outpost_supply, shop) + TEST_ASSERT(rejected.generation_failed, "An unsupported-only request pool must fail generation") + shop.mission_requests += list(valid) + var/list/filtered = shop.get_procurement_requests() + TEST_ASSERT_EQUAL(length(filtered), 1, "Unsupported rows survived the eligibility filter") + TEST_ASSERT_EQUAL(filtered[1], valid, "The filter must retain the original compliant request") + var/datum/mission/outpost_supply/accepted = allocate(/datum/mission/outpost_supply, shop) + TEST_ASSERT(!accepted.generation_failed, "A compliant request must still generate") + TEST_ASSERT_EQUAL(accepted.required_type, valid["type"], "Generation chose an unsupported request") + TEST_ASSERT_EQUAL(accepted.required_amount, 10, "Generation changed a compliant quantity") + TEST_ASSERT_EQUAL(accepted.difficulty, 3, "Generation changed a compliant difficulty") + TEST_ASSERT(istype(accepted.objectives[1], /datum/mission_objective/deliver/procurement), "Ordinary supply requests must use procurement validation") + +/// Empty and unsupported-only pools must let other offers fill the board. +/datum/unit_test/voidcrew_procurement_empty_board/Run() + var/obj/structure/overmap/trader_outpost/outpost = allocate(/obj/structure/overmap/trader_outpost) + // Kitchen Orders need no overmap target, making this a deterministic board. + outpost.shop.extra_offer_mix = list( + /datum/mission/recovery/kill/outpost = 0, + /datum/mission/recovery/outpost = 0, + /datum/mission/outpost_courier = 0, + /datum/mission/outpost_supply/cook = 1, + ) + var/list/pools = list( + list(), + list(list("type" = /obj/item/stack/ore/iron, "name" = "iron", "amount" = 10, "difficulty" = 1)), + list(list("type" = /obj/item/stack/glacial_core, "name" = "glacial cores", "amount" = 5, "difficulty" = 2)), + ) + for(var/list/pool as anything in pools) + QDEL_LIST(outpost.shop_offers) + outpost.shop.mission_requests = pool + outpost.ensure_shop_offers() + // OUTPOST_SHOP_OFFER_COUNT = 4, defined after this test's include. + TEST_ASSERT_EQUAL(length(outpost.shop_offers), 4, "Supply eligibility stalled the outpost board") + TEST_ASSERT_EQUAL(outpost.has_posted_offer_type(/datum/mission/outpost_supply), length(pool) && is_outpost_procurement_type(pool[1]["type"]), "Only eligible pools should force a plain supply request") + +/// Exact loot-module eligibility must not silently expand with printable designs. +/datum/unit_test/voidcrew_procurement_module_sources/Run() + var/list/loot_modules = list(/obj/item/mod/module/springlock, /obj/item/mod/module/visor/rave, /obj/item/mod/module/balloon, /obj/item/mod/module/stamp) + var/obj/effect/spawner/random/mod/maint/spawner_type = /obj/effect/spawner/random/mod/maint + var/list/loot = initial(spawner_type.loot) + for(var/module_type in loot_modules) + TEST_ASSERT(module_type in loot, "Eligible [module_type] lost its loot source") + TEST_ASSERT(is_outpost_procurement_type(module_type), "The loot module [module_type] must be supported") + for(var/datum/design/design_type as anything in subtypesof(/datum/design)) + TEST_ASSERT(!(initial(design_type.build_path) in loot_modules), "[design_type] can print eligible loot module [initial(design_type.build_path)]") + for(var/datum/crafting_recipe/recipe_type as anything in subtypesof(/datum/crafting_recipe)) + TEST_ASSERT(!(initial(recipe_type.result) in loot_modules), "[recipe_type] can craft an eligible loot module") + +/// Procurement rejects forged submissions and consumes only eligible goods. +/datum/unit_test/voidcrew_procurement_turn_in/Run() + var/list/unsupported_types = list( + /obj/item/stack/ore/iron, + /obj/item/stack/sheet/plasteel, + /obj/item/stack/cable_coil, + /obj/item/mod/control, + /obj/item/mod/module, + /obj/item/mod/module/storage, + /obj/item/mod/module/visor/meson, + /obj/item/mod/module/balloon/advanced, + ) + for(var/item_type in unsupported_types) + var/datum/mission/mission = allocate(/datum/mission) + mission.requires_item = TRUE + var/datum/mission_objective/deliver/procurement/ask = new + ask.required_type = item_type + mission.add_objective(ask) + var/obj/item/item = allocate(item_type) + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left, item), "A forged [item_type] turn-in must fail") + TEST_ASSERT_EQUAL(ask.accept_item(item, run_loc_floor_bottom_left), 0, "Direct acceptance must refuse unsupported [item_type]") // MISSION_ITEM_REFUSED + TEST_ASSERT(!QDELETED(item), "Refusing [item_type] must not consume it") + + var/datum/mission/control_mission = allocate(/datum/mission) + control_mission.requires_item = TRUE + var/datum/mission_objective/deliver/procurement/control_ask = new + control_ask.required_type = /obj/item/mod/control/pre_equipped + control_mission.add_objective(control_ask) + var/obj/item/mod/control/manufactured = allocate(/obj/item/mod/control) + TEST_ASSERT(!control_mission.turn_in(run_loc_floor_bottom_left, manufactured), "An assembled base control cannot satisfy a salvaged-control ask") + var/obj/item/mod/control/pre_equipped/salvaged = allocate(/obj/item/mod/control/pre_equipped/standard) + var/mob/living/carbon/human/wearer = allocate(/mob/living/carbon/human/consistent) + TEST_ASSERT(wearer.equip_to_slot_if_possible(salvaged, ITEM_SLOT_BACK), "The control fixture must be worn") + TEST_ASSERT(!control_mission.turn_in(run_loc_floor_bottom_left, salvaged), "A worn salvaged control must be refused") + TEST_ASSERT_EQUAL(control_ask.accept_item(salvaged, run_loc_floor_bottom_left), 0, "Direct acceptance must also refuse a worn control") + TEST_ASSERT(!QDELETED(salvaged), "A refused worn suit must survive") + TEST_ASSERT(wearer.dropItemToGround(salvaged), "The salvaged control must be removable") + TEST_ASSERT(control_mission.turn_in(run_loc_floor_bottom_left, salvaged), "An unworn pre-equipped control must be accepted") + TEST_ASSERT(QDELETED(salvaged), "The accepted control must be consumed") + + var/datum/mission_objective/deliver/procurement/exact_module = allocate(/datum/mission_objective/deliver/procurement) + exact_module.required_type = /obj/item/mod/module/balloon + var/obj/item/mod/module/balloon/advanced/descendant = allocate(/obj/item/mod/module/balloon/advanced) + TEST_ASSERT(!exact_module.can_turn_in(descendant), "A loot-module ask must reject a different descendant type") + TEST_ASSERT_EQUAL(exact_module.accept_item(descendant, run_loc_floor_bottom_left), 0, "Direct acceptance must preserve exact module matching") + TEST_ASSERT(!QDELETED(descendant), "A refused module must survive") + + var/list/loose_types = list(/obj/item/sea_crystal, /obj/item/organ/monster_core/regenerative_core/legion, /obj/item/mod/construction/broken_core, /obj/item/mod/module/springlock, /obj/item/mod/module/visor/rave, /obj/item/mod/module/balloon, /obj/item/mod/module/stamp) + for(var/item_type in loose_types) + var/datum/mission/mission = allocate(/datum/mission) + mission.requires_item = TRUE + var/datum/mission_objective/deliver/procurement/ask = new + ask.required_type = item_type + ask.required_amount = 2 + mission.add_objective(ask) + var/obj/item/first = allocate(item_type) + var/obj/item/second = allocate(item_type) + mission.register_quest_atom(first) + TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left, first), "The first [item_type] must count as progress") + TEST_ASSERT(QDELETED(first), "The first loose item must be consumed") + TEST_ASSERT_NULL(mission.quest_atom, "Consumption must forget the quest atom before deletion") + TEST_ASSERT(!mission.failed, "Consuming a tracked item must not void the mission") + TEST_ASSERT_EQUAL(ask.delivered_count, 1, "Loose deliveries must count one item per hand-over") + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left, first), "A consumed item cannot be submitted twice") + TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left, second), "The second [item_type] must finish the request") + TEST_ASSERT(QDELETED(second), "The second loose item must be consumed") + TEST_ASSERT(QDELETED(mission), "The counted request must finish") + + var/list/stack_cases = list(list(/obj/item/stack/telecrystal_raw, 10), list(/obj/item/stack/glacial_core, 5), list(/obj/item/stack/spice_pods, 6)) + for(var/list/stack_case as anything in stack_cases) + var/datum/mission/mission = allocate(/datum/mission) + mission.requires_item = TRUE + var/datum/mission_objective/deliver/procurement/ask = new + ask.required_type = stack_case[1] + ask.required_amount = stack_case[2] + mission.add_objective(ask) + var/obj/item/stack/short_stack = allocate(stack_case[1], run_loc_floor_bottom_left, ask.required_amount - 1, FALSE) + var/obj/item/stack/full_stack = allocate(stack_case[1], run_loc_floor_bottom_left, ask.required_amount + 2, FALSE) + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left, short_stack), "A short eligible stack must be refused") + TEST_ASSERT_EQUAL(ask.accept_item(short_stack, run_loc_floor_bottom_left), 0, "Direct acceptance must also check stack quantities") + TEST_ASSERT_EQUAL(short_stack.amount, stack_case[2] - 1, "A refused stack must remain untouched") + mission.register_quest_atom(full_stack) + TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left, full_stack), "A full eligible stack must be accepted") + TEST_ASSERT_EQUAL(full_stack.amount, 2, "Only the configured stack quantity must be consumed") + TEST_ASSERT(QDELETED(mission), "A full stack must finish the request") From 57676197e556167f55d8c935e23eb646abcb604d Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:09:17 -0700 Subject: [PATCH 023/105] Rebuild revive fixes and explicit attribution --- code/game/objects/items/defib.dm | 38 +- code/modules/admin/topic.dm | 2 +- code/modules/admin/verbs/debug.dm | 2 +- code/modules/admin/verbs/secrets.dm | 2 +- .../monster_organs/regenerative_core.dm | 2 +- code/modules/mob/living/living.dm | 2 +- .../reagents/cat2_medicine_reagents.dm | 2 +- .../internal/cyberimp/augments_chest.dm | 151 +++++-- code/modules/surgery/revival.dm | 2 +- voidcrew/modules/lich/lich_loot.dm | 3 +- voidcrew/modules/loot/uniques/medical.dm | 4 +- voidcrew/modules/loot/uniques/research.dm | 2 +- voidcrew/modules/metrics/combat_metrics.dm | 88 ++-- .../modules/nanites/code/programs/healing.dm | 79 +++- .../unit_tests/voidcrew_combat_metrics.dm | 425 +++++++++++++++++- 15 files changed, 656 insertions(+), 148 deletions(-) diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index b68b11d9f63..8da48f4be31 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -619,28 +619,15 @@ user.visible_message(span_warning("[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - [fail_reason]")) playsound(src, 'sound/machines/defib/defib_failed.ogg', 50, FALSE) else - var/total_brute = H.getBruteLoss() - var/total_burn = H.getFireLoss() - - var/need_mob_update = FALSE - //If the body has been fixed so that they would not be in crit when defibbed, give them oxyloss to put them back into crit - if (H.health > HALFWAYCRITDEATH) - need_mob_update += H.adjustOxyLoss(H.health - HALFWAYCRITDEATH, updating_health = FALSE) - else - var/overall_damage = total_brute + total_burn + H.getToxLoss() + H.getOxyLoss() - var/mobhealth = H.health - need_mob_update += H.adjustOxyLoss((mobhealth - HALFWAYCRITDEATH) * (H.getOxyLoss() / overall_damage), updating_health = FALSE) - need_mob_update += H.adjustToxLoss((mobhealth - HALFWAYCRITDEATH) * (H.getToxLoss() / overall_damage), updating_health = FALSE, forced = TRUE) // force tox heal for toxin lovers too - need_mob_update += H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), updating_health = FALSE) - need_mob_update += H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), updating_health = FALSE) - if(need_mob_update) - H.updatehealth() // Previous "adjust" procs don't update health, so we do it manually. + // VOIDCREW EDIT ADDITION START: shared defib healing and explicit combat metrics attribution. + if(!revive_patient(H, defib_result)) + playsound(src, 'sound/machines/defib/defib_failed.ogg', 50, FALSE) + do_success() // The shock still consumes a charge and recharges the paddles. + return + // VOIDCREW EDIT ADDITION END user.visible_message(span_notice("[req_defib ? "[defib]" : "[src]"] pings: Resuscitation successful.")) playsound(src, 'sound/machines/defib/defib_success.ogg', 50, FALSE) - H.set_heartattack(FALSE) - if(defib_result == DEFIB_POSSIBLE) - H.grab_ghost() - H.revive() + // VOIDCREW EDIT: revival happens in revive_patient(), before any success effects. H.emote("gasp") H.set_jitter_if_lower(200 SECONDS) SEND_SIGNAL(H, COMSIG_LIVING_MINOR_SHOCK) @@ -672,6 +659,17 @@ playsound(src, 'sound/machines/defib/defib_failed.ogg', 50, FALSE) do_cancel() +// VOIDCREW EDIT ADDITION START: shared defib healing and explicit combat metrics attribution. +/obj/item/shockpaddles/proc/revive_patient(mob/living/carbon/patient, defib_result) + if(defib_result != DEFIB_POSSIBLE && defib_result != DEFIB_NOGRAB_AGHOST) + return FALSE + patient.heal_for_defib() + patient.set_heartattack(FALSE) + if(defib_result == DEFIB_POSSIBLE) + patient.grab_ghost() + return patient.revive_from("defibrillator") +// VOIDCREW EDIT ADDITION END + /obj/item/shockpaddles/proc/is_wielded() return HAS_TRAIT(src, TRAIT_WIELDED) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index d619e7712e4..3d2b5093f30 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -585,7 +585,7 @@ to_chat(usr, "This can only be used on instances of type /mob/living.", confidential = TRUE) return - L.revive(ADMIN_HEAL_ALL) + L.revive_from("admin", ADMIN_HEAL_ALL) // VOIDCREW EDIT: explicit combat metrics attribution. message_admins(span_danger("Admin [key_name_admin(usr)] healed / revived [key_name_admin(L)]!")) log_admin("[key_name(usr)] healed / Revived [key_name(L)].") diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index c0abfcd88cc..9a504e9b8a6 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -459,7 +459,7 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(cmd_admin_rejuvenate, R_ADMIN, "Rejuvenate", mob/li if(!istype(M)) tgui_alert(user,"Cannot revive a ghost") return - M.revive(ADMIN_HEAL_ALL) + M.revive_from("admin", ADMIN_HEAL_ALL) // VOIDCREW EDIT: explicit combat metrics attribution. log_admin("[key_name(user)] healed / revived [key_name(M)]") var/msg = span_danger("Admin [key_name_admin(user)] healed / revived [ADMIN_LOOKUPFLW(M)]!") diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm index f9c9bdc50f6..2a7733515d8 100644 --- a/code/modules/admin/verbs/secrets.dm +++ b/code/modules/admin/verbs/secrets.dm @@ -684,7 +684,7 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w ghost.reenter_corpse() for(var/mob/living/player in GLOB.player_list) - player.revive(ADMIN_HEAL_ALL, force_grab_ghost = TRUE) + player.revive_from("admin", ADMIN_HEAL_ALL, force_grab_ghost = TRUE) // VOIDCREW EDIT: explicit combat metrics attribution. sound_to_playing_players('sound/effects/pray_chaplain.ogg') message_admins("[key_name_admin(holder)] healed everyone.") diff --git a/code/modules/mining/equipment/monster_organs/regenerative_core.dm b/code/modules/mining/equipment/monster_organs/regenerative_core.dm index bcec0eb6c4e..528764f1e40 100644 --- a/code/modules/mining/equipment/monster_organs/regenerative_core.dm +++ b/code/modules/mining/equipment/monster_organs/regenerative_core.dm @@ -31,7 +31,7 @@ trigger_organ_action(TRIGGER_FORCE_AVAILABLE) /obj/item/organ/monster_core/regenerative_core/on_triggered_internal() - owner.revive(HEAL_ALL & ~HEAL_REFRESH_ORGANS) + owner.revive_from("legion_core", HEAL_ALL & ~HEAL_REFRESH_ORGANS) // VOIDCREW EDIT: explicit combat metrics attribution. qdel(src) /// Log applications and apply moodlet. diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 9bb4e2da159..4778809a828 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1022,7 +1022,7 @@ setFireLoss(round(fire_loss - fire_healing, DAMAGE_PRECISION), updating_health=TRUE, forced=TRUE) healing_amount = max(0, healing_amount - fire_healing) - revive(NONE, excess_healing=max(healing_amount, 0), force_grab_ghost=FALSE) // and any excess healing is passed along + revive_from("strange_reagent", NONE, excess_healing=max(healing_amount, 0), force_grab_ghost=FALSE) // VOIDCREW EDIT: explicit combat metrics attribution; pass excess healing along. /// Checks if we are actually able to ressuscitate this mob. /// (We don't want to revive then to have them instantly die again) diff --git a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm index 3099051c106..caeafc53bcd 100644 --- a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm @@ -76,7 +76,7 @@ if(3) //VICTORY ROYALE to_chat(affected_mob, span_hierophant("You win, and the malevolent spirits fade away as well as your wounds.")) affected_mob.client.give_award(/datum/award/achievement/jobs/helbitaljanken, affected_mob) - affected_mob.revive(HEAL_ALL & ~HEAL_REFRESH_ORGANS) + affected_mob.revive_from("reagent", HEAL_ALL & ~HEAL_REFRESH_ORGANS) // VOIDCREW EDIT: explicit combat metrics attribution. holder.del_reagent(type) return diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm index c5dedb71fab..2966d6d6219 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm @@ -42,15 +42,24 @@ hunger_threshold = NUTRITION_LEVEL_HUNGRY poison_amount = 10 +// VOIDCREW EDIT ADDITION START: scoped reviver activation and cooldown (combat metrics). /obj/item/organ/cyberimp/chest/reviver name = "reviver implant" - desc = "This implant will attempt to revive and heal you if you lose consciousness. For the faint of heart!" + desc = "A small implant with a faint, steady buzz." icon_state = "reviver_implant" aug_overlay = "reviver" emissive_overlay = TRUE slot = ORGAN_SLOT_HEART_AID var/revive_cost = 0 + /// Removing an active implant must not erase healing it has already paid for. + var/resume_healing_cost = FALSE var/reviving = FALSE + /// Invalidates callbacks when an activation ends, including removal and reinsertion. + var/activation_generation = 0 + var/implantation_generation = 0 + var/heal_generation = 0 + var/heal_timer + var/heal_due = 0 COOLDOWN_DECLARE(reviver_cooldown) COOLDOWN_DECLARE(defib_cooldown) @@ -63,71 +72,131 @@ try_heal() /obj/item/organ/cyberimp/chest/reviver/proc/try_heal() + if(QDELETED(src) || QDELETED(owner)) + return if(reviving) if(owner.stat == CONSCIOUS) - COOLDOWN_START(src, reviver_cooldown, revive_cost) - reviving = FALSE - to_chat(owner, span_notice("Your reviver implant shuts down and starts recharging. It will be ready again in [DisplayTimeText(revive_cost)].")) - else - addtimer(CALLBACK(src, PROC_REF(heal)), 3 SECONDS) + reviver_cooldown = reviver_time() + revive_cost + cancel_activation() + to_chat(owner, span_notice("Your reviver implant falls silent.")) + else if(!heal_timer) + queue_heal(3 SECONDS) return - if(!COOLDOWN_FINISHED(src, reviver_cooldown) || HAS_TRAIT(owner, TRAIT_SUICIDED)) + if(reviver_time() < reviver_cooldown || HAS_TRAIT(owner, TRAIT_SUICIDED)) return if(owner.stat != CONSCIOUS) - revive_cost = 0 + if(!resume_healing_cost) + revive_cost = 0 + resume_healing_cost = FALSE reviving = TRUE + activation_generation++ to_chat(owner, span_notice("You feel a faint buzzing as your reviver implant starts patching your wounds...")) - COOLDOWN_START(src, defib_cooldown, 8 SECONDS) // 5 seconds after heal proc delay + defib_cooldown = reviver_time() + 8 SECONDS // 5 seconds after heal proc delay + +/// Overridden by the clock-controlled regression scenario. +/obj/item/organ/cyberimp/chest/reviver/proc/reviver_time() + return world.time + +/obj/item/organ/cyberimp/chest/reviver/proc/queue_heal(delay) + if(heal_timer || !reviving || QDELETED(src) || QDELETED(owner)) + return + heal_generation++ + heal_due = reviver_time() + delay + heal_timer = addtimer(CALLBACK(src, PROC_REF(heal), WEAKREF(owner), activation_generation, heal_generation), delay, TIMER_STOPPABLE | TIMER_DELETE_ME) + +/obj/item/organ/cyberimp/chest/reviver/proc/cancel_activation() + activation_generation++ + reviving = FALSE + heal_due = 0 + if(heal_timer) + deltimer(heal_timer) + heal_timer = null + +/obj/item/organ/cyberimp/chest/reviver/on_mob_remove(mob/living/carbon/organ_owner, special = FALSE, movement_flags) + implantation_generation++ + if(reviving) + resume_healing_cost = TRUE + cancel_activation() + return ..() +/obj/item/organ/cyberimp/chest/reviver/Destroy() + cancel_activation() + return ..() -/obj/item/organ/cyberimp/chest/reviver/proc/heal() - if(COOLDOWN_FINISHED(src, defib_cooldown)) - revive_dead() +/obj/item/organ/cyberimp/chest/reviver/proc/heal(datum/weakref/intended_owner, generation, callback_generation) + if(QDELETED(src) || QDELETED(owner) || !reviving || generation != activation_generation || callback_generation != heal_generation || intended_owner?.resolve() != owner || !heal_timer) + return + var/mob/living/carbon/patient = owner + deltimer(heal_timer) + heal_timer = null + heal_due = 0 + if(owner.stat == CONSCIOUS) + try_heal() + return /// boolean that stands for if PHYSICAL damage being patched var/body_damage_patched = FALSE var/need_mob_update = FALSE - if(owner.getOxyLoss()) - need_mob_update += owner.adjustOxyLoss(-5, updating_health = FALSE) + if(patient.getOxyLoss()) + need_mob_update += patient.adjustOxyLoss(-5, updating_health = FALSE) revive_cost += 5 - if(owner.getBruteLoss()) - need_mob_update += owner.adjustBruteLoss(-2, updating_health = FALSE) + if(patient.getBruteLoss()) + need_mob_update += patient.adjustBruteLoss(-2, updating_health = FALSE) revive_cost += 40 body_damage_patched = TRUE - if(owner.getFireLoss()) - need_mob_update += owner.adjustFireLoss(-2, updating_health = FALSE) + if(patient.getFireLoss()) + need_mob_update += patient.adjustFireLoss(-2, updating_health = FALSE) revive_cost += 40 body_damage_patched = TRUE - if(owner.getToxLoss()) - need_mob_update += owner.adjustToxLoss(-1, updating_health = FALSE) + if(patient.getToxLoss()) + need_mob_update += patient.adjustToxLoss(-1, updating_health = FALSE) revive_cost += 40 if(need_mob_update) - owner.updatehealth() + patient.updatehealth() + if(QDELETED(src) || QDELETED(patient) || owner != patient || generation != activation_generation || !reviving) + return if(body_damage_patched && prob(35)) // healing is called every few seconds, not every tick - owner.visible_message(span_warning("[owner]'s body twitches a bit."), span_notice("You feel like something is patching your injured body.")) + patient.visible_message(span_warning("[patient]'s body twitches a bit."), span_notice("You feel like something is patching your injured body.")) + revive_dead() + // Previously each mob tick queued a delayed heal. Preserve that cadence without overlap. + if(!QDELETED(src) && !QDELETED(patient) && owner == patient && generation == activation_generation && reviving) + queue_heal(SSmobs.wait) /obj/item/organ/cyberimp/chest/reviver/proc/revive_dead() - if(!COOLDOWN_FINISHED(src, defib_cooldown) || owner.stat != DEAD || owner.can_defib() != DEFIB_POSSIBLE) - return - owner.notify_revival("You are being revived by [src]!") - revive_cost += 10 MINUTES // Additional 10 minutes cooldown after revival. - owner.grab_ghost() + if(QDELETED(src) || QDELETED(owner) || !reviving || reviver_time() < defib_cooldown || owner.stat != DEAD || owner.health <= owner.hardcrit_threshold || owner.can_defib() != DEFIB_POSSIBLE) + return FALSE + var/mob/living/carbon/patient = owner + var/healing_cost = revive_cost + var/generation = activation_generation + patient.notify_revival("You are being revived by [src]!") + patient.grab_ghost() + if(QDELETED(src) || QDELETED(patient) || owner != patient || generation != activation_generation || !reviving) + return FALSE defib_cooldown += 16 SECONDS // delay so it doesn't spam - owner.visible_message(span_warning("[owner]'s body convulses a bit.")) - playsound(owner, SFX_BODYFALL, 50, TRUE) - playsound(owner, 'sound/machines/defib/defib_zap.ogg', 75, TRUE, -1) - owner.set_heartattack(FALSE) - owner.revive() - owner.emote("gasp") - owner.set_jitter_if_lower(200 SECONDS) - SEND_SIGNAL(owner, COMSIG_LIVING_MINOR_SHOCK) - log_game("[owner] been revived by [src]") + patient.set_heartattack(FALSE) + if(!patient.revive_from("reviver_implant")) + return FALSE + if(QDELETED(src)) + return TRUE + revive_cost = healing_cost + 10 MINUTES + reviver_cooldown = reviver_time() + revive_cost + cancel_activation() + if(!QDELETED(patient)) + patient.visible_message(span_warning("[patient]'s body convulses a bit.")) + playsound(patient, SFX_BODYFALL, 50, TRUE) + playsound(patient, 'sound/machines/defib/defib_zap.ogg', 75, TRUE, -1) + patient.emote("gasp") + patient.set_jitter_if_lower(200 SECONDS) + SEND_SIGNAL(patient, COMSIG_LIVING_MINOR_SHOCK) + log_game("[patient] been revived by [src]") + return TRUE +// VOIDCREW EDIT ADDITION END /obj/item/organ/cyberimp/chest/reviver/emp_act(severity) @@ -145,12 +214,14 @@ if(human_owner.stat != DEAD && prob(50 / severity) && human_owner.can_heartattack()) human_owner.set_heartattack(TRUE) to_chat(human_owner, span_userdanger("You feel a horrible agony in your chest!")) - addtimer(CALLBACK(src, PROC_REF(undo_heart_attack)), 600 / severity) + addtimer(CALLBACK(src, PROC_REF(undo_heart_attack), WEAKREF(human_owner), implantation_generation), 600 / severity) // VOIDCREW EDIT: keep the EMP callback on its intended body. -/obj/item/organ/cyberimp/chest/reviver/proc/undo_heart_attack() - var/mob/living/carbon/human/human_owner = owner - if(!istype(human_owner)) +// VOIDCREW EDIT ADDITION START: do not apply a delayed EMP recovery to a different owner. +/obj/item/organ/cyberimp/chest/reviver/proc/undo_heart_attack(datum/weakref/intended_owner, generation) + var/mob/living/carbon/human/human_owner = intended_owner?.resolve() + if(QDELETED(src) || QDELETED(human_owner) || owner != human_owner || generation != implantation_generation) return +// VOIDCREW EDIT ADDITION END human_owner.set_heartattack(FALSE) if(human_owner.stat == CONSCIOUS) to_chat(human_owner, span_notice("You feel your heart beating again!")) diff --git a/code/modules/surgery/revival.dm b/code/modules/surgery/revival.dm index 65c8116769d..351cee78fc4 100644 --- a/code/modules/surgery/revival.dm +++ b/code/modules/surgery/revival.dm @@ -115,7 +115,7 @@ if(iscarbon(target)) var/mob/living/carbon/carbon_target = target carbon_target.set_heartattack(FALSE) - if(target.revive()) + if(target.revive_from("surgery")) // VOIDCREW EDIT: explicit combat metrics attribution. on_revived(user, target) return TRUE diff --git a/voidcrew/modules/lich/lich_loot.dm b/voidcrew/modules/lich/lich_loot.dm index 516e9ffcfc1..b099b1ff68d 100644 --- a/voidcrew/modules/lich/lich_loot.dm +++ b/voidcrew/modules/lich/lich_loot.dm @@ -671,7 +671,8 @@ GLOBAL_LIST_INIT(lich_hoard_contents, list( refuse_draught() return - var/came_back = drinker.heal_and_revive( + var/came_back = drinker.heal_and_revive_from( + "phylactery", LICH_PHYLACTERY_REVIVE_TO, span_boldwarning("[drinker] jerks upright in a wash of green light, and somewhere a jar breaks."), ) diff --git a/voidcrew/modules/loot/uniques/medical.dm b/voidcrew/modules/loot/uniques/medical.dm index f8dfd616c5e..9623cdc8675 100644 --- a/voidcrew/modules/loot/uniques/medical.dm +++ b/voidcrew/modules/loot/uniques/medical.dm @@ -537,7 +537,7 @@ patient.updatehealth() patient.set_heartattack(FALSE) patient.grab_ghost() - patient.revive() + patient.revive_from("meridian_heart") patient.emote("gasp") patient.set_jitter_if_lower(200 SECONDS) SEND_SIGNAL(patient, COMSIG_LIVING_MINOR_SHOCK) @@ -729,7 +729,7 @@ target.grab_ghost(force = TRUE) target.fully_heal(HEAL_ALL) // also cures husk, unconditionally - see /mob/living/proc/fully_heal - target.revive(force_grab_ghost = TRUE) + target.revive_from("lazarus_line", force_grab_ghost = TRUE) if(target.stat == DEAD) to_chat(user, span_warning("[target] convulses, then lies still. It didn't take.")) return FALSE diff --git a/voidcrew/modules/loot/uniques/research.dm b/voidcrew/modules/loot/uniques/research.dm index bff0bf2ee50..44a9a7ec5d7 100644 --- a/voidcrew/modules/loot/uniques/research.dm +++ b/voidcrew/modules/loot/uniques/research.dm @@ -640,7 +640,7 @@ user.setOxyLoss(snap["oxy"]) user.setStaminaLoss(snap["stamina"]) if(user.stat == DEAD) - user.revive(NONE) + user.revive_from("temporal_rewind", NONE) user.visible_message(span_warning("[user]'s wrist brace flares and cracks in half, and suddenly [user.p_theyre()] standing somewhere else!"), \ span_userdanger("The last ten seconds unwind. You're back where you were, and the splint is scrap.")) diff --git a/voidcrew/modules/metrics/combat_metrics.dm b/voidcrew/modules/metrics/combat_metrics.dm index 23c544ae907..724781e299d 100644 --- a/voidcrew/modules/metrics/combat_metrics.dm +++ b/voidcrew/modules/metrics/combat_metrics.dm @@ -49,8 +49,8 @@ // revived A dead player's body came back to life. ckey, ship, zone, quantity = 1, // points = seconds dead, subject = method: defibrillator, // reviver_implant, nanites, legion_core, strange_reagent, surgery, -// reagent, admin, cloning_vat or other. details: via = the proc that -// called revive(), read off the call stack. +// reagent, admin, phylactery, meridian_heart, lazarus_line, +// temporal_rewind, cloning_vat or other. Methods are explicit at the call site. // revived_repeat Tallied in place of revived for revive loops, same limit as deaths. // ckey, zone, subject = method, quantity = revivals, // points = seconds dead summed. @@ -72,6 +72,9 @@ GLOBAL_DATUM_INIT(combat_metrics, /datum/combat_metrics, new) // Per-mob state. Only numbers, text and typepaths, never references, so nothing here can hold // a deleted atom. Unset vars cost no memory per mob. /mob/living + /// Scoped to synchronous revival calls; never inferred from callers. + var/metric_revival_method + var/metric_revive_was_dead = FALSE /// ckey of the player who last hit this mob. Null when the last hit came from an NPC. var/metric_hit_ckey /// Type of the mob that last hit this mob. @@ -243,45 +246,40 @@ GLOBAL_DATUM_INIT(combat_metrics, /datum/combat_metrics, new) return "toxin" return "brute" -/** - * Finds what called revive(), by walking up the call stack from a COMSIG_LIVING_REVIVE handler - * to the first proc above revive() and heal_and_revive(). Returns list(that proc's src, its name, - * its path), or null. Only runs when a dead player comes back, so the walk is cheap enough. - */ -/proc/metric_revive_site() - var/callee/frame = caller - var/seen_revive = FALSE - for(var/depth in 1 to 16) - if(isnull(frame)) - return null - var/path = "[frame.proc]" - var/proc_name = copytext(path, findlasttext(path, "/") + 1) - if(proc_name == "revive" || proc_name == "heal_and_revive") - seen_revive = TRUE - else if(seen_revive) - return list(frame.src, proc_name, path) - frame = frame.caller - return null +/// Retain the state from before revive() sends its signal, including unclassified calls. +/mob/living/revive(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE) + var/previous_was_dead = metric_revive_was_dead + metric_revive_was_dead = stat == DEAD + try + . = ..() + catch(var/exception/error) + metric_revive_was_dead = previous_was_dead + throw error + metric_revive_was_dead = previous_was_dead -/// Names the revival method from metric_revive_site()'s src and proc name. -/proc/metric_revive_method(datum/site_src, proc_name) - if(proc_name == "do_strange_reagent_revival") - return "strange_reagent" - if(istype(site_src, /obj/item/shockpaddles)) - return "defibrillator" - if(istype(site_src, /obj/item/organ/cyberimp/chest/reviver)) - return "reviver_implant" - if(istype(site_src, /datum/nanite_program)) - return "nanites" - if(istype(site_src, /obj/item/organ/monster_core/regenerative_core)) - return "legion_core" - if(istype(site_src, /datum/surgery_step)) - return "surgery" - if(istype(site_src, /datum/reagent)) - return "reagent" - if(istype(site_src, /datum/admins) || istype(site_src, /datum/admin_verb) || istype(site_src, /datum/secrets_menu)) - return "admin" - return "other" +/// Attribute only this body's synchronous revival, restoring any enclosing scope even on failure. +/mob/living/proc/revive_from(method, full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE) + var/previous_method = metric_revival_method + metric_revival_method = method + try + . = revive(full_heal_flags, excess_healing, force_grab_ghost) + catch(var/exception/error) + metric_revival_method = previous_method + throw error + metric_revival_method = previous_method + +/mob/living/proc/heal_and_revive_from(method, heal_to = 50, revive_message) + var/previous_method = metric_revival_method + metric_revival_method = method + try + if(args.len < 2) + . = heal_and_revive() // Preserve subtype defaults when the caller omitted heal_to. + else + . = heal_and_revive(heal_to, revive_message) + catch(var/exception/error) + metric_revival_method = previous_method + throw error + metric_revival_method = previous_method /// A cloning vat woke a dead player up in a fresh body. Called from /obj/machinery/cloning_vat/proc/claim(). /proc/metric_clone_revival(mob/living/clone, mob/old_body) @@ -448,7 +446,7 @@ GLOBAL_DATUM_INIT(combat_metrics, /datum/combat_metrics, new) /// Registered on a dead player's body. revive() sends this for every heal, dead or not. /datum/combat_metrics/proc/on_revive(mob/living/source, full_heal_flags) SIGNAL_HANDLER - if(source.stat == DEAD) + if(source.stat == DEAD || !source.metric_revive_was_dead) return UnregisterSignal(source, COMSIG_LIVING_REVIVE) // A new life starts without the old killer. @@ -462,18 +460,16 @@ GLOBAL_DATUM_INIT(combat_metrics, /datum/combat_metrics, new) var/player_ckey = metric_ckey(source) if(!player_ckey) return - var/list/site = metric_revive_site() - var/method = metric_revive_method(site?[1], site?[2]) - record_revival(source, player_ckey, method, world.time - source.timeofdeath, site?[3]) + record_revival(source, player_ckey, source.metric_revival_method || "other", world.time - source.timeofdeath) /// Writes a revival, or tallies it when this body keeps coming back. -/datum/combat_metrics/proc/record_revival(mob/living/body, player_ckey, method, deciseconds_dead, via) +/datum/combat_metrics/proc/record_revival(mob/living/body, player_ckey, method, deciseconds_dead) last_death_by_ckey -= player_ckey var/seconds_dead = max(0, round(deciseconds_dead / 10)) if(over_burst_limit(body, revival = TRUE)) tally_metric(METRIC_DEATH, "revived_repeat", ckey = player_ckey, zone = metric_cached_zone(body), subject = method, points = seconds_dead) return - record_metric(METRIC_DEATH, "revived", ckey = player_ckey, subject = method, points = seconds_dead, quantity = 1, details = via ? list("via" = via) : null, actor = body) + record_metric(METRIC_DEATH, "revived", ckey = player_ckey, subject = method, points = seconds_dead, quantity = 1, actor = body) /// A player joined a crew. If they died and were never revived, that's a respawn. /datum/combat_metrics/proc/on_crewmember_joined(datum/source, mob/living/character, rank) diff --git a/voidcrew/modules/nanites/code/programs/healing.dm b/voidcrew/modules/nanites/code/programs/healing.dm index 2a7c65ea73a..9f2721f9365 100644 --- a/voidcrew/modules/nanites/code/programs/healing.dm +++ b/voidcrew/modules/nanites/code/programs/healing.dm @@ -209,37 +209,74 @@ /datum/nanite_program/defib name = "Defibrillation" - desc = "The nanites shock the host's heart when triggered, bringing them back to life if the body can sustain it." + desc = "The nanites deliver a pulse to the host's heart." can_trigger = TRUE trigger_cost = 25 trigger_cooldown = 120 rogue_types = list(/datum/nanite_program/shocking) /datum/nanite_program/defib/on_trigger(comm_message) - host_mob.notify_revival("Your heart is being defibrillated by nanites. Re-enter your corpse if you want to be revived!") - host_mob.grab_ghost() - addtimer(CALLBACK(src, PROC_REF(zap)), 50) + if(!check_revivable()) + return + var/mob/living/carbon/patient = host_mob + patient.notify_revival("Your heart is being defibrillated by nanites.") + if(patient.can_defib() == DEFIB_POSSIBLE) + patient.grab_ghost() + addtimer(CALLBACK(src, PROC_REF(zap), WEAKREF(patient)), 5 SECONDS) /datum/nanite_program/defib/proc/check_revivable() - if(!iscarbon(host_mob)) //nonstandard biology + if(QDELETED(src) || QDELETED(host_mob) || !iscarbon(host_mob) || host_mob.stat != DEAD) return FALSE var/mob/living/carbon/C = host_mob - if(C.get_ghost()) - return FALSE - return C.can_defib() + var/defib_result = C.can_defib() + return defib_result == DEFIB_POSSIBLE || defib_result == DEFIB_NOGRAB_AGHOST + +/datum/nanite_program/defib/proc/zap(datum/weakref/intended_host) + var/mob/living/carbon/patient = intended_host?.resolve() + if(QDELETED(patient) || host_mob != patient || !check_revivable()) + return + playsound(patient, 'sound/machines/defib/defib_charge.ogg', 50, FALSE) + sleep(3 SECONDS) + if(QDELETED(src) || QDELETED(patient) || host_mob != patient) + return + playsound(patient, 'sound/machines/defib/defib_zap.ogg', 50, FALSE) + if(!defibrillate()) + playsound(patient, 'sound/machines/defib/defib_failed.ogg', 50, FALSE) -/datum/nanite_program/defib/proc/zap() +/// Rechecked after the windup, immediately before healing and revival. +/datum/nanite_program/defib/proc/defibrillate() + if(!check_revivable()) + return FALSE var/mob/living/carbon/C = host_mob - playsound(C, 'sound/machines/defib/defib_charge.ogg', 50, FALSE) - sleep(30) - playsound(C, 'sound/machines/defib/defib_zap.ogg', 50, FALSE) - if(check_revivable()) - playsound(C, 'sound/machines/defib/defib_success.ogg', 50, FALSE) - C.set_heartattack(FALSE) - C.revive(full_heal_flags = HEAL_ADMIN) - C.emote("gasp") - C.set_timed_status_effect(10 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) - SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK) - log_game("[C] has been successfully defibrillated by nanites.") + C.heal_for_defib() + C.set_heartattack(FALSE) + if(!C.revive_from("nanites")) + return FALSE + playsound(C, 'sound/machines/defib/defib_success.ogg', 50, FALSE) + C.emote("gasp") + C.set_timed_status_effect(10 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) + SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK) + log_game("[C] has been successfully defibrillated by nanites.") + return TRUE + +/// The paddles' damage redistribution, shared with nanites. Leaves unrelated injuries alone. +/mob/living/carbon/proc/heal_for_defib() + var/target_health = -50 + var/need_mob_update = FALSE + if(health > target_health) + need_mob_update += adjustOxyLoss(health - target_health, updating_health = FALSE) else - playsound(C, 'sound/machines/defib/defib_failed.ogg', 50, FALSE) + var/total_brute = getBruteLoss() + var/total_burn = getFireLoss() + var/total_oxy = getOxyLoss() + var/total_tox = getToxLoss() + var/overall_damage = total_brute + total_burn + total_oxy + total_tox + if(overall_damage <= 0) + return + var/damage_change = health - target_health + need_mob_update += adjustOxyLoss(damage_change * (total_oxy / overall_damage), updating_health = FALSE) + need_mob_update += adjustToxLoss(damage_change * (total_tox / overall_damage), updating_health = FALSE, forced = TRUE) + need_mob_update += adjustFireLoss(damage_change * (total_burn / overall_damage), updating_health = FALSE) + need_mob_update += adjustBruteLoss(damage_change * (total_brute / overall_damage), updating_health = FALSE) + if(need_mob_update) + updatehealth() diff --git a/voidcrew/modules/unit_tests/voidcrew_combat_metrics.dm b/voidcrew/modules/unit_tests/voidcrew_combat_metrics.dm index ae7c4778432..e99eee462bb 100644 --- a/voidcrew/modules/unit_tests/voidcrew_combat_metrics.dm +++ b/voidcrew/modules/unit_tests/voidcrew_combat_metrics.dm @@ -1,10 +1,16 @@ /// Combat metrics pick real hits out of log_combat() lines, name how a hit landed and why a player -/// died, find what called revive(), and credit NPC kills to the player with the last hit. +/// died, attribute scoped revivals, and credit NPC kills to the player with the last hit. /// No database: rows stay in SSmetrics' memory. /datum/unit_test/voidcrew_combat_metrics var/was_accepting var/list/old_pending var/list/old_tallies + var/list/old_deaths + var/list/old_last_deaths + var/old_flush_scheduled + var/patient_number = 0 + var/shocks = 0 + var/nested_restored = FALSE /datum/unit_test/voidcrew_combat_metrics/Run() for(var/hit in list("attacked", "shot", "threw and hit", "punched", "kicked")) @@ -31,19 +37,18 @@ TEST_ASSERT_EQUAL(metric_death_cause(FALSE, FALSE, null, null, 190, 10, 0, 0), "brute", "mostly brute damage") TEST_ASSERT_EQUAL(metric_death_cause(FALSE, FALSE, null, null), "unknown", "no damage at all") - var/list/site = revive() - TEST_ASSERT_NOTNULL(site, "the call stack walk finds the proc that called revive()") - TEST_ASSERT_EQUAL(site[1], src, "the caller's src is read off the stack") - TEST_ASSERT_EQUAL(site[2], "Run", "the caller's proc name is read off the stack") - TEST_ASSERT_EQUAL(metric_revive_method(null, "do_strange_reagent_revival"), "strange_reagent", "strange reagent is named by its proc") - TEST_ASSERT_EQUAL(metric_revive_method(src, "Run"), "other", "unknown callers are other") - was_accepting = SSmetrics.accepting old_pending = SSmetrics.pending old_tallies = SSmetrics.tallies SSmetrics.accepting = TRUE SSmetrics.pending = list() SSmetrics.tallies = list() + old_deaths = GLOB.combat_metrics.pending_deaths + old_last_deaths = GLOB.combat_metrics.last_death_by_ckey + old_flush_scheduled = GLOB.combat_metrics.flush_scheduled + GLOB.combat_metrics.pending_deaths = list() + GLOB.combat_metrics.last_death_by_ckey = list() + GLOB.combat_metrics.flush_scheduled = FALSE var/mob/living/carbon/human/player = allocate(/mob/living/carbon/human/consistent) player.mind_initialize() @@ -80,8 +85,405 @@ TEST_ASSERT_EQUAL(kills["ckey"], "combattester", "the killer is the ckey") TEST_ASSERT_EQUAL(kills["quantity"], 2, "both kills count, including the killing blow logged after the death") -/datum/unit_test/voidcrew_combat_metrics/proc/revive() - return metric_revive_site() + check_attribution() + check_implant_clock() + check_implant_callbacks() + check_nanite_defib() + +/// Real humans and real revival code; only the implant clock is simulated. +/datum/unit_test/voidcrew_combat_metrics/proc/patient() + var/mob/living/carbon/human/consistent/voidcrew_revival_test/body = allocate(/mob/living/carbon/human/consistent/voidcrew_revival_test) + body.mind_initialize() + body.mind.key = "revivaltester[++patient_number]" + return body + +/datum/unit_test/voidcrew_combat_metrics/proc/revival_count(mob/living/body, method) + var/count = 0 + for(var/list/row as anything in SSmetrics.pending) + if(row["ckey"] == metric_ckey(body) && row["event"] == "revived" && (!method || row["subject"] == method)) + count += row["quantity"] + for(var/key in SSmetrics.tallies) + var/list/row = SSmetrics.tallies[key] + if(row["ckey"] == metric_ckey(body) && row["event"] == "revived_repeat" && (!method || row["subject"] == method)) + count += row["quantity"] + return count + +/datum/unit_test/voidcrew_combat_metrics/proc/check_attribution() + for(var/method in list("reviver_implant", "nanites", "defibrillator", "strange_reagent", "legion_core", "surgery", "reagent", "admin", "phylactery", "meridian_heart", "lazarus_line", "temporal_rewind")) + var/mob/living/body = patient() + body.death() + TEST_ASSERT(body.revive_from(method), "[method] did not revive a healthy corpse") + TEST_ASSERT_EQUAL(revival_count(body, method), 1, "[method] was not explicitly attributed") + TEST_ASSERT_NULL(body.metric_revival_method, "[method] leaked its attribution") + TEST_ASSERT(!body.metric_revive_was_dead, "[method] leaked its death context") + body.revive_from("admin", ADMIN_HEAL_ALL) + body.heal_and_revive_from("phylactery", 30) + TEST_ASSERT_EQUAL(revival_count(body), 1, "Healing a living body recorded a revival") + + var/mob/living/carbon/human/consistent/voidcrew_revival_test/body = patient() + body.setOxyLoss(250) + body.death() + TEST_ASSERT(!body.revive_from("nanites"), "An unhealed lethal corpse revived") + TEST_ASSERT_NULL(body.metric_revival_method, "A failed revival leaked attribution") + TEST_ASSERT_EQUAL(revival_count(body), 0, "A failed revival was recorded") + TEST_ASSERT(body.heal_and_revive_from("phylactery", 30), "The scoped healing route did not revive") + TEST_ASSERT_EQUAL(revival_count(body, "phylactery"), 1, "The healing route lost its method") + TEST_ASSERT_NULL(body.metric_revival_method, "The healing route leaked attribution") + + var/mob/living/unknown = patient() + unknown.death() + TEST_ASSERT(unknown.revive(), "An unclassified route failed") + TEST_ASSERT_EQUAL(revival_count(unknown, "other"), 1, "Unclassified routes must remain other") + var/mob/living/clone = patient() + metric_clone_revival(clone, unknown) + TEST_ASSERT_EQUAL(revival_count(clone, "cloning_vat"), 1, "Cloning vat attribution changed") + + // A nested heal during the outer revival signal must restore both contexts. + var/mob/living/nested = patient() + RegisterSignal(nested, COMSIG_LIVING_REVIVE, PROC_REF(nested_heal)) + nested.death() + TEST_ASSERT(nested.revive_from("surgery"), "The outer revival failed") + TEST_ASSERT(nested_restored, "A nested living heal did not restore the enclosing method") + TEST_ASSERT_EQUAL(revival_count(nested, "surgery"), 1, "The nested heal replaced the outer method") + TEST_ASSERT_EQUAL(revival_count(nested), 1, "The nested living heal was counted") + TEST_ASSERT_NULL(nested.metric_revival_method, "The nested revival leaked context") + + body.metric_revival_method = "enclosing" + body.throw_on_revive = TRUE + var/caught = FALSE + try + body.revive_from("admin") + catch(var/exception/error) + caught = !isnull(error) + TEST_ASSERT(caught, "The exception fixture did not throw") + TEST_ASSERT_EQUAL(body.metric_revival_method, "enclosing", "An exception lost the enclosing method") + body.throw_on_revive = FALSE + body.throw_on_heal = TRUE + caught = FALSE + try + body.heal_and_revive_from("phylactery", 30) + catch(var/exception/healing_error) + caught = !isnull(healing_error) + TEST_ASSERT(caught, "The healing exception fixture did not throw") + TEST_ASSERT_EQUAL(body.metric_revival_method, "enclosing", "A healing exception lost the enclosing method") + body.metric_revival_method = null + body.throw_on_heal = FALSE + +/datum/unit_test/voidcrew_combat_metrics/proc/nested_heal(mob/living/source, full_heal_flags) + SIGNAL_HANDLER + UnregisterSignal(source, COMSIG_LIVING_REVIVE) + var/outer_method = source.metric_revival_method + source.revive_from("admin") + nested_restored = source.metric_revival_method == outer_method && source.metric_revive_was_dead + +/// Reproduce eleven death/revival requests across nine simulated minutes without sleeping. +/datum/unit_test/voidcrew_combat_metrics/proc/check_implant_clock() + var/mob/living/carbon/human/consistent/voidcrew_revival_test/body = patient() + var/obj/item/organ/cyberimp/chest/reviver/voidcrew_clock_test/implant = allocate(/obj/item/organ/cyberimp/chest/reviver/voidcrew_clock_test) + implant.Insert(body) + body.setOxyLoss(250) + body.death() + var/start_time = 1 HOURS + var/list/attempt_times = list(0, 45 SECONDS, 90 SECONDS, 135 SECONDS, 180 SECONDS, 225 SECONDS, 270 SECONDS, 315 SECONDS, 360 SECONDS, 405 SECONDS, 450 SECONDS) + var/attempts = 0 + var/succeeded_at + var/cooldown_at_success + var/healing_at_success + var/reached_hardcrit = FALSE + for(var/elapsed in 0 to (9 MINUTES) step (1 SECONDS)) + implant.clock = start_time + elapsed + if(elapsed in attempt_times) + attempts++ + if(body.stat != DEAD) + body.setOxyLoss(250) + body.death() + implant.revive_dead() + implant.on_death(1, elapsed / 10) + implant.try_heal() + var/timer_before = implant.heal_timer + implant.try_heal() + TEST_ASSERT_EQUAL(implant.heal_timer, timer_before, "Overlapping processing queued a second healing timer") + if(implant.heal_timer && implant.clock >= implant.heal_due) + implant.heal(WEAKREF(body), implant.activation_generation, implant.heal_generation) + if(body.health == body.hardcrit_threshold) + reached_hardcrit = TRUE + TEST_ASSERT_EQUAL(body.stat, DEAD, "The implant revived at the hard-crit boundary") + if(body.revive_calls && isnull(succeeded_at)) + succeeded_at = implant.clock + cooldown_at_success = implant.reviver_cooldown + healing_at_success = implant.revive_cost - 10 MINUTES + TEST_ASSERT(body.stat != DEAD, "The implant's first attempt did not succeed") + TEST_ASSERT(!implant.reviving && !implant.heal_timer, "Successful revival did not end the activation") + TEST_ASSERT_EQUAL(cooldown_at_success, succeeded_at + 10 MINUTES + healing_at_success, "Cooldown did not begin at success") + if(!isnull(succeeded_at)) + if(elapsed == 60 SECONDS) + body.set_stat(CONSCIOUS) + if(elapsed == 61 SECONDS) + body.set_stat(HARD_CRIT) + implant.try_heal() + TEST_ASSERT_EQUAL(implant.reviver_cooldown, cooldown_at_success, "Consciousness or another death restarted the cooldown") + TEST_ASSERT_EQUAL(attempts, 11, "The scenario did not exercise all eleven observed requests") + TEST_ASSERT(reached_hardcrit, "The scenario never reached the exact hard-crit boundary") + TEST_ASSERT_NOTNULL(succeeded_at, "The implant never revived after healing past hard crit") + TEST_ASSERT_EQUAL(succeeded_at, start_time + 3 SECONDS + 24 * SSmobs.wait, "Single-callback scheduling changed the existing healing rate") + TEST_ASSERT_EQUAL(body.hardcrit_revive_calls, 0, "revive() was attempted at hard-crit health") + TEST_ASSERT_EQUAL(body.revive_calls, 1, "The implant attempted a second revival during cooldown") + TEST_ASSERT_EQUAL(revival_count(body, "reviver_implant"), 1, "The scenario did not produce exactly one attributed success") + TEST_ASSERT(healing_at_success > 0, "Accumulated healing was omitted from cooldown") + TEST_ASSERT(implant.clock < implant.reviver_cooldown, "The nine-minute scenario outlasted the success cooldown") + implant.Remove(body) + implant.Insert(body) + implant.try_heal() + TEST_ASSERT_EQUAL(implant.reviver_cooldown, cooldown_at_success, "Reinsertion reset the successful revival cooldown") + TEST_ASSERT(!implant.reviving && !implant.heal_timer, "Reinsertion bypassed the successful revival cooldown") + +/datum/unit_test/voidcrew_combat_metrics/proc/check_implant_callbacks() + var/mob/living/carbon/human/first = patient() + var/mob/living/carbon/human/second = patient() + first.setOxyLoss(200) + second.setOxyLoss(200) + first.death() + second.death() + var/obj/item/organ/cyberimp/chest/reviver/voidcrew_clock_test/implant = allocate(/obj/item/organ/cyberimp/chest/reviver/voidcrew_clock_test) + implant.clock = 1 HOURS + implant.Insert(first) + implant.try_heal() + implant.try_heal() + var/generation = implant.activation_generation + var/implantation = implant.implantation_generation + var/callback_generation = implant.heal_generation + var/old_timer = implant.heal_timer + for(var/index in 1 to 11) + implant.try_heal() + TEST_ASSERT_EQUAL(implant.heal_timer, old_timer, "Processing queued overlapping callbacks") + implant.Remove(first) + TEST_ASSERT(!implant.heal_timer && !implant.reviving, "Removal did not cancel the pending activation") + implant.Insert(second) + implant.try_heal() + implant.try_heal() + var/new_timer = implant.heal_timer + implant.heal(WEAKREF(first), generation, callback_generation) + TEST_ASSERT_EQUAL(first.getOxyLoss(), 200, "A removed implant healed its former owner") + TEST_ASSERT_EQUAL(second.getOxyLoss(), 200, "A stale callback healed the new owner") + TEST_ASSERT_EQUAL(implant.heal_timer, new_timer, "A stale callback consumed the new owner's timer") + second.set_heartattack(TRUE) + implant.undo_heart_attack(WEAKREF(first), implantation) + TEST_ASSERT(second.undergoing_cardiac_arrest(), "A stale EMP callback healed the new owner") + callback_generation = implant.heal_generation + implant.heal(WEAKREF(second), implant.activation_generation, implant.heal_generation) + TEST_ASSERT_EQUAL(second.getOxyLoss(), 195, "One callback did not preserve the oxygen healing rate") + TEST_ASSERT_EQUAL(implant.heal_due, implant.clock + SSmobs.wait, "A healing callback changed the existing pulse interval") + implant.try_heal() + implant.heal(WEAKREF(second), implant.activation_generation, callback_generation) + TEST_ASSERT_EQUAL(second.getOxyLoss(), 195, "Replaying an earlier callback healed twice") + generation = implant.activation_generation + callback_generation = implant.heal_generation + implantation = implant.implantation_generation + implant.Remove(second) + implant.Insert(second) + implant.try_heal() + implant.try_heal() + TEST_ASSERT_EQUAL(implant.revive_cost, 5, "Reinsertion discarded accumulated healing cost") + implant.heal(WEAKREF(second), generation, callback_generation) + TEST_ASSERT_EQUAL(second.getOxyLoss(), 195, "Reinsertion into the same body accepted a stale generation") + implant.undo_heart_attack(WEAKREF(second), implantation) + TEST_ASSERT(second.undergoing_cardiac_arrest(), "Reinsertion accepted a stale EMP recovery") + generation = implant.activation_generation + callback_generation = implant.heal_generation + qdel(implant) + implant.heal(WEAKREF(second), generation, callback_generation) + TEST_ASSERT_EQUAL(second.getOxyLoss(), 195, "A deleted implant healed its owner") + + var/mob/living/carbon/human/consistent/voidcrew_revival_test/failed = patient() + failed.setBruteLoss(10) + failed.setFireLoss(10) + failed.setToxLoss(10, TRUE, FALSE, ALL) + failed.setOxyLoss(100) + failed.death() + failed.deny_revival = TRUE + var/obj/item/organ/cyberimp/chest/reviver/voidcrew_clock_test/failing_implant = allocate(/obj/item/organ/cyberimp/chest/reviver/voidcrew_clock_test) + failing_implant.clock = 1 HOURS + failing_implant.Insert(failed) + failing_implant.try_heal() + failing_implant.try_heal() + failing_implant.clock += 8 SECONDS + RegisterSignal(failed, COMSIG_LIVING_MINOR_SHOCK, PROC_REF(note_shock)) + failing_implant.heal(WEAKREF(failed), failing_implant.activation_generation, failing_implant.heal_generation) + TEST_ASSERT_EQUAL(failed.getBruteLoss(), 8, "Implant brute healing changed") + TEST_ASSERT_EQUAL(failed.getFireLoss(), 8, "Implant burn healing changed") + TEST_ASSERT_EQUAL(failed.getToxLoss(), 9, "Implant toxin healing changed") + TEST_ASSERT_EQUAL(failed.getOxyLoss(), 95, "Implant oxygen healing changed") + TEST_ASSERT_EQUAL(failed.revive_calls, 1, "The failed implant revival was not attempted after healing") + TEST_ASSERT_EQUAL(failing_implant.revive_cost, 125, "A failed revival added the success surcharge") + TEST_ASSERT_EQUAL(failing_implant.reviver_cooldown, 0, "A failed revival began the success cooldown") + TEST_ASSERT(failing_implant.reviving, "A failed revival ended its activation") + TEST_ASSERT_EQUAL(revival_count(failed), 0, "A failed implant revival was recorded as success") + TEST_ASSERT_EQUAL(shocks, 0, "A failed implant revival emitted a success shock") + +/datum/unit_test/voidcrew_combat_metrics/proc/note_shock(mob/living/source) + SIGNAL_HANDLER + shocks++ + +/datum/unit_test/voidcrew_combat_metrics/proc/check_nanite_defib() + var/list/failures = list("suicide" = DEFIB_FAIL_SUICIDE, "husk" = DEFIB_FAIL_HUSK, "no heart" = DEFIB_FAIL_NO_HEART, "bad heart" = DEFIB_FAIL_FAILING_HEART, "no brain" = DEFIB_FAIL_NO_BRAIN, "bad brain" = DEFIB_FAIL_FAILING_BRAIN, "brute" = DEFIB_FAIL_TISSUE_DAMAGE, "burn" = DEFIB_FAIL_TISSUE_DAMAGE, "blacklist" = DEFIB_FAIL_BLACKLISTED, "no intelligence" = DEFIB_FAIL_NO_INTELLIGENCE) + var/datum/nanite_program/defib/program = allocate(/datum/nanite_program/defib) + for(var/failure in failures) + var/mob/living/carbon/body = patient() + body.setOxyLoss(250) + body.death() + var/obj/item/organ/heart/heart = body.get_organ_slot(ORGAN_SLOT_HEART) + var/obj/item/organ/brain/brain = body.get_organ_slot(ORGAN_SLOT_BRAIN) + switch(failure) + if("suicide") + ADD_TRAIT(body, TRAIT_SUICIDED, INNATE_TRAIT) + if("husk") + ADD_TRAIT(body, TRAIT_HUSK, INNATE_TRAIT) + if("no heart") + heart.Remove(body, special = TRUE) + if("bad heart") + heart.set_organ_damage(heart.maxHealth) + if("no brain") + brain.Remove(body, special = TRUE) + if("bad brain") + brain.set_organ_damage(brain.maxHealth) + if("brute") + body.setBruteLoss(MAX_REVIVE_BRUTE_DAMAGE) + if("burn") + body.setFireLoss(MAX_REVIVE_FIRE_DAMAGE) + if("blacklist") + ADD_TRAIT(body, TRAIT_DEFIB_BLACKLISTED, INNATE_TRAIT) + if("no intelligence") + brain.suicided = TRUE + program.host_mob = body + RegisterSignal(body, COMSIG_LIVING_MINOR_SHOCK, PROC_REF(note_shock)) + var/health_before = body.health + TEST_ASSERT_EQUAL(body.can_defib(), failures[failure], "The [failure] fixture did not reach its intended rejection") + TEST_ASSERT(!program.check_revivable(), "Nanites accepted [failure] as eligible") + TEST_ASSERT(!program.defibrillate(), "Nanites revived despite [failure]") + TEST_ASSERT_EQUAL(body.health, health_before, "Nanites healed a body rejected for [failure]") + TEST_ASSERT_EQUAL(body.stat, DEAD, "Nanites revived a body rejected for [failure]") + TEST_ASSERT_EQUAL(revival_count(body), 0, "A nanite failure was logged as success: [failure]") + TEST_ASSERT_EQUAL(shocks, 0, "A rejected nanite attempt emitted a success shock") + + // Eligibility can pass and revive() can still fail. No success effects may escape. + var/mob/living/carbon/human/consistent/voidcrew_revival_test/failed = patient() + failed.setOxyLoss(250) + failed.death() + failed.deny_revival = TRUE + program.host_mob = failed + RegisterSignal(failed, COMSIG_LIVING_MINOR_SHOCK, PROC_REF(note_shock)) + TEST_ASSERT(program.check_revivable(), "The failed-revive fixture was ineligible") + TEST_ASSERT(!program.defibrillate(), "A failing revive() reported nanite success") + TEST_ASSERT_EQUAL(failed.stat, DEAD, "A failing revive() brought the body back") + TEST_ASSERT_EQUAL(shocks, 0, "A failing revive() emitted success effects") + TEST_ASSERT(!failed.has_status_effect(/datum/status_effect/jitter), "A failing revive() applied success jitter") + TEST_ASSERT_EQUAL(revival_count(failed), 0, "A failing revive() emitted a success row") + TEST_ASSERT_NULL(failed.metric_revival_method, "A failed nanite revival leaked attribution") + + // Both sides exercise their production revival path on identical mixed injuries. + var/mob/living/carbon/nanite_body = patient() + var/mob/living/carbon/paddle_body = patient() + var/obj/item/shockpaddles/cyborg/paddles = allocate(/obj/item/shockpaddles/cyborg) + for(var/mob/living/carbon/body in list(nanite_body, paddle_body)) + body.death() + var/obj/item/organ/liver = body.get_organ_slot(ORGAN_SLOT_LIVER) + liver.Remove(body, special = TRUE) + var/obj/item/bodypart/arm = body.get_bodypart(BODY_ZONE_L_ARM) + arm.drop_limb() + body.setBruteLoss(80) + body.setFireLoss(40) + body.setToxLoss(30, TRUE, FALSE, ALL) + body.setOxyLoss(110) + body.get_organ_slot(ORGAN_SLOT_HEART).set_organ_damage(20) + body.get_organ_slot(ORGAN_SLOT_BRAIN).set_organ_damage(20) + ADD_TRAIT(body, TRAIT_DEAF, INNATE_TRAIT) + program.host_mob = nanite_body + RegisterSignal(nanite_body, COMSIG_LIVING_MINOR_SHOCK, PROC_REF(note_shock)) + TEST_ASSERT(program.defibrillate(), "Eligible nanites did not revive") + TEST_ASSERT(paddles.revive_patient(paddle_body, paddle_body.can_defib()), "Eligible paddles did not revive") + TEST_ASSERT_EQUAL(shocks, 1, "Successful nanites did not emit exactly one success shock") + TEST_ASSERT(abs(nanite_body.health + 50) <= 4 * DAMAGE_PRECISION, "Nanites did not target -50 health within damage rounding") + TEST_ASSERT_EQUAL(nanite_body.getBruteLoss(), paddle_body.getBruteLoss(), "Nanite brute redistribution differs from paddles") + TEST_ASSERT_EQUAL(nanite_body.getFireLoss(), paddle_body.getFireLoss(), "Nanite burn redistribution differs from paddles") + TEST_ASSERT_EQUAL(nanite_body.getToxLoss(), paddle_body.getToxLoss(), "Nanite toxin redistribution differs from paddles") + TEST_ASSERT_EQUAL(nanite_body.getOxyLoss(), paddle_body.getOxyLoss(), "Nanite oxygen redistribution differs from paddles") + for(var/mob/living/carbon/body in list(nanite_body, paddle_body)) + TEST_ASSERT_NULL(body.get_organ_slot(ORGAN_SLOT_LIVER), "Defib restored an unrelated missing organ") + TEST_ASSERT_NULL(body.get_bodypart(BODY_ZONE_L_ARM), "Defib restored a missing limb") + TEST_ASSERT_EQUAL(body.get_organ_loss(ORGAN_SLOT_HEART), 20, "Defib cured unrelated heart damage") + TEST_ASSERT_EQUAL(body.get_organ_loss(ORGAN_SLOT_BRAIN), 20, "Defib cured unrelated brain damage") + TEST_ASSERT(HAS_TRAIT(body, TRAIT_DEAF), "Defib cured unrelated deafness") + TEST_ASSERT_EQUAL(revival_count(nanite_body, "nanites"), 1, "Successful nanites lost their attribution") + TEST_ASSERT_EQUAL(revival_count(paddle_body, "defibrillator"), 1, "Successful paddles lost their attribution") + + // A healthy corpse gets the same oxygen penalty in both paths. + var/mob/living/carbon/healthy = patient() + healthy.death() + program.host_mob = healthy + TEST_ASSERT(program.defibrillate(), "Nanites failed on a repaired corpse") + TEST_ASSERT_EQUAL(healthy.health, -50, "A repaired corpse was not brought to -50 health") + TEST_ASSERT(!program.check_revivable(), "Nanites accepted a living host") + + // The admin-ghost special case remains eligible without forcing its ghost home. + var/mob/living/carbon/human/consistent/voidcrew_revival_test/aghost = patient() + aghost.defib_override = DEFIB_NOGRAB_AGHOST + aghost.death() + program.host_mob = aghost + TEST_ASSERT(program.check_revivable(), "The admin-ghost special case was rejected") + TEST_ASSERT(program.defibrillate(), "The admin-ghost special case could not revive") + + // Change eligibility while the real zap() is in its charge windup. + var/mob/living/carbon/windup = patient() + windup.death() + program.host_mob = windup + shocks = 0 + RegisterSignal(windup, COMSIG_LIVING_MINOR_SHOCK, PROC_REF(note_shock)) + addtimer(CALLBACK(src, PROC_REF(blacklist_during_windup), windup), 1) + program.zap(WEAKREF(windup)) + TEST_ASSERT_EQUAL(windup.stat, DEAD, "Nanites ignored a blacklist added during windup") + TEST_ASSERT_EQUAL(windup.health, 100, "Nanites healed after failing their windup recheck") + TEST_ASSERT_EQUAL(shocks, 0, "A windup failure emitted success effects") + TEST_ASSERT_EQUAL(revival_count(windup), 0, "A windup failure was logged as success") + program.host_mob = null + +/datum/unit_test/voidcrew_combat_metrics/proc/blacklist_during_windup(mob/living/body) + ADD_TRAIT(body, TRAIT_DEFIB_BLACKLISTED, INNATE_TRAIT) + +/// Simulate time without modifying world.time or replacing the implant's healing/revival code. +/obj/item/organ/cyberimp/chest/reviver/voidcrew_clock_test + var/clock = 0 + +/obj/item/organ/cyberimp/chest/reviver/voidcrew_clock_test/reviver_time() + return clock + +/mob/living/carbon/human/consistent/voidcrew_revival_test + var/deny_revival = FALSE + var/throw_on_revive = FALSE + var/throw_on_heal = FALSE + var/defib_override + var/revive_calls = 0 + var/hardcrit_revive_calls = 0 + +/mob/living/carbon/human/consistent/voidcrew_revival_test/can_be_revived() + return !deny_revival && ..() + +/mob/living/carbon/human/consistent/voidcrew_revival_test/can_defib() + if(!isnull(defib_override)) + return defib_override + return ..() + +/mob/living/carbon/human/consistent/voidcrew_revival_test/revive(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE) + if(throw_on_revive) + throw EXCEPTION("Revival scope cleanup fixture") + revive_calls++ + if(health <= hardcrit_threshold) + hardcrit_revive_calls++ + return ..() + +/mob/living/carbon/human/consistent/voidcrew_revival_test/heal_and_revive(heal_to = 75, revive_message) + if(throw_on_heal) + throw EXCEPTION("Healing scope cleanup fixture") + return ..() /datum/unit_test/voidcrew_combat_metrics/proc/find_tally(event) for(var/key in SSmetrics.tallies) @@ -92,6 +494,9 @@ /datum/unit_test/voidcrew_combat_metrics/Destroy() if(old_pending) + GLOB.combat_metrics.pending_deaths = old_deaths + GLOB.combat_metrics.last_death_by_ckey = old_last_deaths + GLOB.combat_metrics.flush_scheduled = old_flush_scheduled SSmetrics.accepting = was_accepting SSmetrics.pending = old_pending SSmetrics.tallies = old_tallies From c338d89ba36767ee8cbaabe2ff06ce730b268d5a Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:18:02 -0700 Subject: [PATCH 024/105] Preserve completed kills through mission rewinds --- voidcrew/modules/missions/_missions.dm | 47 ++-- .../missions/missions/big_game_hunt.dm | 31 +-- .../modules/missions/objectives/combat.dm | 48 ++-- .../faction_pirates/faction_pirate_mobs.dm | 6 + .../modules/unit_tests/voidcrew_missions.dm | 231 ++++++++++++++++++ 5 files changed, 310 insertions(+), 53 deletions(-) diff --git a/voidcrew/modules/missions/_missions.dm b/voidcrew/modules/missions/_missions.dm index d0e14bac212..031b7c9c80a 100644 --- a/voidcrew/modules/missions/_missions.dm +++ b/voidcrew/modules/missions/_missions.dm @@ -94,6 +94,10 @@ var/list/datum/mission_objective/objectives = list() /// Index (1-based) of the current objective var/objective_index = 1 + /// Lifetime kill progress; resetting the site's objectives cannot undo it. + var/named_kill_completed = FALSE + /// Shared by every incarnation of this mission's named pirate target. + var/boss_cash_issued = FALSE // ===== TARGET ===== /// Where the mission points on the overmap, if anywhere @@ -387,6 +391,25 @@ if(objective?.active) objective.deactivate() +/// Re-arm the site, resuming a completed hunt at proof recovery rather than setup. +/datum/mission/proc/restart_objectives() + deactivate_objectives() + objective_index = 1 + if(named_kill_completed) + for(var/datum/mission_objective/field/kill_named/hunt in objectives) + objective_index = objectives.Find(hunt) + break + for(var/index in objective_index to length(objectives)) + var/datum/mission_objective/objective = objectives[index] + objective.reset() + +/// Claim before creating cash, regardless of death-handler ordering or retargets. +/datum/mission/proc/claim_boss_cash() + if(failed || completed || boss_cash_issued) + return FALSE + boss_cash_issued = TRUE + return TRUE + /** * Marks the mission as failed. * * reason - Optional reason for failure (shown to crew) @@ -566,8 +589,8 @@ * So this rewinds rather than retargets. The watch on whatever is standing in * the dead site is dropped before the wipe can fire it (otherwise the wipe reads * as a destroyed objective and burns a retarget re-rolling to a ruin the crew - * has no reason to be at), the objective chain resets, and the field step - * re-arms on the load signal - so docking there again lays the job out fresh. + * has no reason to be at). A completed hunt re-arms only its proof recovery; + * other chains restart from setup when the interior loads again. * * Anything the crew already carried out is untouched: it isn't in the site, so * the contract is still on its delivery step and nothing here applies. @@ -578,20 +601,17 @@ if(!quest_atom || !is_quest_atom_stranded()) return - UnregisterSignal(quest_atom, COMSIG_QDELETING) - quest_atom = null - quest_atom_bounds = null + forget_quest_atom(quest_atom) + if(named_kill_completed) + binding_serial++ // stranded proof must not match its replacement - deactivate_objectives() - for(var/datum/mission_objective/objective as anything in objectives) - objective.reset() - objective_index = 1 + restart_objectives() activate_current_objective() push_waypoint() - servant?.ship_notify("[name]: the site powered down before we recovered anything, and our gear went with it. The contract stands - it will be set up again next time you dock at ([target.target_x], [target.target_y]).", "MISSION UPDATE", SHIP_NOTIFY_WARNING, 'voidcrew/sound/notify2.ogg', 50) + servant?.ship_notify("[name]: contact lost. The contract stands.", "MISSION UPDATE", SHIP_NOTIFY_WARNING, 'voidcrew/sound/notify2.ogg', 50) /** - * Re-picks the target and restarts the objective chain from step one. + * Re-picks the target and restarts unfinished work, preserving completed kills. * Free while the mission sits on the board; budgeted while active. */ /datum/mission/proc/retarget(reason = "Target lost - contract void.") @@ -610,10 +630,7 @@ fail(reason) return - deactivate_objectives() - for(var/datum/mission_objective/objective as anything in objectives) - objective.reset() - objective_index = 1 + restart_objectives() update_text() if(active) diff --git a/voidcrew/modules/missions/missions/big_game_hunt.dm b/voidcrew/modules/missions/missions/big_game_hunt.dm index 7420129e29c..e88be70e6db 100644 --- a/voidcrew/modules/missions/missions/big_game_hunt.dm +++ b/voidcrew/modules/missions/missions/big_game_hunt.dm @@ -284,6 +284,7 @@ * entourage of lesser fauna. Death drops the mission-bound trophy. */ /datum/mission_objective/field/kill_named/big_game + proof_type = /obj/item/mission_recovery/trophy /// Where the lure was staked; the beast breaks cover next to it var/turf/lure_turf /// The trophy the beast drops ("tendril-crowned skull"), set by the mission @@ -298,22 +299,23 @@ /// The beast answers the lure, not a random spawn point /datum/mission_objective/field/kill_named/big_game/do_field_spawn() + if(spawned) + return if(!lure_turf) return ..() spawned = TRUE spawn_field_objects(get_nearby_open_turf(lure_turf, 4)) /datum/mission_objective/field/kill_named/big_game/spawn_field_objects(turf/spawn_turf) + if(mission.named_kill_completed) + return ..() var/mob/living/beast = new target_mob_type(spawn_turf) beast.name = mission.objective_name beast.desc += " This one is old, scarred, and much too big. The guild wants it as a wall piece." if(health_override > beast.maxHealth) beast.maxHealth = health_override beast.health = health_override - target_mob = beast - protect_field_mob(beast) - RegisterSignal(beast, COMSIG_LIVING_DEATH, PROC_REF(on_target_death)) - mission.register_quest_atom(beast) + track_target(beast) // The entourage: lesser fauna drawn in by the blood on the wind. Killing // them pays nothing - the contract is the name on the trophy. for(var/guard_type in guard_types) @@ -322,25 +324,8 @@ beast.visible_message(span_boldwarning("[beast] comes crashing in and goes straight for the lure!")) notify_crew("The lure's been taken. [mission.objective_name] is out in the open - good hunting.", type = SHIP_NOTIFY_WARNING, sound = 'voidcrew/sound/notify2.ogg') -/** - * The beast died: drop the bound trophy, track it instead, and advance. - * Full override of kill_named's proof drop - same signal, hunt flavor. - */ -/datum/mission_objective/field/kill_named/big_game/on_target_death(mob/living/source, gibbed) - SIGNAL_HANDLER - if(target_killed || !mission || mission.failed || mission.completed) - return - target_killed = TRUE - UnregisterSignal(source, COMSIG_LIVING_DEATH) - target_mob = null - - var/obj/item/mission_recovery/trophy/trophy = new(source.drop_location()) - trophy.name = "[mission.objective_name]'s [trophy_part]" - mission.bind_item(trophy) - mission.register_quest_atom(trophy) - - notify_crew("[mission.objective_name] is down. Recover the [trophy_part] and return it to the mission pad.") - complete() +/datum/mission_objective/field/kill_named/big_game/get_proof_name() + return "[mission.objective_name]'s [trophy_part]" /datum/mission_objective/field/kill_named/big_game/get_progress_string() if(!spawned) diff --git a/voidcrew/modules/missions/objectives/combat.dm b/voidcrew/modules/missions/objectives/combat.dm index dc9bded3307..dc4d67168f7 100644 --- a/voidcrew/modules/missions/objectives/combat.dm +++ b/voidcrew/modules/missions/objectives/combat.dm @@ -149,8 +149,8 @@ var/target_mob_type /// Guard typepaths spawned around the target (may repeat; may be empty) var/list/guard_types - /// Whether the named target is dead (the proof tag exists) - var/target_killed = FALSE + /// Proof subtype, shared by the initial kill and subsequent interior rewinds. + var/proof_type = /obj/item/mission_recovery/proof /// The live target, while they're alive var/mob/living/target_mob @@ -161,41 +161,59 @@ return ..() /datum/mission_objective/field/kill_named/reset() + deactivate() // also unhook a surviving target before forgetting it . = ..() - target_killed = FALSE - target_mob = null /datum/mission_objective/field/kill_named/spawn_field_objects(turf/spawn_turf) + if(mission.named_kill_completed) + create_proof(spawn_turf) + complete() + return var/mob/living/target = new target_mob_type(spawn_turf) target.name = mission.objective_name target.desc += " They look like they're worth something dead." - target_mob = target - protect_field_mob(target) - RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(on_target_death)) - mission.register_quest_atom(target) + track_target(target) // The entourage: untracked muscle around the target. Killing them pays // nothing - the contract is the name on the tag. for(var/guard_type in guard_types) var/mob/living/guard = new guard_type(get_nearby_open_turf(spawn_turf)) guard.desc += " They're on somebody's payroll." +/// Keep death tracking and the cash entitlement attached to the same mission. +/datum/mission_objective/field/kill_named/proc/track_target(mob/living/target) + target_mob = target + protect_field_mob(target) + if(istype(target, /mob/living/basic/trooper/pirate/faction)) + var/mob/living/basic/trooper/pirate/faction/pirate = target + pirate.mission_payout_ref = WEAKREF(mission) + RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(on_target_death)) + mission.register_quest_atom(target) + +/datum/mission_objective/field/kill_named/proc/get_proof_name() + return "[mission.objective_name]'s identification tag" + +/// The one proof factory for both a first kill and recovery after a rewind. +/datum/mission_objective/field/kill_named/proc/create_proof(atom/proof_location) + var/obj/item/mission_recovery/proof = new proof_type(proof_location) + proof.name = get_proof_name() + mission.bind_item(proof) + mission.register_quest_atom(proof) + return proof + /** * The target died: drop the proof item, track it instead, and advance. */ /datum/mission_objective/field/kill_named/proc/on_target_death(mob/living/source, gibbed) SIGNAL_HANDLER - if(target_killed || !mission || mission.failed || mission.completed) + if(!active || source != target_mob || !mission || mission.failed || mission.completed || mission.named_kill_completed) return - target_killed = TRUE + mission.named_kill_completed = TRUE UnregisterSignal(source, COMSIG_LIVING_DEATH) target_mob = null - var/obj/item/mission_recovery/proof/proof = new(source.drop_location()) - proof.name = "[mission.objective_name]'s identification tag" - mission.bind_item(proof) - mission.register_quest_atom(proof) + create_proof(source.drop_location()) - notify_crew("[mission.objective_name] eliminated. Recover the identification tag and return it to the mission pad.") + notify_crew("[mission.objective_name] is dead.") complete() /datum/mission_objective/field/kill_named/get_progress_string() diff --git a/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm b/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm index 9f158b5d8d5..7460c534134 100644 --- a/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm +++ b/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm @@ -14,6 +14,8 @@ obj_damage = 60 // Can break doors/objects like blobbernauts /// Guaranteed loot items dropped on death. All items in this list are spawned. var/list/loot_pool + /// A named mission target keeps this even after replacement or mission expiry. + var/datum/weakref/mission_payout_ref /// Random combat loot - one item is picked at random and added to death drops. var/list/random_loot = list(\ /obj/item/pen/edagger,\ @@ -56,6 +58,10 @@ /// Drops plunder_credits as a holochip on death /mob/living/basic/trooper/pirate/faction/proc/on_death_drop_credits(mob/living/source) SIGNAL_HANDLER + if(mission_payout_ref) + var/datum/mission/mission = mission_payout_ref.resolve() + if(!mission?.claim_boss_cash()) + return new /obj/item/holochip(drop_location(), plunder_credits) // ==================== SILVERSCALE (Aristocratic Lizards) ==================== diff --git a/voidcrew/modules/unit_tests/voidcrew_missions.dm b/voidcrew/modules/unit_tests/voidcrew_missions.dm index 59b49bc4b11..be92b4338fe 100644 --- a/voidcrew/modules/unit_tests/voidcrew_missions.dm +++ b/voidcrew/modules/unit_tests/voidcrew_missions.dm @@ -345,3 +345,234 @@ for(var/obj/structure/overmap/space_ruin/ruin as anything in live_ruins) ruin.loaded = saved_loaded[ruin] ruin.mission_claims = saved_claims[ruin] + +/// Isolate mission lifecycle tests from overmap generation and bank accounts. +/datum/mission/kill_rewind_test + var/reward_calls = 0 + +/datum/mission/kill_rewind_test/generate_mission_details() + return + +/datum/mission/kill_rewind_test/distribute_rewards(atom/reward_anchor) + reward_calls++ + +/// The far corner is the site; the near corner represents the crew's ship. +/datum/mission_target/kill_rewind_test + var/turf/spawn_turf + var/interior_loaded = TRUE + +/datum/mission_target/kill_rewind_test/resolve() + return TRUE + +/datum/mission_target/kill_rewind_test/is_interior_loaded() + return interior_loaded + +/datum/mission_target/kill_rewind_test/get_spawn_turf() + return spawn_turf + +/datum/mission_target/kill_rewind_test/contains_turf(turf/where) + return where == spawn_turf + +/datum/mission_target/kill_rewind_test/get_interior_bounds() + return list(spawn_turf.x, spawn_turf.y, spawn_turf.x, spawn_turf.y, spawn_turf.z) + +/// Retain the original body so real revival can exercise the cash handler. +/mob/living/basic/trooper/pirate/faction/boss/mission_rewind_test + ai_controller = null + basic_mob_flags = NONE + use_dynamic_appearance = FALSE + corpse = null + loot = null + loot_pool = null + plunder_credits = 3000 + unsuitable_cold_damage = 0 + unsuitable_heat_damage = 0 + +/datum/unit_test/voidcrew_mission_kill_rewind + abstract_type = /datum/unit_test/voidcrew_mission_kill_rewind + +/datum/unit_test/voidcrew_mission_kill_rewind/proc/make_hunt(big_game = FALSE) + var/datum/mission/kill_rewind_test/mission = allocate(__IMPLIED_TYPE__) + mission.active = TRUE + mission.requires_item = TRUE + mission.objective_name = "Old Testbeard" + var/datum/mission_target/kill_rewind_test/target = allocate(__IMPLIED_TYPE__, mission) + mission.target = target + target.spawn_turf = run_loc_floor_top_right + var/datum/mission_objective/field/kill_named/hunt + var/datum/mission_objective/set_lure/lure + if(big_game) + lure = allocate(__IMPLIED_TYPE__) + mission.add_objective(lure) + var/datum/mission_objective/field/kill_named/big_game/trophy_hunt = allocate(__IMPLIED_TYPE__) + trophy_hunt.trophy_part = "scarred jawbone" + trophy_hunt.health_override = 450 + hunt = trophy_hunt + lure.hunt_objective = trophy_hunt + else + hunt = allocate(__IMPLIED_TYPE__) + hunt.target_mob_type = /mob/living/basic/trooper/pirate/faction/boss/mission_rewind_test + hunt.guard_types = list(/mob/living/basic/trooper/pirate/faction/boss/mission_rewind_test) + mission.add_objective(hunt) + mission.add_objective(allocate(big_game ? /datum/mission_objective/deliver/bound/trophy : /datum/mission_objective/deliver/bound/proof)) + if(lure) + lure.kit = allocate(/obj/item/hunting_lure, target.spawn_turf) + mission.register_quest_atom(lure.kit) + mission.activate_current_objective() + if(lure) + lure.on_planted(null, target.spawn_turf) + // The single-turf fixture stands in for the whole hunting ground. + hunt.target_mob.forceMove(target.spawn_turf) + return mission + +/datum/unit_test/voidcrew_mission_kill_rewind/proc/test_mobs() + var/list/mobs = list() + for(var/mob/living/basic/trooper/pirate/faction/boss/mission_rewind_test/boss in GLOB.mob_list) + if(!QDELETED(boss)) + mobs += boss + return mobs + +/datum/unit_test/voidcrew_mission_kill_rewind/proc/floor_items(item_type) + var/list/items = list() + for(var/turf/tile in block(run_loc_floor_bottom_left, run_loc_floor_top_right)) + for(var/obj/item/item in tile.contents) + if(istype(item, item_type) && !QDELETED(item)) + items += item + return items + +/// Kill, strand the proof and rebuild the interior more than once. +/datum/unit_test/voidcrew_mission_kill_rewind/repeated/Run() + check_repeated_rewinds(FALSE) + +/// The same lifecycle must restore trophies without another lure or beast. +/datum/unit_test/voidcrew_mission_kill_rewind/trophy/Run() + check_repeated_rewinds(TRUE) + +/datum/unit_test/voidcrew_mission_kill_rewind/proc/check_repeated_rewinds(big_game) + var/datum/mission/kill_rewind_test/mission = make_hunt(big_game) + var/datum/mission_target/kill_rewind_test/target = mission.target + var/datum/mission_objective/field/kill_named/hunt = mission.current_objective() + var/mob/living/basic/trooper/pirate/faction/boss/mission_rewind_test/boss = hunt.target_mob + TEST_ASSERT_EQUAL(length(test_mobs()), 2, "The initial hunt must spawn a target and guard") + boss.death(FALSE) + TEST_ASSERT(mission.named_kill_completed, "The mission must retain the completed kill") + TEST_ASSERT(mission.boss_cash_issued, "The first death must claim the mission's cash entitlement") + var/obj/item/mission_recovery/proof = mission.quest_atom + TEST_ASSERT(istype(proof, big_game ? /obj/item/mission_recovery/trophy : /obj/item/mission_recovery/proof), "The initial proof must have the right subtype") + TEST_ASSERT(mission.can_turn_in(proof), "The original proof must be deliverable") + + SEND_SIGNAL(boss, COMSIG_LIVING_DEATH, FALSE) + hunt.on_target_death(boss, FALSE) + TEST_ASSERT(boss.revive(ADMIN_HEAL_ALL), "The retained original boss must be revivable") + boss.death(FALSE) + TEST_ASSERT_EQUAL(mission.quest_atom, proof, "Duplicate death signals and revival must not replace the proof") + TEST_ASSERT_EQUAL(length(floor_items(/obj/item/mission_recovery)), 1, "A revived boss must not create another proof") + var/list/cash = floor_items(/obj/item/holochip) + TEST_ASSERT_EQUAL(length(cash), 1, "Duplicate deaths and revival must issue one holochip") + var/obj/item/holochip/payment = cash[1] + TEST_ASSERT_EQUAL(payment.credits, boss.plunder_credits, "The boss cash amount must stay unchanged") + payment.forceMove(run_loc_floor_bottom_left) + var/retargets_before = mission.retargets_left + + for(var/rewind in 1 to 3) + var/obj/item/mission_recovery/old_proof = mission.quest_atom + var/old_serial = mission.binding_serial + target.interior_loaded = FALSE + mission.on_target_interior_unloaded() + TEST_ASSERT_NULL(mission.quest_atom, "Unload must forget stranded proof before the wipe") + TEST_ASSERT_EQUAL(mission.current_objective(), hunt, "A completed kill must wait at proof recovery") + TEST_ASSERT(mission.named_kill_completed && mission.boss_cash_issued, "Rewind must retain both lifetime flags") + TEST_ASSERT(mission.binding_serial > old_serial, "Replacement proof must get a fresh binding") + for(var/mob/living/left_behind in test_mobs()) + qdel(left_behind) + // Keep one obsolete proof through reload to check stale-binding rejection. + if(rewind != 1) + qdel(old_proof) + TEST_ASSERT(!mission.failed && !QDELETED(mission), "Deleting forgotten quest atoms must not trigger quest loss") + target.interior_loaded = TRUE + mission.on_target_interior_loaded() + var/obj/item/mission_recovery/replacement = mission.quest_atom + TEST_ASSERT_NOTNULL(replacement, "Reload must place replacement proof") + TEST_ASSERT(replacement != old_proof, "Reload must bind a newly created proof") + TEST_ASSERT_EQUAL(replacement.type, big_game ? /obj/item/mission_recovery/trophy : /obj/item/mission_recovery/proof, "Reload must preserve the proof subtype") + TEST_ASSERT_EQUAL(replacement.name, big_game ? "Old Testbeard's scarred jawbone" : "Old Testbeard's identification tag", "Reload must preserve the proof's identity") + TEST_ASSERT(mission.can_turn_in(replacement), "Reload must resume the delivery step") + if(rewind == 1) + TEST_ASSERT(!mission.can_turn_in(old_proof), "Stranded proof must not match the new binding") + qdel(old_proof) + mission.on_target_interior_loaded() + hunt.do_field_spawn() + TEST_ASSERT_EQUAL(length(test_mobs()), 0, "Completed hunts must never respawn a boss or guards") + TEST_ASSERT_EQUAL(length(floor_items(/obj/item/mission_recovery)), 1, "Repeated load callbacks must leave exactly one proof") + TEST_ASSERT_EQUAL(length(floor_items(/obj/item/holochip)), 1, "Rewinds must not issue more boss cash") + TEST_ASSERT_EQUAL(mission.retargets_left, retargets_before, "Interior rewinds must not consume retargets") + if(big_game) + var/datum/mission_objective/set_lure/lure = mission.objectives[1] + TEST_ASSERT(lure.completed, "A completed trophy hunt must never ask for another lure") + + TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left, mission.quest_atom), "Replacement proof must finish the mission") + TEST_ASSERT(!mission.failed && mission.completed, "Proof consumption must finish rather than void the mission") + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left, null, TRUE), "Repeated forced turn-in must still honor mission completion") + TEST_ASSERT_EQUAL(mission.reward_calls, 1, "Repeated turn-in must not distribute rewards twice") + +/// Carried proof stays valid while the crew revisits an emptied site. +/datum/unit_test/voidcrew_mission_kill_rewind/carried/Run() + for(var/big_game in list(FALSE, TRUE)) + var/datum/mission/kill_rewind_test/mission = make_hunt(big_game) + var/datum/mission_target/kill_rewind_test/target = mission.target + var/datum/mission_objective/field/kill_named/hunt = mission.current_objective() + var/mob/living/basic/trooper/pirate/faction/boss/mission_rewind_test/boss = hunt.target_mob + boss.death(FALSE) + var/obj/item/mission_recovery/proof = mission.quest_atom + var/mob/living/carbon/human/carrier = allocate(__IMPLIED_TYPE__) + TEST_ASSERT(carrier.put_in_hands(proof), "The crew must be able to carry out the proof") + var/serial_before = mission.binding_serial + var/datum/mission_objective/delivery = mission.current_objective() + for(var/rewind in 1 to 3) + target.interior_loaded = FALSE + mission.on_target_interior_unloaded() + target.interior_loaded = TRUE + mission.on_target_interior_loaded() + TEST_ASSERT_EQUAL(mission.quest_atom, proof, "Extracted proof must stay tracked") + TEST_ASSERT_EQUAL(mission.binding_serial, serial_before, "Extracted proof must keep its binding") + TEST_ASSERT_EQUAL(mission.current_objective(), delivery, "Extracted proof must stay on delivery") + TEST_ASSERT(mission.can_turn_in(proof), "Carried proof must remain valid") + TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left, proof), "Carried proof must still finish the contract") + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left, proof), "The same proof cannot pay twice") + TEST_ASSERT_EQUAL(mission.reward_calls, 1, "Carried proof must pay once") + var/cash_count = length(floor_items(/obj/item/holochip)) + boss.on_death_drop_credits(boss) + TEST_ASSERT_EQUAL(length(floor_items(/obj/item/holochip)), cash_count, "An expired mission reference must never become an unbound cash drop") + +/// An abandoned live target and its replacement share the same cash entitlement. +/datum/unit_test/voidcrew_mission_kill_rewind/replacement/Run() + var/datum/mission/kill_rewind_test/mission = make_hunt() + var/datum/mission_target/kill_rewind_test/target = mission.target + var/datum/mission_objective/field/kill_named/hunt = mission.current_objective() + var/mob/living/basic/trooper/pirate/faction/boss/mission_rewind_test/original = hunt.target_mob + target.interior_loaded = FALSE + mission.on_target_interior_unloaded() + TEST_ASSERT(!mission.named_kill_completed && !mission.boss_cash_issued, "A live target's rewind must not invent completion or spend cash") + TEST_ASSERT_NULL(hunt.target_mob, "Reset must release the original target") + target.interior_loaded = TRUE + mission.on_target_interior_loaded() + var/mob/living/basic/trooper/pirate/faction/boss/mission_rewind_test/replacement = hunt.target_mob + TEST_ASSERT(replacement && replacement != original, "An unfinished hunt must spawn a replacement target") + original.death(FALSE) + TEST_ASSERT(!mission.named_kill_completed, "The original target's old death handler must be unregistered") + TEST_ASSERT_EQUAL(mission.quest_atom, replacement, "An obsolete target must not replace the live quest atom") + TEST_ASSERT_EQUAL(length(floor_items(/obj/item/mission_recovery)), 0, "An obsolete target must not drop proof") + replacement.death(FALSE) + TEST_ASSERT(mission.named_kill_completed, "The current target must complete the kill") + TEST_ASSERT_EQUAL(length(floor_items(/obj/item/holochip)), 1, "Original and replacement targets must share one cash payment") + var/obj/item/mission_recovery/old_proof = mission.quest_atom + var/mob_count = length(test_mobs()) + mission.retarget() + TEST_ASSERT(mission.named_kill_completed && mission.boss_cash_issued, "Retargeting must preserve both lifetime flags") + TEST_ASSERT_EQUAL(length(test_mobs()), mob_count, "Retargeting a completed kill must restore proof without more mobs") + TEST_ASSERT(!mission.can_turn_in(old_proof), "A retarget must reject the obsolete proof") + TEST_ASSERT(mission.can_turn_in(mission.quest_atom), "A retarget must resume proof delivery") + qdel(old_proof) + SEND_SIGNAL(original, COMSIG_LIVING_DEATH, FALSE) + SEND_SIGNAL(replacement, COMSIG_LIVING_DEATH, FALSE) + TEST_ASSERT_EQUAL(length(floor_items(/obj/item/holochip)), 1, "Retargeting must not replenish the boss cash entitlement") From aa01a50f6816ac32212c4fd09b685e2e5c115766 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:35:47 -0700 Subject: [PATCH 025/105] Unified installed capacity and cyberware failure gates --- .../signals_atom/signals_atom_x_act.dm | 2 +- tgstation.dme | 1 + voidcrew/_DEFINES/cyberware.dm | 2 - voidcrew/edits/surgery/installed_capacity.dm | 91 ++++ voidcrew/modules/cyberware/chrome_cradle.dm | 32 +- voidcrew/modules/cyberware/cradle_ui.dm | 2 +- voidcrew/modules/cyberware/cyberware_base.dm | 36 +- .../modules/cyberware/cyberware_component.dm | 104 +++- .../modules/cyberware/ripperdoc_catalog.dm | 2 +- voidcrew/modules/cyberware/ware_legend.dm | 12 +- .../modules/cyberware/ware_military_body.dm | 29 +- .../modules/nanites/code/nanite_component.dm | 63 ++- .../nanites/code/programs/_programs.dm | 58 ++ .../modules/unit_tests/voidcrew_cyberware.dm | 494 +++++++++++++++++- 14 files changed, 853 insertions(+), 75 deletions(-) create mode 100644 voidcrew/edits/surgery/installed_capacity.dm diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm index 0b732912726..4840bfa85dd 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm @@ -9,7 +9,7 @@ ///from the [EX_ACT] wrapper macro: (severity, target) #define COMSIG_ATOM_EX_ACT "atom_ex_act" ///from base of atom/emp_act(severity): (severity). return EMP protection flags -#define COMSIG_ATOM_PRE_EMP_ACT "atom_emp_act" +#define COMSIG_ATOM_PRE_EMP_ACT "atom_pre_emp_act" // VOIDCREW EDIT: separate protection from EMP notification. ///from base of atom/emp_act(severity): (severity, protection) #define COMSIG_ATOM_EMP_ACT "atom_emp_act" ///from base of atom/fire_act(): (exposed_temperature, exposed_volume) diff --git a/tgstation.dme b/tgstation.dme index 0c9037cfd75..6525e2a61b3 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6937,6 +6937,7 @@ #include "voidcrew\edits\subsystem\ticker.dm" #include "voidcrew\edits\subsystem\tutorials.dm" #include "voidcrew\edits\surgery\decapitation.dm" +#include "voidcrew\edits\surgery\installed_capacity.dm" #include "voidcrew\edits\surgery\leg_manipulation.dm" #include "voidcrew\edits\surgery\self_surgery.dm" #include "voidcrew\edits\vehicles\mecha.dm" diff --git a/voidcrew/_DEFINES/cyberware.dm b/voidcrew/_DEFINES/cyberware.dm index 911864fd572..78d71dbfde3 100644 --- a/voidcrew/_DEFINES/cyberware.dm +++ b/voidcrew/_DEFINES/cyberware.dm @@ -40,8 +40,6 @@ #define ORGAN_SLOT_CYBERWARE_LEGS "cyberware_legs" /// Vocal hardware, mouth. Currently unused (Voicebox Mimic cut in roster v2). #define ORGAN_SLOT_CYBERWARE_LARYNX "cyberware_larynx" -/// Capacity governor, head. Governor Delete (+6 capacity). -#define ORGAN_SLOT_CYBERWARE_GOVERNOR "cyberware_governor" /// Hand augmentation, arms. Gecko Grips vs Fixer's Fingers. #define ORGAN_SLOT_CYBERWARE_HANDS "cyberware_hands" /// Emissive circuit tattoos, chest. Chromatic Dermis. diff --git a/voidcrew/edits/surgery/installed_capacity.dm b/voidcrew/edits/surgery/installed_capacity.dm new file mode 100644 index 00000000000..76358669b22 --- /dev/null +++ b/voidcrew/edits/surgery/installed_capacity.dm @@ -0,0 +1,91 @@ +// Capacity checks run before upstream can evict, consume or move an installed item. +/obj/item/organ/Insert(mob/living/carbon/receiver, special = FALSE, movement_flags) + // Chrome has already checked its install context, including forced admin installs. + if(!special && !GetComponent(/datum/component/cyberware) && !cyberware_insert_check(src, receiver)) + return FALSE + . = ..() + if(.) + cyberware_reevaluate_brownout(receiver) + +/obj/item/organ/on_mob_remove(mob/living/carbon/organ_owner, special = FALSE, movement_flags) + . = ..() + cyberware_reevaluate_brownout(organ_owner) + +/obj/item/organ/apply_organ_damage(damage_amount, maximum = maxHealth, required_organ_flag = NONE) + . = ..() + var/datum/component/cyberware/chrome = GetComponent(/datum/component/cyberware) + chrome?.update_failing() + +/obj/item/organ/set_organ_damage(damage_amount, required_organ_flag = NONE) + . = ..() + var/datum/component/cyberware/chrome = GetComponent(/datum/component/cyberware) + chrome?.update_failing() + +/obj/item/organ/pre_surgical_insertion(mob/living/user, mob/living/carbon/new_owner, target_zone) + . = ..() + if(.) + return cyberware_insert_check(src, new_owner, feedback_to = user) + +// Surgery has its own delay, then unequips the organ before calling Insert(). +// Recheck here so a late capacity refusal leaves it in the surgeon's hands. +/datum/surgery_step/manipulate_organs/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) + if(current_type == "insert" && (QDELETED(target_organ) || !cyberware_insert_check(target_organ, target, feedback_to = user))) + return SURGERY_STEP_FAIL + return ..() + +/obj/item/implant/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE) + if(!force && iscarbon(target)) + var/list/replaced = list() + // Upstream combines duplicate implants instead of adding a second object. + if(!allow_multiple) + for(var/obj/item/implant/incumbent in target.implants) + if(istype(incumbent, type)) + replaced += incumbent + break + if(!installed_capacity_check(target, list(src), replaced, silent)) + return FALSE + . = ..() + if(.) + cyberware_reevaluate_brownout(target) + +/obj/item/implant/removed(mob/living/source, silent = FALSE, special = 0) + . = ..() + cyberware_reevaluate_brownout(source) + +/// Limbs are free, but the organs carried inside them are not. +/obj/item/bodypart/proc/installed_capacity_can_attach(mob/living/carbon/receiver) + var/list/additions = list(src) + var/list/removals = list() + var/obj/item/bodypart/incumbent_limb = receiver.get_bodypart(body_zone) + if(incumbent_limb != src) + removals += incumbent_limb + for(var/obj/item/organ/organ in src) + additions |= organ + removals |= organ.cyberware_get_incumbents(receiver) + return installed_capacity_check(receiver, additions, removals) + +/obj/item/bodypart/replace_limb(mob/living/carbon/limb_owner, special) + if(istype(limb_owner) && !installed_capacity_can_attach(limb_owner)) + return FALSE + return ..() + +/obj/item/bodypart/try_attach_limb(mob/living/carbon/new_limb_owner, special, lazy) + if(!lazy && !installed_capacity_can_attach(new_limb_owner)) + return FALSE + . = ..() + if(.) + cyberware_reevaluate_brownout(new_limb_owner) + +// Reject before status_effect/on_creation assigns owner: a rejected enhancement +// must not run bioware_lost() for a benefit it never granted. +/datum/status_effect/bioware/on_creation(mob/living/new_owner, ...) + if(!installed_capacity_check(new_owner, list(src))) + qdel(src) + return FALSE + . = ..() + if(.) + cyberware_reevaluate_brownout(new_owner) + +/datum/status_effect/bioware/on_remove() + . = ..() + cyberware_reevaluate_brownout(owner) diff --git a/voidcrew/modules/cyberware/chrome_cradle.dm b/voidcrew/modules/cyberware/chrome_cradle.dm index 9304e582ed8..904bb0d0899 100644 --- a/voidcrew/modules/cyberware/chrome_cradle.dm +++ b/voidcrew/modules/cyberware/chrome_cradle.dm @@ -236,10 +236,14 @@ */ /obj/machinery/chrome_cradle/proc/begin_install(obj/item/organ/ware) var/mob/living/carbon/patient = occupant + if(!istype(patient) || QDELETED(ware)) + return + var/datum/component/cyberware/chrome = ware.GetComponent(/datum/component/cyberware) + if(!chrome || !cyberware_insert_check(ware, patient)) + return if(ware.loc != src && !patient.transferItemToLoc(ware, src)) balloon_alert(patient, "[ware.name] is stuck to you!") return - var/datum/component/cyberware/chrome = ware.GetComponent(/datum/component/cyberware) busy = TRUE busy_action = "install" busy_ware = ware @@ -282,8 +286,18 @@ var/datum/component/cyberware/chrome = ware.GetComponent(/datum/component/cyberware) if(!chrome) return + // Recheck the final set after the sequence delay, while every incumbent is + // still installed. An intervening install or lost Governor must not evict it. + if(!cyberware_insert_check(ware, patient)) + tray |= ware + balloon_alert(patient, "install refused!") + playsound(src, 'sound/machines/scanner/scanbuzz.ogg', 40, TRUE) + wake_patient(patient) + SStgui.update_uis(src) + return // Same-slot incumbents come out into the tray first, never the floor. - for(var/obj/item/organ/incumbent in ware.cyberware_get_incumbents(patient)) + var/list/incumbents = ware.cyberware_get_incumbents(patient) + for(var/obj/item/organ/incumbent in incumbents) incumbent.Remove(patient, special = TRUE) incumbent.forceMove(src) tray += incumbent @@ -291,10 +305,16 @@ tray -= ware chrome.grant_install_context(patient) if(!ware.Insert(patient)) - tray += ware + chrome.clear_install_context() + // Preserve the old installation even if a later insertion gate refuses. + for(var/obj/item/organ/incumbent in incumbents) + if(!QDELETED(incumbent) && incumbent.Insert(patient, special = TRUE)) + tray -= incumbent + tray |= ware balloon_alert(patient, "install refused!") playsound(src, 'sound/machines/scanner/scanbuzz.ogg', 40, TRUE) wake_patient(patient) + SStgui.update_uis(src) return do_sparks(3, FALSE, src) patient.flash_act(visual = 1) @@ -644,11 +664,9 @@ projected_capacity += chrome.capacity_bonus for(var/obj/item/organ/incumbent in selected_ware.cyberware_get_incumbents(patient)) evicts += incumbent.name + projected_load -= get_installed_capacity_cost(incumbent) var/datum/component/cyberware/incumbent_chrome = incumbent.GetComponent(/datum/component/cyberware) - if(!incumbent_chrome) - continue - projected_load -= incumbent_chrome.chrome_load - projected_capacity -= incumbent_chrome.capacity_bonus + projected_capacity -= incumbent_chrome?.capacity_bonus return list( "load" = projected_load, "capacity" = projected_capacity, diff --git a/voidcrew/modules/cyberware/cradle_ui.dm b/voidcrew/modules/cyberware/cradle_ui.dm index 889222f0bfd..7ad8beda7ad 100644 --- a/voidcrew/modules/cyberware/cradle_ui.dm +++ b/voidcrew/modules/cyberware/cradle_ui.dm @@ -18,7 +18,7 @@ * somewhere even before it gets a home. */ GLOBAL_LIST_INIT(cyberware_ui_groups, list( - list("id" = "cortex", "name" = "Frontal Cortex", "region" = "head", "slots" = list(ORGAN_SLOT_CYBERWARE_GOVERNOR, ORGAN_SLOT_CYBERWARE_RIGGER, ORGAN_SLOT_CYBERWARE_REGISTRY)), + list("id" = "cortex", "name" = "Frontal Cortex", "region" = "head", "slots" = list(ORGAN_SLOT_CYBERWARE_RIGGER, ORGAN_SLOT_CYBERWARE_REGISTRY)), list("id" = "ocular", "name" = "Ocular System", "region" = "head", "slots" = list(ORGAN_SLOT_EYES)), list("id" = "aural", "name" = "Auditory System", "region" = "head", "slots" = list(ORGAN_SLOT_CYBERWARE_EARS, ORGAN_SLOT_CYBERWARE_LARYNX)), list("id" = "os", "name" = "Operating System", "region" = "torso", "slots" = list(ORGAN_SLOT_CYBERWARE_OS)), diff --git a/voidcrew/modules/cyberware/cyberware_base.dm b/voidcrew/modules/cyberware/cyberware_base.dm index 921b8d4eb16..367f077f491 100644 --- a/voidcrew/modules/cyberware/cyberware_base.dm +++ b/voidcrew/modules/cyberware/cyberware_base.dm @@ -74,7 +74,6 @@ /obj/item/organ/cyberimp/cyberware/examine(mob/user) . = ..() - . += span_notice("Neural load: [chrome_load][chrome_capacity_bonus ? ", grants +[chrome_capacity_bonus] chrome capacity" : ""]. Tier [tier] chrome, install at a Chrome Cradle or through organ-manipulation surgery.") . += cyberware_emp_examine_line() /obj/item/organ/cyberimp/cyberware/Insert(mob/living/carbon/receiver, special = FALSE, movement_flags) @@ -151,8 +150,6 @@ /obj/item/organ/eyes/robotic/cyberware/examine(mob/user) . = ..() - . += span_notice("Neural load: [chrome_load]. Tier [tier] chrome, install at a Chrome Cradle or through organ-manipulation surgery.") - . += span_notice("Diagnostic bus: [chrome_scan_resolution >= CYBERWARE_SCAN_ITEMIZED ? "reads a body's chrome piece by piece" : "counts a body's chrome signatures, but can't name them"].") . += cyberware_emp_examine_line() /obj/item/organ/eyes/robotic/cyberware/Insert(mob/living/carbon/receiver, special = FALSE, movement_flags) @@ -223,7 +220,6 @@ /obj/item/organ/cyberimp/arm/toolkit/cyberware/examine(mob/user) . = ..() - . += span_notice("Neural load: [chrome_load]. Tier [tier] chrome, install at a Chrome Cradle or through organ-manipulation surgery.") . += cyberware_emp_examine_line() /obj/item/organ/cyberimp/arm/toolkit/cyberware/Insert(mob/living/carbon/receiver, special = FALSE, movement_flags) @@ -250,6 +246,9 @@ // (Fixer's Fingers picking a tool off the radial, the Rockjaw drill, blades, // launchers) lights the bearer up on the way out and on the way back in. /obj/item/organ/cyberimp/arm/toolkit/cyberware/Extend(obj/item/augment) + var/datum/component/cyberware/chrome = GetComponent(/datum/component/cyberware) + if(!chrome?.is_running()) + return . = ..() // The parent assigns active_item before it knows whether a hand is free // (augments_arms.dm), so "did it deploy" is "did it leave us", not "is it set". @@ -297,24 +296,10 @@ /proc/cyberware_insert_check(obj/item/organ/ware, mob/living/carbon/target, silent = FALSE, mob/feedback_to) if(!iscarbon(target)) return FALSE - var/datum/component/cyberware/chrome = ware.GetComponent(/datum/component/cyberware) - if(!chrome) + if(installed_capacity_check(target, list(ware), ware.cyberware_get_incumbents(target), silent)) return TRUE - var/projected_load = get_chrome_load(target) + chrome.chrome_load - var/projected_capacity = get_chrome_capacity(target) + chrome.capacity_bonus - for(var/obj/item/organ/incumbent in ware.cyberware_get_incumbents(target)) - var/datum/component/cyberware/incumbent_chrome = incumbent.GetComponent(/datum/component/cyberware) - if(!incumbent_chrome) - continue - projected_load -= incumbent_chrome.chrome_load - projected_capacity -= incumbent_chrome.capacity_bonus - if(projected_load <= projected_capacity) - return TRUE - if(!silent) - target.balloon_alert(target, "no neural headroom!") - to_chat(target, span_warning("Your nervous system is already maxed out. [ware] needs [projected_load - projected_capacity] more chrome capacity.")) - if(feedback_to && feedback_to != target) - to_chat(feedback_to, span_warning("[target]'s nervous system can't take [ware], [projected_load - projected_capacity] over capacity.")) + if(!silent && feedback_to && feedback_to != target) + feedback_to.balloon_alert(feedback_to, "no neural headroom!") return FALSE /** @@ -381,7 +366,7 @@ /// weakness was always in the design and never legible on the item itself; /// now that it actually bites (BAL-4), it says so where people read it. /proc/cyberware_emp_examine_line() - return span_notice("Electromagnetic pulses scramble chrome. An EMP knocks this offline for up to [DisplayTimeText(CYBERWARE_EMP_DOWNTIME)] and everything it was doing for you stops until it reboots; a Chrome Cradle tune-up clears it early.") + return span_notice("The shielding is thin and worn.") // ---- Ink bus ----------------------------------------------------------- @@ -458,11 +443,10 @@ . = ..() if(!.) return - if(!organ?.owner) - return FALSE - if(organ.organ_flags & ORGAN_FAILING) + var/datum/component/cyberware/chrome = organ?.GetComponent(/datum/component/cyberware) + if(!chrome?.is_running()) if(feedback) - organ.owner.balloon_alert(organ.owner, "chrome offline!") + organ?.owner?.balloon_alert(organ.owner, "chrome offline!") return FALSE return TRUE diff --git a/voidcrew/modules/cyberware/cyberware_component.dm b/voidcrew/modules/cyberware/cyberware_component.dm index 56456fb7f8d..36aa2c2692d 100644 --- a/voidcrew/modules/cyberware/cyberware_component.dm +++ b/voidcrew/modules/cyberware/cyberware_component.dm @@ -26,7 +26,7 @@ /// CYBERWARE_TIER_*, drives accent colours and Splice's bedside manner. var/tier = CYBERWARE_TIER_1 /// Chrome capacity this ware ADDS to its bearer while installed, the - /// Overclock Governor hook. Load 0 + bonus 6 is a Governor. + /// Governor Delete hook. Load 0 + bonus 15 is a Governor. var/capacity_bonus = 0 /// TRUE while the bearer is over capacity and this ware is browned out. var/browned_out = FALSE @@ -186,9 +186,10 @@ */ /datum/component/cyberware/proc/settle_passives(mob/living/carbon/bearer) var/obj/item/organ/ware = parent - var/installed_here = !QDELETED(ware) && bearer && ware.owner == bearer - var/ware_running = !browned_out && !emp_down && !(ware.organ_flags & ORGAN_FAILING) - var/should_be_online = installed_here && ware_running + var/should_be_online = bearer && ware.owner == bearer && is_running() + if(!should_be_online && istype(ware, /obj/item/organ/cyberimp/arm/toolkit/cyberware)) + var/obj/item/organ/cyberimp/arm/toolkit/cyberware/arm = ware + arm.Retract() if(passives_online == !!should_be_online) return passives_online = !!should_be_online @@ -201,7 +202,12 @@ /// settle (see the registration comment in on_implanted()). /datum/component/cyberware/proc/on_owner_life(mob/living/carbon/source, seconds_per_tick, times_fired) SIGNAL_HANDLER - settle_passives(source) + update_failing() + +/// Read our own failure sources: organ healing can clear the shared failing bit mid-reboot. +/datum/component/cyberware/proc/is_running() + var/obj/item/organ/ware = parent + return !QDELETED(ware) && ware.owner && !browned_out && !emp_down && ware.damage < ware.maxHealth && !(ware.organ_flags & ORGAN_FAILING) // ---- Install context --------------------------------------------------- // Cyberware refuses Insert() outside a legit context: organ-manipulation @@ -243,20 +249,86 @@ if(organ.GetComponent(/datum/component/cyberware)) . += organ -/// Chrome load of a single organ; 0 for anything that isn't chrome. +/// Compatibility helper for callers quoting an organ's installed load. /proc/get_organ_chrome_load(obj/item/organ/ware) - var/datum/component/cyberware/chrome = ware?.GetComponent(/datum/component/cyberware) - return chrome ? chrome.chrome_load : 0 + return get_installed_capacity_cost(ware) + +/// All non-chrome costs. Ordinary anatomy is free; chrome retains its component's cost. +GLOBAL_LIST_INIT(installed_capacity_costs, list( + "implant" = 1, + "robotic_organ" = 1, + "bioware" = 1, + "prosthetic_limb" = 0, +)) -/// The target's total neural load, summed live off the installed organs. +/proc/get_installed_capacity_cost(datum/installed) + if(QDELETED(installed)) + return 0 + if(isorgan(installed)) + var/obj/item/organ/organ = installed + var/datum/component/cyberware/chrome = organ.GetComponent(/datum/component/cyberware) + if(chrome) + return chrome.chrome_load + return (IS_ROBOTIC_ORGAN(organ) || istype(organ, /obj/item/organ/cyberimp)) ? GLOB.installed_capacity_costs["robotic_organ"] : 0 + if(istype(installed, /obj/item/implant)) + return GLOB.installed_capacity_costs["implant"] + if(istype(installed, /datum/status_effect/bioware)) + return GLOB.installed_capacity_costs["bioware"] + if(istype(installed, /obj/item/bodypart)) + return GLOB.installed_capacity_costs["prosthetic_limb"] + if(istype(installed, /datum/nanite_program)) + var/datum/nanite_program/program = installed + return program.capacity_cost() + return 0 + +/// A set of installed objects, so chrome never also counts as a generic robotic organ. +/proc/get_installed_capacity_items(mob/living/carbon/target) + var/list/installed = list() + if(!iscarbon(target)) + return installed + installed |= target.organs + if(target.implants) + installed |= target.implants + installed |= target.bodyparts + for(var/datum/status_effect/bioware/enhancement in target.status_effects) + installed |= enhancement + var/datum/component/nanites/nanites = target.GetComponent(/datum/component/nanites) + if(nanites && !QDELETED(nanites)) + installed |= nanites.programs + return installed + +/// Check the complete resulting body before mutating it. Removal and load-neutral recovery stay possible. +/proc/installed_capacity_check(mob/living/carbon/target, list/additions, list/removals, silent = FALSE) + if(!iscarbon(target)) + return TRUE + var/list/projected = get_installed_capacity_items(target) + if(removals) + projected -= removals + if(additions) + projected |= additions + var/load = 0 + var/capacity = CYBERWARE_BASE_CAPACITY + var/addition_cost = 0 + for(var/datum/item in additions) + addition_cost += get_installed_capacity_cost(item) + for(var/datum/item in projected) + load += get_installed_capacity_cost(item) + if(isorgan(item)) + var/datum/component/cyberware/chrome = item.GetComponent(/datum/component/cyberware) + capacity += chrome?.capacity_bonus + if(load <= capacity || (!addition_cost && load <= get_chrome_load(target) && capacity >= get_chrome_capacity(target))) + return TRUE + if(!silent) + target.balloon_alert(target, "no neural headroom!") + return FALSE + +/// The target's total installed load, including disabled programs. /proc/get_chrome_load(mob/living/carbon/target) . = 0 if(!iscarbon(target)) return - for(var/obj/item/organ/organ in target.organs) - var/datum/component/cyberware/chrome = organ.GetComponent(/datum/component/cyberware) - if(chrome) - . += chrome.chrome_load + for(var/datum/item in get_installed_capacity_items(target)) + . += get_installed_capacity_cost(item) /// The target's chrome capacity: the body's baseline plus every installed /// ware's capacity bonus (the Governor hook). @@ -291,9 +363,9 @@ if(!iscarbon(target) || QDELETED(target)) return var/list/installed = get_installed_cyberware(target) - if(!length(installed)) - return var/over = get_chrome_load(target) > get_chrome_capacity(target) + var/datum/component/nanites/nanites = target.GetComponent(/datum/component/nanites) + nanites?.settle_capacity(over) var/newly_tripped = FALSE var/any_recovered = FALSE for(var/obj/item/organ/ware as anything in installed) @@ -306,7 +378,7 @@ any_recovered = TRUE if(newly_tripped) target.balloon_alert(target, "chrome brownout!") - to_chat(target, span_boldwarning("Your chrome browns out. Too much load on the wetware. Shed some ware to bring it back.")) + to_chat(target, span_boldwarning("Your chrome goes dark.")) do_sparks(2, TRUE, target) else if(any_recovered) target.balloon_alert(target, "chrome back online") diff --git a/voidcrew/modules/cyberware/ripperdoc_catalog.dm b/voidcrew/modules/cyberware/ripperdoc_catalog.dm index b7b379946ef..ff4f0506e45 100644 --- a/voidcrew/modules/cyberware/ripperdoc_catalog.dm +++ b/voidcrew/modules/cyberware/ripperdoc_catalog.dm @@ -389,7 +389,7 @@ /datum/shop_sku/ripperdoc/governor_delete category = "Legend Chrome" - desc = "Firmware surgery. Your capacity governor goes back in believing your spine can carry six more points of load, and it holds. Everything else on this shelf needs it." + desc = "A factory neural governor with its limiter firmware stripped out." item_path = /obj/item/organ/cyberimp/cyberware/governor_delete price_vouchers = 5 stock_min = 1 diff --git a/voidcrew/modules/cyberware/ware_legend.dm b/voidcrew/modules/cyberware/ware_legend.dm index 856c4306d2c..acfc6943157 100644 --- a/voidcrew/modules/cyberware/ware_legend.dm +++ b/voidcrew/modules/cyberware/ware_legend.dm @@ -576,10 +576,10 @@ // ========================================================================= /** - * # Governor Delete (T4, head, governor slot, load 0, +6 capacity) + * # Governor Delete (T4, chest OS, load 0, +15 capacity) * * The enabler: a neural governor with its limiter firmware deleted, worth - * six points of chrome capacity and nothing else. Deliberately built on the + * fifteen points of capacity and nothing else. Deliberately built on the * generic chrome base rather than tg's brain-implant subtype, the brain * base answers EMP with a 200/severity stun, which on a PvP server would * turn a one-voucher grenade into an execution button. Here it browns out @@ -587,13 +587,13 @@ */ /obj/item/organ/cyberimp/cyberware/governor_delete name = "\improper Governor Delete" - desc = "A factory neural governor with the governing part surgically removed. It tells your nervous system it has six more points of headroom than it really does, and your nervous system believes it." + desc = "A factory neural governor with its limiter firmware stripped out." icon_state = "governor_delete" - zone = BODY_ZONE_HEAD - slot = ORGAN_SLOT_CYBERWARE_GOVERNOR + zone = BODY_ZONE_CHEST + slot = ORGAN_SLOT_CYBERWARE_OS w_class = WEIGHT_CLASS_SMALL chrome_load = 0 - chrome_capacity_bonus = 6 + chrome_capacity_bonus = 15 tier = CYBERWARE_TIER_4 // ========================================================================= diff --git a/voidcrew/modules/cyberware/ware_military_body.dm b/voidcrew/modules/cyberware/ware_military_body.dm index 8bd9840fb15..66cd60b4e75 100644 --- a/voidcrew/modules/cyberware/ware_military_body.dm +++ b/voidcrew/modules/cyberware/ware_military_body.dm @@ -294,6 +294,8 @@ tier = CYBERWARE_TIER_3 /// TRUE during the one-second windup. var/jolting = FALSE + /// Changes on every windup/cancellation; old callbacks cannot spend a new installation's charge. + var/jolt_generation = 0 /// The once-per-six-minutes clock. COOLDOWN_DECLARE(jolt_cooldown) @@ -312,6 +314,12 @@ . = ..() UnregisterSignal(organ_owner, COMSIG_MOB_STATCHANGE) jolting = FALSE + jolt_generation++ + +/obj/item/organ/cyberimp/cyberware/lazarus/chrome_passives_off(mob/living/carbon/bearer) + . = ..() + jolting = FALSE + jolt_generation++ /** * Signal proc for [COMSIG_MOB_STATCHANGE]: fires the windup on the @@ -322,7 +330,8 @@ SIGNAL_HANDLER if(jolting) return - if(organ_flags & ORGAN_FAILING) + var/datum/component/cyberware/chrome = GetComponent(/datum/component/cyberware) + if(source != owner || !chrome?.is_running()) return if(new_stat == CONSCIOUS || new_stat == DEAD) return @@ -331,7 +340,7 @@ if(!COOLDOWN_FINISHED(src, jolt_cooldown)) return jolting = TRUE - COOLDOWN_START(src, jolt_cooldown, CYBERWARE_LAZARUS_COOLDOWN) + jolt_generation++ source.visible_message( span_boldwarning("[source] seizes, something under [source.p_their()] ribs whines up to full charge!"), span_userdanger("The Lazarus node screams up to charge..."), @@ -339,20 +348,26 @@ playsound(source, 'sound/machines/defib/defib_charge.ogg', 75, TRUE) source.set_jitter_if_lower(4 SECONDS) source.do_jitter_animation(200) - addtimer(CALLBACK(src, PROC_REF(jolt)), CYBERWARE_LAZARUS_WINDUP) + addtimer(CALLBACK(src, PROC_REF(jolt), jolt_generation, WEAKREF(source)), CYBERWARE_LAZARUS_WINDUP) /// The discharge: heal to 30%, clear the floor out from under every stun, /// and stand the patient up with a thunderclap. Skipped if they died (or /// recovered) during the windup, that second belongs to the attacker. -/obj/item/organ/cyberimp/cyberware/lazarus/proc/jolt() +/obj/item/organ/cyberimp/cyberware/lazarus/proc/jolt(windup_generation, datum/weakref/intended_patient) + if(!jolting || windup_generation != jolt_generation) + return jolting = FALSE - var/mob/living/carbon/patient = owner - if(QDELETED(src) || QDELETED(patient)) + var/mob/living/carbon/patient = intended_patient?.resolve() + if(QDELETED(src) || QDELETED(patient) || patient != owner) return - if(organ_flags & ORGAN_FAILING) + var/datum/component/cyberware/chrome = GetComponent(/datum/component/cyberware) + if(!chrome?.is_running()) return if(patient.stat == DEAD || patient.stat == CONSCIOUS) return + if(!COOLDOWN_FINISHED(src, jolt_cooldown)) + return + COOLDOWN_START(src, jolt_cooldown, CYBERWARE_LAZARUS_COOLDOWN) var/needed = (patient.maxHealth * CYBERWARE_LAZARUS_HEAL_TO) - patient.health if(needed > 0) var/oxy_heal = min(needed, patient.getOxyLoss()) diff --git a/voidcrew/modules/nanites/code/nanite_component.dm b/voidcrew/modules/nanites/code/nanite_component.dm index 5b0d9a2c0d4..800a13b2abf 100644 --- a/voidcrew/modules/nanites/code/nanite_component.dm +++ b/voidcrew/modules/nanites/code/nanite_component.dm @@ -36,6 +36,8 @@ var/announce_cloud_takeover = FALSE ///All nanite programs in the user var/list/datum/nanite_program/programs = list() + /// Suppress intermediate checks and brownouts while committing an already checked complete set. + var/programming_transaction = FALSE ///How many programs this user can have at once var/max_programs = NANITE_PROGRAM_LIMIT @@ -137,6 +139,7 @@ /datum/component/nanites/Destroy() STOP_PROCESSING(SSnanites, src) QDEL_LIST(programs) + cyberware_reevaluate_brownout(host_mob) if(host_mob) set_nanite_bar(TRUE) host_mob.hud_set_nanite_indicator() @@ -151,6 +154,7 @@ adjust_nanites(null, amount) //just add to the nanite volume /datum/component/nanites/process() + capacity_changed() if(!HAS_TRAIT(host_mob, TRAIT_STASIS)) adjust_nanites(null, regen_rate) for(var/datum/nanite_program/NP as anything in programs) @@ -186,11 +190,24 @@ . = NONE var/list/programs_to_remove = programs.Copy() var/list/programs_to_add = source.programs.Copy() + // Build the complete result before copying settings or deleting incumbents. for(var/datum/nanite_program/NP as anything in programs) for(var/datum/nanite_program/SNP as anything in programs_to_add) if(NP.type == SNP.type) programs_to_remove -= NP programs_to_add -= SNP + break + var/list/result = programs.Copy() + if(full_overwrite) + result -= programs_to_remove + result += programs_to_add + if(length(result) > max_programs || !programs_fit_capacity(result)) + capacity_changed() + return NONE + programming_transaction = TRUE + for(var/datum/nanite_program/NP as anything in programs) + for(var/datum/nanite_program/SNP as anything in source.programs) + if(NP.type == SNP.type) if(SNP.programming_differs(NP, copy_activation)) . |= NANITE_SYNC_REPLACED SNP.copy_programming(NP, copy_activation) @@ -202,6 +219,31 @@ for(var/datum/nanite_program/SNP as anything in programs_to_add) . |= NANITE_SYNC_ADDED add_program(null, SNP.copy()) + programming_transaction = FALSE + capacity_changed() + +/// Cloud backups have no body. Only a hosted complete result has a capacity ceiling. +/datum/component/nanites/proc/programs_fit_capacity(list/result) + if(!iscarbon(host_mob)) + return TRUE + var/load = get_chrome_load(host_mob) + for(var/datum/nanite_program/program in programs) + load -= program.capacity_cost() + for(var/datum/nanite_program/program in result) + load += program.capacity_cost() + return load <= get_chrome_capacity(host_mob) + +/datum/component/nanites/proc/capacity_changed() + if(!programming_transaction) + cyberware_reevaluate_brownout(host_mob) + +/// Only withdraw effects here; resuming uses normal processing and its fuel/condition checks. +/datum/component/nanites/proc/settle_capacity(over) + if(programming_transaction) + return + for(var/datum/nanite_program/program in programs) + if(over && program.capacity_beneficial() && program.passive_enabled) + program.disable_passive_effect() /** * Tells the host one line about what their nanites are doing. Dropped entirely when there is no @@ -246,16 +288,29 @@ /datum/component/nanites/proc/add_program(datum/source, datum/nanite_program/new_program, datum/nanite_program/source_program) SIGNAL_HANDLER - for(var/X in programs) - var/datum/nanite_program/NP = X + if(new_program in programs) + capacity_changed() + return COMPONENT_PROGRAM_INSTALLED + var/list/replaced = list() + for(var/datum/nanite_program/NP in programs) if(NP.unique && NP.type == new_program.type) - qdel(NP) - if(programs.len >= max_programs) + replaced += NP + var/list/result = programs - replaced + result += new_program + if(length(result) > max_programs) + return COMPONENT_PROGRAM_NOT_INSTALLED + if(!programming_transaction && !installed_capacity_check(host_mob, list(new_program), replaced, silent = TRUE)) return COMPONENT_PROGRAM_NOT_INSTALLED + var/was_transaction = programming_transaction + programming_transaction = TRUE + for(var/datum/nanite_program/NP in replaced) + qdel(NP) if(source_program) source_program.copy_programming(new_program) programs += new_program new_program.on_add(src) + programming_transaction = was_transaction + capacity_changed() return COMPONENT_PROGRAM_INSTALLED /datum/component/nanites/proc/consume_nanites(amount, force = FALSE) diff --git a/voidcrew/modules/nanites/code/programs/_programs.dm b/voidcrew/modules/nanites/code/programs/_programs.dm index ecc6b2f1774..8766160f419 100644 --- a/voidcrew/modules/nanites/code/programs/_programs.dm +++ b/voidcrew/modules/nanites/code/programs/_programs.dm @@ -1,3 +1,36 @@ +// Exact types are resolved before category defaults, independently of table order. +GLOBAL_LIST_INIT(nanite_program_capacity_costs, list( + /datum/nanite_program/regenerative_advanced = 6, + /datum/nanite_program/defib = 6, + /datum/nanite_program/regenerative = 3, + /datum/nanite_program/repairing = 3, + /datum/nanite_program/hardening = 3, + /datum/nanite_program/refractive = 3, + /datum/nanite_program/nervous = 3, + /datum/nanite_program/adrenaline = 3, + /datum/nanite_program/purging = 2, + /datum/nanite_program/purging_advanced = 2, + /datum/nanite_program/brain_heal_advanced = 2, + /datum/nanite_program/coagulating = 2, + /datum/nanite_program/access = 2, + /datum/nanite_program/viral = 2, + /datum/nanite_program/emp = 2, + /datum/nanite_program/spreading = 2, + /datum/nanite_program/brain_heal = 1, + /datum/nanite_program/blood_restoring = 1, + /datum/nanite_program/temperature = 1, + /datum/nanite_program/conductive = 1, + /datum/nanite_program/mindshield = 1, + /datum/nanite_program/self_scan = 1, + /datum/nanite_program/stealth = 1, + /datum/nanite_program/metabolic_synthesis = 1, + /datum/nanite_program/mitosis = 1, + /datum/nanite_program/nanite_sting = 1, + /datum/nanite_program/protocol = 1, + /datum/nanite_program/sensor = 0, + /datum/nanite_program = 0, +)) + /datum/nanite_program var/name = "Generic Nanite Program" var/desc = "Warn a coder if you can read this." @@ -82,8 +115,27 @@ on_mob_remove() if(nanites) nanites.programs -= src + nanites.capacity_changed() + nanites = null + host_mob = null return ..() +/datum/nanite_program/proc/capacity_cost() + // Walk the type tree, so a specific zero also overrides a costed category. + var/program_type = type + while(ispath(program_type, /datum/nanite_program)) + if(program_type in GLOB.nanite_program_capacity_costs) + return GLOB.nanite_program_capacity_costs[program_type] + program_type = type2parent(program_type) + return 0 + +/// Paid support programs pause on overload. Hostile payloads retain their effects. +/datum/nanite_program/proc/capacity_beneficial() + return capacity_cost() > 0 && !istype(src, /datum/nanite_program/viral) && !istype(src, /datum/nanite_program/emp) && !istype(src, /datum/nanite_program/spreading) && !istype(src, /datum/nanite_program/nanite_sting) + +/datum/nanite_program/proc/capacity_blocked() + return capacity_beneficial() && iscarbon(host_mob) && get_chrome_load(host_mob) > get_chrome_capacity(host_mob) + /datum/nanite_program/proc/copy() var/datum/nanite_program/new_program = new type() copy_programming(new_program, TRUE) @@ -213,6 +265,10 @@ timer_restart_next = world.time + timer_restart /datum/nanite_program/proc/on_process() + if(capacity_blocked()) + if(passive_enabled) + disable_passive_effect() + return if(!activated) if(timer_restart_next && world.time > timer_restart_next) activate() @@ -269,6 +325,8 @@ //Checks conditions then fires the nanite trigger effect /datum/nanite_program/proc/trigger(delayed = FALSE, comm_message) + if(capacity_blocked()) + return if(!can_trigger) return if(!activated || force_disabled) diff --git a/voidcrew/modules/unit_tests/voidcrew_cyberware.dm b/voidcrew/modules/unit_tests/voidcrew_cyberware.dm index 62fb62ba357..2bff6b77223 100644 --- a/voidcrew/modules/unit_tests/voidcrew_cyberware.dm +++ b/voidcrew/modules/unit_tests/voidcrew_cyberware.dm @@ -46,6 +46,12 @@ slot = "voidcrew_test_chrome_ladder" chrome_load = 20 // fits ONLY because the mk1 nets out +// A later insertion gate refusing after the Cradle's projected check passed. +/obj/item/organ/cyberimp/cyberware/test_ladder_high/refused/Insert(mob/living/carbon/receiver, special = FALSE, movement_flags) + if(!special) + return FALSE + return ..() + /obj/item/organ/cyberimp/cyberware/test_heavy name = "test heavy chrome" zone = BODY_ZONE_CHEST @@ -330,6 +336,98 @@ TEST_ASSERT(paired["vouchers"] > 0, "[half] indexed with no voucher price") TEST_ASSERT(paired["paired"], "[half] came out of a pair case without the paired flag") +/// Recheck the complete final installation after the delay, before touching incumbents. +/datum/unit_test/voidcrew_cradle_installed_capacity + +/datum/unit_test/voidcrew_cradle_installed_capacity/Run() + var/obj/machinery/chrome_cradle/rig = allocate(/obj/machinery/chrome_cradle) + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + rig.buckle_mob(patient, force = TRUE) + var/obj/item/organ/cyberimp/cyberware/test_ladder_low/incumbent = allocate(/obj/item/organ/cyberimp/cyberware/test_ladder_low) + var/obj/item/organ/cyberimp/cyberware/test_small/extra = allocate(/obj/item/organ/cyberimp/cyberware/test_small) + var/obj/item/organ/cyberimp/cyberware/test_ladder_high/upgrade = allocate(/obj/item/organ/cyberimp/cyberware/test_ladder_high) + TEST_ASSERT(incumbent.Insert(patient, TRUE), "Cradle incumbent fixture failed") + TEST_ASSERT(extra.Insert(patient, TRUE), "Cradle extra-load fixture failed") + patient.put_in_hands(upgrade) + rig.begin_install(upgrade) + TEST_ASSERT(!rig.busy, "Cradle began an over-budget sequence") + TEST_ASSERT_EQUAL(upgrade.loc, patient, "Initial refusal moved the incoming ware") + TEST_ASSERT_EQUAL(incumbent.owner, patient, "Initial refusal evicted the incumbent") + extra.Remove(patient, TRUE) + rig.begin_install(upgrade) + TEST_ASSERT(rig.busy && rig.busy_ware == upgrade, "Fitting upgrade didn't begin its sequence") + TEST_ASSERT_EQUAL(incumbent.owner, patient, "Beginning the sequence evicted the incumbent") + // An implanter can add load while the patient is sedated. + var/obj/item/implant/voidcrew_capacity_test/implant = allocate(/obj/item/implant/voidcrew_capacity_test) + TEST_ASSERT(implant.implant(patient), "Mid-sequence implantation fixture failed") + rig.finish_install() + TEST_ASSERT_EQUAL(incumbent.owner, patient, "Post-delay capacity refusal evicted the incumbent") + TEST_ASSERT(!QDELETED(incumbent) && !QDELETED(upgrade), "Post-delay refusal consumed an organ") + TEST_ASSERT(!upgrade.owner && upgrade.loc == rig && (upgrade in rig.tray), "Rejected incoming ware wasn't preserved in the tray") + TEST_ASSERT_EQUAL(get_chrome_load(patient), 19, "Rejected sequence changed installed load") + TEST_ASSERT(!rig.busy && !patient.IsUnconscious(), "Rejected sequence didn't clear the cycle and sedation") + implant.removed(patient) + // Even a refusal by a later Insert() gate must restore the old piece. + var/obj/item/organ/cyberimp/cyberware/test_ladder_high/refused/late_refusal = allocate(/obj/item/organ/cyberimp/cyberware/test_ladder_high/refused) + late_refusal.forceMove(rig) + rig.begin_install(late_refusal) + TEST_ASSERT(rig.busy, "Late-refusal fixture failed its projected check") + rig.finish_install() + TEST_ASSERT_EQUAL(incumbent.owner, patient, "Insertion refusal didn't restore the incumbent") + TEST_ASSERT(!(incumbent in rig.tray), "Restored incumbent remained in the parts tray") + TEST_ASSERT(!late_refusal.owner && late_refusal.loc == rig && (late_refusal in rig.tray), "Insertion refusal lost the incoming ware") + TEST_ASSERT_EQUAL(get_chrome_load(patient), 18, "Rollback changed the original installed load") + // Retry after shedding load: net the old piece out rather than summing both. + rig.begin_install(upgrade) + rig.finish_install() + TEST_ASSERT_EQUAL(upgrade.owner, patient, "Fitting Cradle replacement was refused") + TEST_ASSERT(!incumbent.owner && incumbent.loc == rig && (incumbent in rig.tray), "Successful replacement didn't rack its incumbent") + TEST_ASSERT_EQUAL(get_chrome_load(patient), 20, "Cradle replacement didn't net the incumbent") + upgrade.Remove(patient, TRUE) + TEST_ASSERT(incumbent.Insert(patient, TRUE), "Governor-loss incumbent fixture failed") + var/obj/item/organ/cyberimp/cyberware/governor_delete/governor = allocate(/obj/item/organ/cyberimp/cyberware/governor_delete) + governor.Insert(patient, TRUE) + implant.implant(patient) + upgrade.forceMove(rig) + rig.begin_install(upgrade) + TEST_ASSERT(rig.busy, "Governor-backed replacement didn't begin") + governor.Remove(patient, TRUE) + rig.finish_install() + TEST_ASSERT_EQUAL(incumbent.owner, patient, "Losing a Governor during the delay evicted the incumbent") + TEST_ASSERT_EQUAL(get_chrome_capacity(patient), 20, "Cradle retained the removed Governor's bonus") + TEST_ASSERT(!upgrade.owner && (upgrade in rig.tray), "Governor-loss refusal lost the incoming ware") + // A Governor-for-Governor swap must fit the exact 35 boundary. + implant.removed(patient) + incumbent.Remove(patient, TRUE) + governor.Insert(patient, TRUE) + upgrade.Insert(patient, TRUE) + var/obj/item/organ/cyberimp/cyberware/test_heavy/heavy = allocate(/obj/item/organ/cyberimp/cyberware/test_heavy) + heavy.Insert(patient, TRUE) + var/obj/item/organ/cyberimp/cyberware/governor_delete/new_governor = allocate(/obj/item/organ/cyberimp/cyberware/governor_delete) + new_governor.forceMove(rig) + rig.begin_install(new_governor) + TEST_ASSERT(rig.busy, "Governor replacement at 35 failed its projected check") + rig.finish_install() + TEST_ASSERT_EQUAL(new_governor.owner, patient, "Cradle rejected a netted Governor replacement at 35") + TEST_ASSERT(!governor.owner && (governor in rig.tray), "Successful Governor replacement didn't rack the old Governor") + TEST_ASSERT_EQUAL(get_chrome_capacity(patient), 35, "Governor replacement changed capacity") + TEST_ASSERT_EQUAL(get_chrome_load(patient), 35, "Governor replacement changed installed load") + +/datum/unit_test/voidcrew_cradle_generic_projection + +/datum/unit_test/voidcrew_cradle_generic_projection/Run() + var/obj/machinery/chrome_cradle/rig = allocate(/obj/machinery/chrome_cradle) + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + var/obj/item/organ/cyberimp/cyberware/test_nineteen/bulk = allocate(/obj/item/organ/cyberimp/cyberware/test_nineteen) + var/obj/item/organ/eyes/robotic/incumbent = allocate(/obj/item/organ/eyes/robotic) + var/obj/item/organ/eyes/robotic/cyberware/nightshade/optics = allocate(/obj/item/organ/eyes/robotic/cyberware/nightshade) + bulk.Insert(patient, TRUE) + incumbent.Insert(patient, TRUE) + rig.selected_ware = optics + var/list/projection = rig.build_projection(patient, "carried") + TEST_ASSERT_EQUAL(projection["load"], 20, "Cradle projection didn't net out generic robotic eyes") + TEST_ASSERT_EQUAL(get_chrome_load(patient), 20, "Building a Cradle projection changed the body") + /// (i) Gecko Grips: the clamp is a refusal of the involuntary drop itself, so /// what it does and does not refuse is the whole ware. Everything below is a /// real drop attempt rather than a state check, because the failure this @@ -621,20 +719,408 @@ TEST_ASSERT(!(mesh.organ_flags & ORGAN_FAILING), "A tune-up didn't bring the EMP'd ware back online") TEST_ASSERT_EQUAL(lab_rat.physiology.armor.get_rating(MELEE), plated, "Repaired chrome didn't hand its plating back") - // One pulse, then the capacitors have to vent. Both pulses below land in - // the same tick, so the shortened recharge can't finish between them; it - // is shortened only so the recharge timer doesn't outlive the test. + // Protection and notification must have distinct signals. The first pulse + // is absorbed; the next one arrives before the one-minute recharge. + TEST_ASSERT(COMSIG_ATOM_PRE_EMP_ACT != COMSIG_ATOM_EMP_ACT, "EMP protection collides with EMP notification") var/obj/item/organ/heart/cybernetic/anomalock/prebuilt/shield = allocate(/obj/item/organ/heart/cybernetic/anomalock/prebuilt) - shield.emp_absorb_cooldown_time = 1 + TEST_ASSERT_EQUAL(shield.emp_absorb_cooldown_time, 1 MINUTES, "Voltaic recharge changed") TEST_ASSERT(shield.Insert(lab_rat, special = TRUE), "Test fixture: Voltaic cyberheart staging insert was refused") lab_rat.emp_act(EMP_HEAVY) TEST_ASSERT(!(mesh.organ_flags & ORGAN_FAILING), "The Voltaic cyberheart didn't absorb the first pulse") + TEST_ASSERT_EQUAL(COOLDOWN_TIMELEFT(shield, emp_absorb_cooldown), 1 MINUTES, "Absorption didn't start the one-minute recharge") lab_rat.emp_act(EMP_HEAVY) TEST_ASSERT(mesh.organ_flags & ORGAN_FAILING, "The Voltaic cyberheart ate a second pulse on drained capacitors. It must only ever cover one") + chrome.tune_up() + // Advance only the charge clock, without sleeping through a minute of world processing. + shield.emp_absorb_cooldown = world.time + lab_rat.emp_act(EMP_HEAVY) + TEST_ASSERT(chrome.is_running(), "A recharged Voltaic heart failed to absorb another pulse") // Pulling the core first: a cored heart tesla-zaps the room on removal, // and teardown removes it. QDEL_NULL(shield.core) +/// Non-chrome fixtures use production installation hooks and costs. +/obj/item/organ/cyberimp/cyberware/test_nineteen + zone = BODY_ZONE_CHEST + slot = "voidcrew_test_chrome_bulk" + chrome_load = 19 + +/obj/item/implant/voidcrew_capacity_test + allow_multiple = TRUE + +/datum/unit_test/voidcrew_installed_capacity_mixed + +/datum/unit_test/voidcrew_installed_capacity_mixed/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + TEST_ASSERT_EQUAL(get_chrome_load(patient), 0, "Organic anatomy costs capacity") + var/obj/item/organ/cyberimp/cyberware/test_heavy/chrome = allocate(/obj/item/organ/cyberimp/cyberware/test_heavy) + var/obj/item/organ/cyberimp/brain/anti_drop/implant_organ = allocate(/obj/item/organ/cyberimp/brain/anti_drop) + var/obj/item/organ/heart/cybernetic/heart = allocate(/obj/item/organ/heart/cybernetic) + var/obj/item/implant/voidcrew_capacity_test/implant = allocate(/obj/item/implant/voidcrew_capacity_test) + TEST_ASSERT(chrome.Insert(patient, TRUE), "Chrome fixture failed") + TEST_ASSERT(implant_organ.Insert(patient), "TG cyber implant failed") + TEST_ASSERT(heart.Insert(patient), "Robotic heart failed") + TEST_ASSERT(implant.implant(patient), "Implant fixture failed") + var/datum/status_effect/bioware/nerves/grounded/bioware = patient.apply_status_effect(/datum/status_effect/bioware/nerves/grounded) + TEST_ASSERT(bioware, "Bioware fixture failed") + var/datum/component/nanites/nanites = patient.AddComponent(/datum/component/nanites) + var/datum/nanite_program/protocol/kickstart/protocol = allocate(/datum/nanite_program/protocol/kickstart) + protocol.activated = FALSE + TEST_ASSERT_EQUAL(nanites.add_program(null, protocol), 1, "Protocol fixture failed") // COMPONENT_PROGRAM_INSTALLED + TEST_ASSERT_EQUAL(get_chrome_load(patient), 20, "Mixed installed sources weren't counted exactly once") + TEST_ASSERT(!(chrome.organ_flags & ORGAN_FAILING), "The exact 20 boundary browned out") + var/obj/item/bodypart/arm/left/robot/arm = allocate(/obj/item/bodypart/arm/left/robot) + TEST_ASSERT(arm.replace_limb(patient, TRUE), "Free prosthetic failed at capacity") + TEST_ASSERT_EQUAL(get_chrome_load(patient), 20, "Prosthetic limb costs capacity") + // Generic replacements net the incumbent before upstream can delete it. + var/obj/item/organ/heart/cybernetic/replacement = allocate(/obj/item/organ/heart/cybernetic) + TEST_ASSERT(replacement.Insert(patient, FALSE, DELETE_IF_REPLACED), "Netted robotic-organ replacement failed at 20") + TEST_ASSERT(QDELETED(heart), "Successful replacement didn't follow DELETE_IF_REPLACED") + TEST_ASSERT_EQUAL(get_chrome_load(patient), 20, "Robotic-organ replacement double-counted") + var/obj/item/implant/voidcrew_capacity_test/refused = allocate(/obj/item/implant/voidcrew_capacity_test) + var/atom/old_location = refused.loc + TEST_ASSERT(!refused.implant(patient), "Over-budget implant was accepted") + TEST_ASSERT(!QDELETED(refused) && !refused.imp_in && refused.loc == old_location, "Rejected implantation consumed or moved the item") + var/stun_mod = patient.physiology.stun_mod + TEST_ASSERT(!patient.apply_status_effect(/datum/status_effect/bioware/ligaments/reinforced), "Over-budget bioware was accepted") + TEST_ASSERT_EQUAL(patient.physiology.stun_mod, stun_mod, "Rejected bioware changed physiology") + qdel(protocol) + TEST_ASSERT_EQUAL(get_chrome_load(patient), 19, "Program deletion didn't release capacity") + TEST_ASSERT(refused.implant(patient), "Released capacity didn't allow implantation") + implant.removed(patient) + TEST_ASSERT_EQUAL(get_chrome_load(patient), 19, "Implant removal didn't release capacity") + +/datum/unit_test/voidcrew_installed_capacity_rejections + +/datum/unit_test/voidcrew_installed_capacity_rejections/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + var/obj/item/organ/cyberimp/cyberware/test_full_body/bulk = allocate(/obj/item/organ/cyberimp/cyberware/test_full_body) + bulk.Insert(patient, TRUE) + var/obj/item/organ/heart/incumbent = patient.get_organ_slot(ORGAN_SLOT_HEART) + var/obj/item/organ/heart/cybernetic/refused = allocate(/obj/item/organ/heart/cybernetic) + var/atom/old_location = refused.loc + TEST_ASSERT(!refused.Insert(patient, FALSE, DELETE_IF_REPLACED), "Robotic heart was installed over capacity") + TEST_ASSERT_EQUAL(patient.get_organ_slot(ORGAN_SLOT_HEART), incumbent, "Rejected replacement removed the incumbent") + TEST_ASSERT(!QDELETED(incumbent) && !QDELETED(refused), "Rejected replacement deleted an organ") + TEST_ASSERT_EQUAL(refused.loc, old_location, "Rejected replacement moved the new organ") + TEST_ASSERT(!patient.apply_status_effect(/datum/status_effect/bioware/nerves/spliced), "Bioware was applied over capacity") + TEST_ASSERT_EQUAL(patient.physiology.stun_mod, 1, "Refused bioware ran its removal effect without applying") + // An attached limb can carry installed organs, even though the limb itself is free. + var/obj/item/bodypart/arm/left/robot/arm = allocate(/obj/item/bodypart/arm/left/robot) + var/obj/item/organ/cyberimp/cyberware/test_arm/packed = allocate(/obj/item/organ/cyberimp/cyberware/test_arm) + packed.bodypart_insert(arm) + var/obj/item/bodypart/original_arm = patient.get_bodypart(BODY_ZONE_L_ARM) + TEST_ASSERT(!arm.replace_limb(patient, TRUE), "A loaded prosthetic bypassed capacity") + TEST_ASSERT_EQUAL(patient.get_bodypart(BODY_ZONE_L_ARM), original_arm, "Rejected prosthetic replacement detached the original limb") + TEST_ASSERT_EQUAL(packed.loc, arm, "Rejected prosthetic lost its organ") + TEST_ASSERT(!QDELETED(arm) && !QDELETED(packed), "Rejected prosthetic replacement consumed items") + // Net a generic robotic eye out when replacing it with chrome optics. + bulk.Remove(patient, TRUE) + var/obj/item/organ/cyberimp/cyberware/test_nineteen/nineteen = allocate(/obj/item/organ/cyberimp/cyberware/test_nineteen) + nineteen.Insert(patient, TRUE) + var/obj/item/organ/eyes/robotic/robotic_eyes = allocate(/obj/item/organ/eyes/robotic) + TEST_ASSERT(robotic_eyes.Insert(patient), "Generic eye fixture failed") + var/obj/item/organ/eyes/robotic/cyberware/nightshade/optics = allocate(/obj/item/organ/eyes/robotic/cyberware/nightshade) + var/datum/component/cyberware/optics_chrome = optics.GetComponent(/datum/component/cyberware) + optics_chrome.grant_install_context(patient) + TEST_ASSERT(optics.Insert(patient), "Chrome replacement didn't net out generic robotic eyes") + TEST_ASSERT_EQUAL(get_chrome_load(patient), 20, "Chrome optics counted as both chrome and robotic anatomy") + +/// Capacity can change between surgery's preop check and its insertion step. +/datum/unit_test/voidcrew_surgery_capacity_recheck + +/datum/unit_test/voidcrew_surgery_capacity_recheck/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + var/mob/living/carbon/human/surgeon = allocate(/mob/living/carbon/human/consistent) + var/obj/item/organ/cyberimp/cyberware/test_nineteen/bulk = allocate(/obj/item/organ/cyberimp/cyberware/test_nineteen) + var/obj/item/organ/cyberimp/cyberware/test_small/extra = allocate(/obj/item/organ/cyberimp/cyberware/test_small) + bulk.Insert(patient, TRUE) + var/obj/item/organ/cyberimp/brain/anti_drop/implant = allocate(/obj/item/organ/cyberimp/brain/anti_drop) + surgeon.put_in_hands(implant) + TEST_ASSERT(implant.pre_surgical_insertion(surgeon, patient, BODY_ZONE_HEAD), "Surgical capacity fixture didn't initially fit") + extra.Insert(patient, TRUE) + var/datum/surgery_step/manipulate_organs/step = allocate(/datum/surgery_step/manipulate_organs) + step.current_type = "insert" + step.target_organ = implant + TEST_ASSERT_EQUAL(step.success(surgeon, patient, BODY_ZONE_HEAD, implant, null), SURGERY_STEP_FAIL, "Surgery didn't recheck capacity after its delay") + TEST_ASSERT(surgeon.is_holding(implant), "Late surgical refusal unequipped the new organ") + TEST_ASSERT(!QDELETED(implant) && !implant.owner, "Late surgical refusal consumed or installed the organ") + +/datum/unit_test/voidcrew_governor_capacity + +/datum/unit_test/voidcrew_governor_capacity/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + var/obj/item/organ/cyberimp/cyberware/governor_delete/governor = allocate(/obj/item/organ/cyberimp/cyberware/governor_delete) + TEST_ASSERT_EQUAL(governor.zone, BODY_ZONE_CHEST, "Governor isn't chest hardware") + for(var/os_type in list(/obj/item/organ/cyberimp/cyberware/cascade, /obj/item/organ/cyberimp/cyberware/redline)) + var/obj/item/organ/os = os_type + TEST_ASSERT_EQUAL(governor.slot, initial(os.slot), "Governor doesn't share the OS slot with [os_type]") + TEST_ASSERT(governor.Insert(patient, TRUE), "Governor fixture failed") + TEST_ASSERT_EQUAL(get_chrome_capacity(patient), 35, "Governor must yield 35 capacity") + var/obj/item/organ/cyberimp/cyberware/test_full_body/bulk = allocate(/obj/item/organ/cyberimp/cyberware/test_full_body) + var/obj/item/organ/cyberimp/cyberware/test_heavy/heavy = allocate(/obj/item/organ/cyberimp/cyberware/test_heavy) + bulk.Insert(patient, TRUE) + heavy.Insert(patient, TRUE) + TEST_ASSERT_EQUAL(get_chrome_load(patient), 35, "35 boundary fixture is wrong") + var/datum/component/cyberware/heavy_chrome = heavy.GetComponent(/datum/component/cyberware) + TEST_ASSERT(heavy_chrome.is_running(), "35/35 browned out") + var/obj/item/organ/cyberimp/cyberware/test_small/extra = allocate(/obj/item/organ/cyberimp/cyberware/test_small) + TEST_ASSERT(!cyberware_insert_check(extra, patient, TRUE), "36/35 passed the capacity gate") + var/obj/item/organ/cyberimp/cyberware/governor_delete/replacement = allocate(/obj/item/organ/cyberimp/cyberware/governor_delete) + var/datum/component/cyberware/replacement_chrome = replacement.GetComponent(/datum/component/cyberware) + replacement_chrome.grant_install_context(patient) + TEST_ASSERT(replacement.Insert(patient), "Governor replacement double-counted its bonus") + var/obj/item/organ/cyberimp/cyberware/cascade/cascade = allocate(/obj/item/organ/cyberimp/cyberware/cascade) + TEST_ASSERT(!cyberware_insert_check(cascade, patient, TRUE), "OS replacement kept the evicted Governor's capacity") + TEST_ASSERT_EQUAL(replacement.owner, patient, "Rejected OS replacement evicted the Governor") + replacement.Remove(patient, TRUE) + TEST_ASSERT_EQUAL(get_chrome_capacity(patient), 20, "Governor removal retained its bonus") + TEST_ASSERT(!heavy_chrome.is_running(), "Capacity loss didn't brown out chrome") + heavy.Remove(patient, TRUE) + var/datum/component/cyberware/bulk_chrome = bulk.GetComponent(/datum/component/cyberware) + TEST_ASSERT(bulk_chrome.is_running(), "Removal didn't recover chrome at 20") + bulk.Remove(patient, TRUE) + TEST_ASSERT(cascade.Insert(patient, TRUE), "OS fixture failed") + TEST_ASSERT(governor.Insert(patient, TRUE), "Governor couldn't replace an OS") + TEST_ASSERT(!cascade.owner && governor.owner == patient, "Chest OS hardware stacked") + +/// Every approved exception is checked independently of the table under test. +/datum/unit_test/voidcrew_nanite_capacity_costs + +/datum/unit_test/voidcrew_nanite_capacity_costs/Run() + var/list/cost_groups = list( + list(/datum/nanite_program/regenerative_advanced, /datum/nanite_program/defib), + list(/datum/nanite_program/regenerative, /datum/nanite_program/repairing, /datum/nanite_program/hardening, /datum/nanite_program/refractive, /datum/nanite_program/nervous, /datum/nanite_program/adrenaline), + list(/datum/nanite_program/purging, /datum/nanite_program/purging_advanced, /datum/nanite_program/brain_heal_advanced, /datum/nanite_program/coagulating, /datum/nanite_program/access, /datum/nanite_program/viral, /datum/nanite_program/emp, /datum/nanite_program/spreading), + list(/datum/nanite_program/brain_heal, /datum/nanite_program/blood_restoring, /datum/nanite_program/temperature, /datum/nanite_program/conductive, /datum/nanite_program/mindshield, /datum/nanite_program/self_scan, /datum/nanite_program/stealth, /datum/nanite_program/metabolic_synthesis, /datum/nanite_program/mitosis, /datum/nanite_program/nanite_sting), + list(/datum/nanite_program/relay, /datum/nanite_program/dermal_button, /datum/nanite_program/sensor/repeat, /datum/nanite_program/sensor/relay_repeat, /datum/nanite_program/reduced_diagnostics, /datum/nanite_program/monitoring, /datum/nanite_program/poison, /datum/nanite_program/glitch, /datum/nanite_program/paralyzing), + ) + var/list/costs = list(6, 3, 2, 1, 0) + for(var/index in 1 to length(cost_groups)) + for(var/program_type in cost_groups[index]) + var/datum/nanite_program/program = allocate(program_type) + TEST_ASSERT_EQUAL(program.capacity_cost(), costs[index], "Wrong capacity for [program_type]") + program.activated = FALSE + program.force_disabled = TRUE + TEST_ASSERT_EQUAL(program.capacity_cost(), costs[index], "Disabling [program_type] made it free") + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + var/datum/component/nanites/nanites = patient.AddComponent(/datum/component/nanites) + for(var/program_type in subtypesof(/datum/nanite_program/protocol)) + var/datum/nanite_program/protocol/program = allocate(program_type) + program.activated = FALSE + program.force_disabled = TRUE + TEST_ASSERT_EQUAL(nanites.add_program(null, program), 1, "Protocol installation failed") + TEST_ASSERT_EQUAL(get_chrome_load(patient), length(subtypesof(/datum/nanite_program/protocol)), "Inactive/exclusive protocols were free") + var/datum/nanite_program/defib/old_program = allocate(/datum/nanite_program/defib) + old_program.activated = FALSE + TEST_ASSERT_EQUAL(nanites.add_program(null, old_program), 1, "Disabled program installation failed") + var/old_load = get_chrome_load(patient) + var/datum/nanite_program/defib/new_program = allocate(/datum/nanite_program/defib) + TEST_ASSERT_EQUAL(nanites.add_program(null, new_program), 1, "Netted nanite replacement failed") + TEST_ASSERT(QDELETED(old_program), "Replaced program survived") + TEST_ASSERT_EQUAL(get_chrome_load(patient), old_load, "Nanite replacement doubled its cost") + var/obj/item/organ/cyberimp/cyberware/test_full_body/bulk = allocate(/obj/item/organ/cyberimp/cyberware/test_full_body) + bulk.Insert(patient, TRUE) + var/datum/nanite_program/defib/refused = allocate(/datum/nanite_program/defib) + refused.activation_code = 42 + TEST_ASSERT_EQUAL(nanites.add_program(null, refused), 2, "Over-budget replacement was accepted") + TEST_ASSERT(!QDELETED(new_program) && new_program in nanites.programs, "Rejected replacement deleted its incumbent") + TEST_ASSERT(!QDELETED(refused) && !refused.nanites, "Rejected replacement consumed the new program") + // A different paid program cannot consume an over-budget body's remaining programming. + var/datum/nanite_program/hardening/rejected = allocate(/datum/nanite_program/hardening) + TEST_ASSERT_EQUAL(nanites.add_program(null, rejected), 2, "Over-budget nanite installation succeeded") // COMPONENT_PROGRAM_NOT_INSTALLED + TEST_ASSERT(!QDELETED(rejected) && !rejected.nanites, "Rejected nanite program was consumed") + TEST_ASSERT(new_program in nanites.programs, "Rejected nanite install removed existing programming") + +/datum/unit_test/voidcrew_nanite_capacity_sync + +/datum/unit_test/voidcrew_nanite_capacity_sync/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + var/obj/item/organ/cyberimp/cyberware/test_heavy/heavy = allocate(/obj/item/organ/cyberimp/cyberware/test_heavy) + heavy.Insert(patient, TRUE) + var/datum/component/nanites/nanites = patient.AddComponent(/datum/component/nanites) + var/datum/nanite_program/hardening/incumbent = allocate(/datum/nanite_program/hardening) + var/datum/nanite_program/brain_heal/shared = allocate(/datum/nanite_program/brain_heal) + nanites.add_program(null, incumbent) + nanites.add_program(null, shared) + shared.activation_code = 12 + shared.activated = FALSE + var/obj/machinery/computer/nanite_cloud_controller/controller = allocate(/obj/machinery/computer/nanite_cloud_controller) + var/datum/nanite_cloud_backup/backup = allocate(/datum/nanite_cloud_backup, controller) + var/datum/component/nanites/cloud = backup.AddComponent(/datum/component/nanites) + backup.nanites = cloud + var/datum/nanite_program/brain_heal/cloud_shared = allocate(/datum/nanite_program/brain_heal) + cloud_shared.activation_code = 34 + var/datum/nanite_program/nervous/cloud_new = allocate(/datum/nanite_program/nervous) + cloud.add_program(null, cloud_new) + cloud.add_program(null, cloud_shared) + var/list/excess = list() + for(var/program_type in list(/datum/nanite_program/defib, /datum/nanite_program/regenerative_advanced, /datum/nanite_program/repairing, /datum/nanite_program/hardening)) + var/datum/nanite_program/program = allocate(program_type) + TEST_ASSERT_EQUAL(cloud.add_program(null, program), 1, "Hostless backup was capacity-limited") + excess += program + TEST_ASSERT(cloud.programs_fit_capacity(cloud.programs), "Hostless cloud has a body capacity") + TEST_ASSERT_EQUAL(nanites.sync_programming(cloud, TRUE, TRUE), 0, "Over-budget cloud sync changed the body") + TEST_ASSERT(incumbent in nanites.programs, "Rejected cloud sync deleted an incumbent") + TEST_ASSERT_EQUAL(shared.activation_code, 12, "Rejected cloud sync copied settings") + TEST_ASSERT(!shared.activated, "Rejected cloud sync copied activation") + TEST_ASSERT_EQUAL(length(nanites.programs), 2, "Rejected cloud sync partially installed programs") + for(var/datum/nanite_program/program in excess) + qdel(program) + TEST_ASSERT(nanites.sync_programming(cloud), "Fitting cloud sync didn't commit") + TEST_ASSERT(QDELETED(incumbent), "Committed cloud sync didn't remove old programming") + TEST_ASSERT_EQUAL(shared.activation_code, 34, "Committed cloud sync didn't copy settings") + TEST_ASSERT_EQUAL(get_chrome_load(patient), 19, "Cloud sync didn't net its complete replacement set") + var/datum/component/cyberware/chrome = heavy.GetComponent(/datum/component/cyberware) + chrome.set_browned_out(TRUE) + // Identical programming still has to settle capacity; reordering the cloud is immaterial. + cloud.programs.Swap(1, 2) + TEST_ASSERT_EQUAL(nanites.sync_programming(cloud), 0, "Identical resync reported a programming change") + TEST_ASSERT(chrome.is_running(), "Unchanged resync didn't recalculate brownout") + // A partial sync must count the programs it retains, too. + var/datum/nanite_program/hardening/additional = allocate(/datum/nanite_program/hardening) + cloud.add_program(null, additional) + TEST_ASSERT_EQUAL(nanites.sync_programming(cloud, FALSE), 0, "Partial cloud sync ignored retained program load") + TEST_ASSERT_EQUAL(length(nanites.programs), 2, "Rejected partial sync changed programming") + +/datum/unit_test/voidcrew_nanite_capacity_recovery + +/datum/unit_test/voidcrew_nanite_capacity_recovery/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + var/obj/item/organ/cyberimp/cyberware/governor_delete/governor = allocate(/obj/item/organ/cyberimp/cyberware/governor_delete) + var/obj/item/organ/cyberimp/cyberware/test_heavy/heavy = allocate(/obj/item/organ/cyberimp/cyberware/test_heavy) + var/obj/item/organ/heart/cybernetic/heart = allocate(/obj/item/organ/heart/cybernetic) + governor.Insert(patient, TRUE) + heavy.Insert(patient, TRUE) + heart.Insert(patient) + var/datum/component/nanites/nanites = patient.AddComponent(/datum/component/nanites) + var/datum/nanite_program/hardening/armor = allocate(/datum/nanite_program/hardening) + var/datum/nanite_program/adrenaline/burst = allocate(/datum/nanite_program/adrenaline) + nanites.add_program(null, armor) + nanites.add_program(null, burst) + var/bare_armor = patient.physiology.armor.get_rating(MELEE) + armor.on_process() + TEST_ASSERT(armor.passive_enabled, "Beneficial passive didn't start") + governor.Remove(patient, TRUE) + TEST_ASSERT(!armor.passive_enabled, "Capacity loss retained beneficial nanite armor") + TEST_ASSERT_EQUAL(patient.physiology.armor.get_rating(MELEE), bare_armor, "Paused nanites retained armor") + TEST_ASSERT(!(heart.organ_flags & ORGAN_FAILING), "Capacity loss shut down a vital TG organ") + var/volume = nanites.nanite_volume + armor.on_process() + burst.trigger() + TEST_ASSERT_EQUAL(nanites.nanite_volume, volume, "Over-budget beneficial nanites consumed fuel") + TEST_ASSERT_EQUAL(burst.next_trigger, 0, "A paused beneficial trigger spent its cooldown") + TEST_ASSERT(!patient.reagents.has_reagent(/datum/reagent/medicine/stimulants), "Paused Adrenaline Burst fired") + for(var/program_type in list(/datum/nanite_program/glitch, /datum/nanite_program/poison, /datum/nanite_program/paralyzing, /datum/nanite_program/sensor/repeat, /datum/nanite_program/monitoring)) + var/datum/nanite_program/hostile = allocate(program_type) + var/load = get_chrome_load(patient) + TEST_ASSERT_EQUAL(nanites.add_program(null, hostile), 1, "Zero-cost payload was refused over capacity") + TEST_ASSERT_EQUAL(get_chrome_load(patient), load, "Zero-cost payload sabotaged capacity") + TEST_ASSERT(!hostile.capacity_blocked(), "Capacity paused a hostile/free program") + qdel(burst) + TEST_ASSERT_EQUAL(get_chrome_load(patient), 19, "Deletion didn't release beneficial program load") + var/datum/component/cyberware/chrome = heavy.GetComponent(/datum/component/cyberware) + TEST_ASSERT(chrome.is_running(), "Deleting a program didn't recover chrome") + armor.on_process() + TEST_ASSERT(armor.passive_enabled, "Beneficial nanites didn't resume after recovery") + qdel(nanites) + TEST_ASSERT_EQUAL(get_chrome_load(patient), 16, "Deleting nanites retained installed program costs") + TEST_ASSERT_EQUAL(patient.physiology.armor.get_rating(MELEE), bare_armor, "Deleting recovered nanites retained their armor") + +/datum/unit_test/voidcrew_cyberware_running_gates + +/datum/unit_test/voidcrew_cyberware_running_gates/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + var/obj/item/organ/eyes/robotic/cyberware/nightshade/eyes = allocate(/obj/item/organ/eyes/robotic/cyberware/nightshade) + eyes.Insert(patient, TRUE) + var/datum/component/cyberware/eye_chrome = eyes.GetComponent(/datum/component/cyberware) + var/datum/action/cooldown/cyberware/chrome_read/read = locate() in eyes.actions + TEST_ASSERT(read, "Chrome read action fixture missing") + TEST_ASSERT(read.IsAvailable(), "Installed healthy optics action unavailable") + eyes.set_organ_damage(eyes.maxHealth) + eye_chrome.start_emp_reboot() + eyes.set_organ_damage(0) + TEST_ASSERT(eye_chrome.emp_down, "Organ repair cleared EMP downtime") + TEST_ASSERT(!eye_chrome.is_running() && !read.IsAvailable(), "Healing eyes reopened buttons before reboot") + // The running predicate must remain authoritative even if another caller clears the shared bit. + eyes.organ_flags &= ~ORGAN_FAILING + TEST_ASSERT(!read.IsAvailable(), "Clearing the shared failing flag bypassed EMP downtime") + eye_chrome.tune_up() + TEST_ASSERT(read.IsAvailable(), "Finished reboot didn't restore the action") + read.StartCooldown(1 MINUTES) + var/ready_at = read.next_use_time + eyes.Remove(patient, TRUE) + TEST_ASSERT(!eye_chrome.is_running() && !read.IsAvailable(), "Removed optics still running") + eyes.Insert(patient, TRUE) + TEST_ASSERT_EQUAL(read.next_use_time, ready_at, "Removing/reinstalling reset an ability cooldown") + var/obj/item/organ/cyberimp/arm/toolkit/cyberware/mantis/arm = allocate(/obj/item/organ/cyberimp/arm/toolkit/cyberware/mantis) + arm.Insert(patient, TRUE) + var/datum/component/cyberware/arm_chrome = arm.GetComponent(/datum/component/cyberware) + var/obj/item/blade = arm.contents[1] + arm.Extend(blade) + TEST_ASSERT(arm.active_item == blade && blade.loc == patient, "Arm deployment fixture failed") + arm_chrome.start_emp_reboot() + TEST_ASSERT(!arm.active_item && blade.loc == arm, "EMP left chrome arm hardware deployed") + arm.organ_flags &= ~ORGAN_FAILING + arm.Extend(blade) + TEST_ASSERT(blade.loc == arm, "Arm deployed during EMP reboot after shared flag was cleared") + arm_chrome.tune_up() + arm.Extend(blade) + arm.set_organ_damage(arm.maxHealth) + TEST_ASSERT(!arm.active_item && blade.loc == arm, "Damage failure left chrome arm hardware deployed") + arm_chrome.tune_up() + arm.Extend(blade) + var/obj/item/organ/cyberimp/cyberware/test_full_body/bulk = allocate(/obj/item/organ/cyberimp/cyberware/test_full_body) + bulk.Insert(patient, TRUE) + TEST_ASSERT(!arm.active_item && blade.loc == arm, "Brownout left chrome arm hardware deployed") + bulk.Remove(patient, TRUE) + arm.Extend(blade) + TEST_ASSERT_EQUAL(arm.active_item, blade, "Capacity recovery didn't restore arm deployment") + arm.Remove(patient, TRUE) + TEST_ASSERT(!arm.active_item && blade.loc == arm, "Removal left arm hardware deployed") + +/datum/unit_test/voidcrew_cyberware_lazarus_windup + +/datum/unit_test/voidcrew_cyberware_lazarus_windup/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + var/obj/item/organ/cyberimp/cyberware/lazarus/node = allocate(/obj/item/organ/cyberimp/cyberware/lazarus) + node.Insert(patient, TRUE) + var/datum/component/cyberware/chrome = node.GetComponent(/datum/component/cyberware) + patient.stat = SOFT_CRIT + node.on_stat_change(patient, SOFT_CRIT, CONSCIOUS) + var/first_generation = node.jolt_generation + TEST_ASSERT(node.jolting, "Lazarus didn't wind up") + TEST_ASSERT(COOLDOWN_FINISHED(node, jolt_cooldown), "Windup consumed Lazarus charge") + chrome.start_emp_reboot() + TEST_ASSERT(!node.jolting, "EMP didn't cancel Lazarus windup") + chrome.tune_up() + node.jolt(first_generation, WEAKREF(patient)) + TEST_ASSERT(COOLDOWN_FINISHED(node, jolt_cooldown), "Cancelled EMP windup consumed charge") + node.on_stat_change(patient, SOFT_CRIT, CONSCIOUS) + var/removed_generation = node.jolt_generation + node.Remove(patient, TRUE) + node.Insert(patient, TRUE) + node.on_stat_change(patient, SOFT_CRIT, CONSCIOUS) + var/current_generation = node.jolt_generation + node.jolt(removed_generation, WEAKREF(patient)) + TEST_ASSERT(node.jolting, "A stale Lazarus callback cancelled the new windup") + TEST_ASSERT(COOLDOWN_FINISHED(node, jolt_cooldown), "Removal/reinstall allowed a stale callback to discharge") + patient.stat = DEAD + node.jolt(current_generation, WEAKREF(patient)) + TEST_ASSERT(COOLDOWN_FINISHED(node, jolt_cooldown), "Dead patient consumed Lazarus charge") + patient.stat = SOFT_CRIT + node.on_stat_change(patient, SOFT_CRIT, CONSCIOUS) + patient.stat = CONSCIOUS + node.jolt(node.jolt_generation, WEAKREF(patient)) + TEST_ASSERT(COOLDOWN_FINISHED(node, jolt_cooldown), "Recovered patient consumed Lazarus charge") + patient.stat = SOFT_CRIT + node.on_stat_change(patient, SOFT_CRIT, CONSCIOUS) + node.jolt(node.jolt_generation, WEAKREF(patient)) + TEST_ASSERT_EQUAL(COOLDOWN_TIMELEFT(node, jolt_cooldown), 6 MINUTES, "Successful discharge didn't start the six-minute cooldown") + var/ready_at = node.jolt_cooldown + node.Remove(patient, TRUE) + node.Insert(patient, TRUE) + TEST_ASSERT_EQUAL(node.jolt_cooldown, ready_at, "Removal/reinstall reset Lazarus cooldown") From f22080bf73197cd3120ce3ceb2e8db153d4bdd9d Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:44:07 -0700 Subject: [PATCH 026/105] Nanite armor pays for absorbed damage --- .../modules/nanites/code/programs/buffing.dm | 100 +++++++- .../unit_tests/armor_partial_modifiers.dm | 220 ++++++++++++++++++ 2 files changed, 318 insertions(+), 2 deletions(-) diff --git a/voidcrew/modules/nanites/code/programs/buffing.dm b/voidcrew/modules/nanites/code/programs/buffing.dm index f1afcb13bab..ad5aab4a6d8 100644 --- a/voidcrew/modules/nanites/code/programs/buffing.dm +++ b/voidcrew/modules/nanites/code/programs/buffing.dm @@ -38,20 +38,30 @@ /datum/nanite_program/hardening name = "Dermal Hardening" - desc = "The nanites form a mesh under the host's skin, protecting them from melee and bullet impacts." + desc = "The nanites form a mesh under the host's skin." use_rate = 1.0 rogue_types = list(/datum/nanite_program/skin_decay) #define NANITE_ARMOR_BOOST_ADDED 30 +#define NANITE_ARMOR_COST_PER_DAMAGE 1 //TODO on_hit effect that turns skin grey for a moment /datum/nanite_program/hardening/enable_passive_effect() + if(passive_enabled || !ishuman(host_mob) || nanite_armor_exhausted()) + return . = ..() if(ishuman(host_mob)) var/mob/living/carbon/human/user = host_mob user.physiology.armor = user.physiology.armor.generate_new_with_modifiers(list(MELEE = NANITE_ARMOR_BOOST_ADDED, BULLET = NANITE_ARMOR_BOOST_ADDED)) + RegisterSignal(user, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(nanite_resolve_hit_armor)) + +/datum/nanite_program/hardening/active_effect() + nanite_armor_exhausted() /datum/nanite_program/hardening/disable_passive_effect() + if(!passive_enabled) + return + UnregisterSignal(host_mob, COMSIG_MOB_APPLY_DAMAGE) . = ..() if(ishuman(host_mob)) var/mob/living/carbon/human/user = host_mob @@ -61,17 +71,26 @@ /datum/nanite_program/refractive name = "Dermal Refractive Surface" - desc = "The nanites form a membrane above the host's skin, reducing the effect of laser and energy impacts." + desc = "The nanites form a reflective membrane above the host's skin." use_rate = 1.0 rogue_types = list(/datum/nanite_program/skin_decay) /datum/nanite_program/refractive/enable_passive_effect() + if(passive_enabled || !ishuman(host_mob) || nanite_armor_exhausted()) + return . = ..() if(ishuman(host_mob)) var/mob/living/carbon/human/user = host_mob user.physiology.armor = user.physiology.armor.generate_new_with_modifiers(list(LASER = NANITE_ARMOR_BOOST_ADDED, ENERGY = NANITE_ARMOR_BOOST_ADDED)) + RegisterSignal(user, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(nanite_resolve_hit_armor)) + +/datum/nanite_program/refractive/active_effect() + nanite_armor_exhausted() /datum/nanite_program/refractive/disable_passive_effect() + if(!passive_enabled) + return + UnregisterSignal(host_mob, COMSIG_MOB_APPLY_DAMAGE) . = ..() if(ishuman(host_mob)) var/mob/living/carbon/human/user = host_mob @@ -79,6 +98,83 @@ if(user.physiology) user.physiology.armor = user.physiology.armor.generate_new_with_modifiers(list(LASER = -NANITE_ARMOR_BOOST_ADDED, ENERGY = -NANITE_ARMOR_BOOST_ADDED)) +/// Both armor programs draw on the same reserve. Recovery still goes through normal upkeep. +/datum/nanite_program/proc/nanite_armor_exhausted() + if(nanites && nanites.nanite_volume > nanites.safety_threshold) + return FALSE + if(nanites) + for(var/datum/nanite_program/program in nanites.programs) + if(program.passive_enabled && (istype(program, /datum/nanite_program/hardening) || istype(program, /datum/nanite_program/refractive))) + program.disable_passive_effect() + return TRUE + +/** + * Bill only the incremental armor supplied by this program, once apply_damage accepts a hit. + * The signal has no armor category: projectiles supply theirs, items use melee, and source-less + * brute/burn hits fall back to melee/laser. Unknown caller modifiers are approximated by treating + * the reported blocked value as the cap. Forced hits with blocked = 0 and direct limb damage + * are intentionally unbilled. An underfunded hit keeps its already calculated protection. + */ +/datum/nanite_program/proc/nanite_resolve_hit_armor(mob/living/carbon/human/source, damage, damagetype, def_zone, blocked, wound_bonus, exposed_wound_bonus, sharpness, attack_direction, attacking_item) + SIGNAL_HANDLER + if(!passive_enabled || damage <= 0 || blocked <= 0 || blocked >= 100 || (damagetype != BRUTE && damagetype != BURN)) + return + if(nanite_armor_exhausted()) + return + + var/armor_flag = damagetype == BRUTE ? MELEE : LASER + var/penetration = 0 + var/weak_against_armor = FALSE + if(istype(attacking_item, /obj/projectile)) + var/obj/projectile/projectile = attacking_item + armor_flag = projectile.armor_flag + penetration = projectile.armour_penetration + weak_against_armor = projectile.weak_against_armour + else if(isitem(attacking_item)) + var/obj/item/weapon = attacking_item + armor_flag = MELEE + penetration = weapon.armour_penetration + weak_against_armor = weapon.weak_against_armour + if(istype(src, /datum/nanite_program/hardening)) + if(armor_flag != MELEE && armor_flag != BULLET) + return + else if(armor_flag != LASER && armor_flag != ENERGY) + return + + // Rebuild clothing's multiplicative remainder without temporarily changing the host's armor. + var/list/parts = isbodypart(def_zone) ? list(def_zone) : source.bodyparts + var/clothing_remainder = 0 + for(var/obj/item/bodypart/part in parts) + var/part_remainder = 1 + for(var/obj/item/clothing/clothing in source.get_clothing_on_part(part)) + part_remainder *= (100 - min(clothing.get_armor_rating(armor_flag), 100)) / 100 + clothing_remainder += part_remainder + clothing_remainder /= max(length(parts), 1) + var/armor_with = source.getarmor(def_zone, armor_flag) + var/physiology_without = source.physiology.armor.get_rating(armor_flag) - NANITE_ARMOR_BOOST_ADDED + var/armor_without = 100 - clothing_remainder * (100 - min(physiology_without, 100)) + if(weak_against_armor) + armor_with *= ARMOR_WEAKENED_MULTIPLIER + armor_without *= ARMOR_WEAKENED_MULTIPLIER + if(armor_with > 0) + armor_with = max(0, PENETRATE_ARMOUR(armor_with, penetration)) + if(armor_without > 0) + armor_without = max(0, PENETRATE_ARMOUR(armor_without, penetration)) + var/armor_delta = max(0, min(blocked, armor_with) - min(blocked, armor_without)) + var/cost = damage * armor_delta / (100 - blocked) * NANITE_ARMOR_COST_PER_DAMAGE + if(cost <= 0) + return + + var/datum/component/nanites/swarm = nanites + var/available = max(0, swarm.nanite_volume - swarm.safety_threshold) + if(cost >= available) + // Disable before withdrawing: a zero-safety swarm deletes itself at zero volume. + for(var/datum/nanite_program/program in swarm.programs) + if(program.passive_enabled && (istype(program, /datum/nanite_program/hardening) || istype(program, /datum/nanite_program/refractive))) + program.disable_passive_effect() + swarm.adjust_nanites(null, -min(cost, available)) + +#undef NANITE_ARMOR_COST_PER_DAMAGE #undef NANITE_ARMOR_BOOST_ADDED /datum/nanite_program/coagulating diff --git a/voidcrew/modules/unit_tests/armor_partial_modifiers.dm b/voidcrew/modules/unit_tests/armor_partial_modifiers.dm index ee784100a49..0e6ce992ef3 100644 --- a/voidcrew/modules/unit_tests/armor_partial_modifiers.dm +++ b/voidcrew/modules/unit_tests/armor_partial_modifiers.dm @@ -15,3 +15,223 @@ qdel(scaled) qdel(added) qdel(base) + +/// Landed-hit accounting deliberately permits one fully protected, underfunded final hit. +/datum/unit_test/armor_partial_modifiers/nanites + abstract_type = /datum/unit_test/armor_partial_modifiers/nanites + var/mob/living/carbon/human/patient + var/datum/component/nanites/swarm + var/datum/nanite_program/hardening/hardening + var/datum/nanite_program/refractive/refractive + var/obj/projectile/projectile + var/test_armor_flag = BULLET + +/datum/unit_test/armor_partial_modifiers/nanites/proc/setup(safety = 50) + patient = allocate(/mob/living/carbon/human/consistent) + swarm = patient.AddComponent(/datum/component/nanites) + STOP_PROCESSING(SSnanites, swarm) + swarm.regen_rate = 0 + swarm.safety_threshold = safety + hardening = allocate(/datum/nanite_program/hardening) + refractive = allocate(/datum/nanite_program/refractive) + TEST_ASSERT_EQUAL(swarm.add_program(null, hardening), 1, "Hardening installation failed") // COMPONENT_PROGRAM_INSTALLED + TEST_ASSERT_EQUAL(swarm.add_program(null, refractive), 1, "Refractive installation failed") + hardening.enable_passive_effect() + refractive.enable_passive_effect() + TEST_ASSERT(hardening.passive_enabled && refractive.passive_enabled, "Armor fixture did not activate") + projectile = allocate(/obj/projectile) + projectile.damage = 20 + projectile.damage_type = BRUTE + projectile.wound_bonus = CANT_WOUND + +/// Keep endurance independent of survival and limb caps, without yielding between hits. +/datum/unit_test/armor_partial_modifiers/nanites/proc/hit(armor_flag = test_armor_flag, penetration = 0, weak = FALSE, cap = 90) + patient.heal_overall_damage(1000, 1000) + projectile.armor_flag = armor_flag + projectile.damage_type = (armor_flag == LASER || armor_flag == ENERGY) ? BURN : BRUTE + projectile.armour_penetration = penetration + projectile.weak_against_armour = weak + var/blocked = min(cap, patient.run_armor_check(BODY_ZONE_CHEST, armor_flag, armour_penetration = penetration, silent = TRUE, weak_against_armour = weak)) + return patient.apply_damage(20, projectile.damage_type, BODY_ZONE_CHEST, blocked, wound_bonus = CANT_WOUND, attacking_item = projectile, wound_clothing = FALSE) + +/datum/unit_test/armor_partial_modifiers/nanites/endurance/Run() + setup() + var/start_tick = world.time + for(var/shot in 1 to 8) + TEST_ASSERT(abs(hit() - 14) < 0.01, "Funded bullet [shot] did not deal 14 damage") + TEST_ASSERT(abs(swarm.nanite_volume - (100 - 6 * shot)) < 0.01, "Bullet [shot] did not cost 6 nanites") + TEST_ASSERT(abs(hit() - 14) < 0.01, "Underfunded ninth bullet lost its accepted full protection") + TEST_ASSERT_EQUAL(swarm.nanite_volume, 50, "Ninth bullet crossed the safety threshold") + TEST_ASSERT(!hardening.passive_enabled && !refractive.passive_enabled, "Depletion did not immediately remove both armor contributions") + TEST_ASSERT_EQUAL(patient.getarmor(BODY_ZONE_CHEST, BULLET), 0, "Depleted Hardening retained armor") + TEST_ASSERT_EQUAL(patient.getarmor(BODY_ZONE_CHEST, LASER), 0, "Depleted Refractive retained armor") + TEST_ASSERT(abs(hit() - 20) < 0.01, "A second underfunded hit received free armor") + TEST_ASSERT_EQUAL(swarm.nanite_volume, 50, "Unarmored hit spent reserved nanites") + TEST_ASSERT_EQUAL(world.time, start_tick, "Endurance fixture yielded between hits") + +/datum/unit_test/armor_partial_modifiers/nanites/endurance/refractive + test_armor_flag = LASER + +/datum/unit_test/armor_partial_modifiers/nanites/safety_zero/Run() + setup(0) + for(var/shot in 1 to 16) + TEST_ASSERT(abs(hit() - 14) < 0.01, "Zero-safety bullet [shot] did not receive full armor") + TEST_ASSERT(abs(swarm.nanite_volume - (100 - 6 * shot)) < 0.01, "Zero-safety bullet [shot] had the wrong cost") + TEST_ASSERT(abs(hit() - 14) < 0.01, "Underfunded seventeenth bullet lost full protection") + TEST_ASSERT_NULL(patient.GetComponent(/datum/component/nanites), "An empty zero-safety swarm was not removed") + TEST_ASSERT_EQUAL(patient.getarmor(BODY_ZONE_CHEST, BULLET), 0, "Deleting the empty swarm retained armor") + TEST_ASSERT(abs(hit() - 20) < 0.01, "A hit after zero-safety depletion received armor") + +/datum/unit_test/armor_partial_modifiers/nanites/safety_zero/refractive + test_armor_flag = LASER + +/datum/unit_test/armor_partial_modifiers/nanites/channels/Run() + setup() + for(var/armor_flag in list(MELEE, BULLET, LASER, ENERGY)) + var/before = swarm.nanite_volume + TEST_ASSERT(abs(hit(armor_flag) - 14) < 0.01, "[armor_flag] did not receive the existing +30 armor") + TEST_ASSERT(abs(before - swarm.nanite_volume - 6) < 0.01, "[armor_flag] was billed to both programs or to neither") + var/before = swarm.nanite_volume + for(var/armor_flag in list(BOMB, FIRE, ACID)) + hit(armor_flag) + TEST_ASSERT_EQUAL(swarm.nanite_volume, before, "Unprotected armor categories spent nanites") + patient.apply_damage(5, TOX, blocked = 30) + patient.apply_damage(20, BRUTE, BODY_ZONE_CHEST, 0, TRUE, wound_bonus = CANT_WOUND) + patient.apply_damage(0, BRUTE, BODY_ZONE_CHEST, 30) + patient.apply_damage(-20, BRUTE, BODY_ZONE_CHEST, 30) + var/obj/item/bodypart/chest = patient.get_bodypart(BODY_ZONE_CHEST) + chest.receive_damage(20, blocked = 30, wound_bonus = CANT_WOUND) + TEST_ASSERT_EQUAL(swarm.nanite_volume, before, "Forced, nonphysical, zero, healing or direct limb damage spent nanites") + +/datum/armor/nanite_accounting_test + melee = 75 + bullet = 75 + laser = 75 + energy = 75 + +/obj/item/clothing/suit/nanite_accounting_test + body_parts_covered = CHEST + armor_type = /datum/armor/nanite_accounting_test + +/datum/unit_test/armor_partial_modifiers/nanites/clothing_chrome/Run() + setup() + var/obj/item/clothing/suit/nanite_accounting_test/suit = allocate(/obj/item/clothing/suit/nanite_accounting_test) + TEST_ASSERT(patient.equip_to_slot_if_possible(suit, ITEM_SLOT_OCLOTHING), "Could not equip armor fixture") + TEST_ASSERT(abs(hit() - 3.5) < 0.01, "75 bullet clothing did not combine multiplicatively") + TEST_ASSERT(abs(swarm.nanite_volume - 98.5) < 0.01, "Nanites were charged for clothing's protection") + var/obj/item/organ/cyberimp/cyberware/dermal_mesh/mesh = allocate(/obj/item/organ/cyberimp/cyberware/dermal_mesh) + mesh.Insert(patient, TRUE) + TEST_ASSERT_EQUAL(patient.physiology.armor.get_rating(BULLET), 45, "Chrome fixture did not stack with Hardening") + TEST_ASSERT(abs(hit() - 2.75) < 0.06, "Clothing/chrome/nanite armor stack changed damage") + TEST_ASSERT(abs(swarm.nanite_volume - 97) < 0.01, "Nanites paid for chrome's armor contribution") + TEST_ASSERT(abs(hit(BULLET, 20) - 3.4375) < 0.06, "Penetration changed the clothing/chrome stack incorrectly") + TEST_ASSERT(abs(swarm.nanite_volume - 95.125) < 0.01, "Penetration billed clothing/chrome to nanites") + hardening.disable_passive_effect() + TEST_ASSERT_EQUAL(patient.physiology.armor.get_rating(BULLET), 15, "Disabling nanites removed chrome armor") + mesh.Remove(patient, TRUE) + TEST_ASSERT_EQUAL(patient.physiology.armor.get_rating(BULLET), 0, "Removing chrome left phantom armor") + +/datum/unit_test/armor_partial_modifiers/nanites/penetration_caps_modifiers/Run() + setup() + TEST_ASSERT(abs(hit(BULLET, 20) - 17.5) < 0.01, "Penetration did not reduce nanite armor") + TEST_ASSERT(abs(swarm.nanite_volume - 97.5) < 0.01, "Penetrating bullet had the wrong drain") + TEST_ASSERT(abs(hit(BULLET, 100) - 20) < 0.01, "Full penetration retained nanite protection") + TEST_ASSERT(abs(swarm.nanite_volume - 97.5) < 0.01, "Full penetration spent nanites") + TEST_ASSERT(abs(hit(BULLET, 0, TRUE) - 8) < 0.01, "Armor weakness modifier was lost") + TEST_ASSERT(abs(swarm.nanite_volume - 85.5) < 0.01, "Armor weakness had the wrong drain") + patient.physiology.brute_mod = 0.5 + TEST_ASSERT(abs(hit() - 7) < 0.01, "Physiology damage modifier was lost") + TEST_ASSERT(abs(swarm.nanite_volume - 82.5) < 0.01, "Damage modifier was not reflected in armor cost") + patient.physiology.brute_mod = 1 + patient.physiology.armor = patient.physiology.armor.generate_new_with_modifiers(list(BULLET = 80)) + TEST_ASSERT(abs(hit() - 2) < 0.01, "Projectile armor cap changed") + TEST_ASSERT(abs(swarm.nanite_volume - 80.5) < 0.01, "Nanites paid for protection above the armor cap") + patient.physiology.armor = patient.physiology.armor.generate_new_with_modifiers(list(BULLET = 15)) + hit() + TEST_ASSERT(abs(swarm.nanite_volume - 80.5) < 0.01, "Already capped non-nanite armor was billed to the swarm") + +/datum/unit_test/armor_partial_modifiers/nanites/upkeep_lifecycle/Run() + setup() + swarm.nanite_volume = 52 + hardening.on_process() + TEST_ASSERT_EQUAL(swarm.nanite_volume, 51, "Hardening upkeep changed") + TEST_ASSERT(hardening.passive_enabled && refractive.passive_enabled, "Funded armor was disabled early") + refractive.on_process() + TEST_ASSERT_EQUAL(swarm.nanite_volume, 50, "Refractive upkeep changed") + TEST_ASSERT(!hardening.passive_enabled && !refractive.passive_enabled, "Upkeep reaching safety retained armor") + hardening.on_process() + TEST_ASSERT_EQUAL(swarm.nanite_volume, 50, "Unfunded upkeep crossed safety") + swarm.nanite_volume = 50.5 + hardening.on_process() + TEST_ASSERT_EQUAL(swarm.nanite_volume, 50.5, "Partial upkeep was consumed") + TEST_ASSERT(!hardening.passive_enabled, "Partial upkeep enabled armor") + swarm.nanite_volume = 51 + hardening.on_process() + TEST_ASSERT_EQUAL(swarm.nanite_volume, 50, "Exact upkeep was not consumed") + TEST_ASSERT(!hardening.passive_enabled, "Upkeep leaving no hit reserve enabled armor") + swarm.nanite_volume = 51.25 + hardening.on_process() + TEST_ASSERT(hardening.passive_enabled, "Regenerated armor failed to resume through upkeep") + TEST_ASSERT_EQUAL(swarm.nanite_volume, 50.25, "Resuming skipped upkeep") + TEST_ASSERT(abs(hit() - 14) < 0.01, "Fractionally funded hit lost full protection") + TEST_ASSERT_EQUAL(swarm.nanite_volume, 50, "Fractionally funded hit crossed safety") + TEST_ASSERT(!hardening.passive_enabled, "Fractionally funded armor remained enabled") + swarm.nanite_volume = 100 + hardening.enable_passive_effect() + hardening.enable_passive_effect() + TEST_ASSERT_EQUAL(patient.getarmor(BODY_ZONE_CHEST, BULLET), 30, "Repeated activation stacked armor") + hardening.disable_passive_effect() + hardening.disable_passive_effect() + TEST_ASSERT_EQUAL(patient.getarmor(BODY_ZONE_CHEST, BULLET), 0, "Repeated deactivation subtracted other armor") + hardening.enable_passive_effect() + refractive.enable_passive_effect() + qdel(swarm) + TEST_ASSERT_EQUAL(patient.getarmor(BODY_ZONE_CHEST, BULLET), 0, "Swarm removal retained Hardening") + TEST_ASSERT_EQUAL(patient.getarmor(BODY_ZONE_CHEST, LASER), 0, "Swarm removal retained Refractive") + +/datum/unit_test/armor_partial_modifiers/nanites/proc/block_hit() + SIGNAL_HANDLER + return SUCCESSFUL_BLOCK + +/datum/unit_test/armor_partial_modifiers/nanites/queries_misses_blocks/Run() + setup() + for(var/query in 1 to 20) + patient.getarmor(BODY_ZONE_CHEST, BULLET) + patient.run_armor_check(BODY_ZONE_CHEST, MELEE, silent = TRUE) + patient.get_incoming_damage_modifier(14, BRUTE, BODY_ZONE_CHEST) + TEST_ASSERT_EQUAL(swarm.nanite_volume, 100, "Pure armor/modifier queries spent nanites") + var/mob/living/carbon/human/attacker = allocate(/mob/living/carbon/human/consistent) + attacker.set_combat_mode(TRUE) + ADD_TRAIT(attacker, TRAIT_PERFECT_ATTACKER, TRAIT_SOURCE_UNIT_TESTS) + // A zero lower bound selects the guaranteed miss branch, even with a nonzero upper bound. + for(var/obj/item/bodypart/arm in attacker.hand_bodyparts) + arm.unarmed_damage_low = 0 + arm.unarmed_damage_high = 20 + patient.attack_hand(attacker, list(RIGHT_CLICK = FALSE)) + TEST_ASSERT_EQUAL(patient.getBruteLoss(), 0, "Miss fixture landed a hit") + TEST_ASSERT_EQUAL(swarm.nanite_volume, 100, "Missed punch spent nanites") + RegisterSignal(patient, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(block_hit)) + var/obj/item/storage/toolbox/weapon = allocate(/obj/item/storage/toolbox) + weapon.force = 20 + weapon.throwforce = 20 + patient.attacked_by(weapon, attacker) + patient.hitby(weapon) + projectile.armor_flag = BULLET + patient.bullet_act(projectile, BODY_ZONE_CHEST) + TEST_ASSERT_EQUAL(patient.getBruteLoss(), 0, "Shield-block fixture allowed damage") + TEST_ASSERT_EQUAL(swarm.nanite_volume, 100, "Shield-blocked melee, thrown or projectile attack spent nanites") + UnregisterSignal(patient, COMSIG_LIVING_CHECK_BLOCK) + patient.attacked_by(weapon, attacker) + TEST_ASSERT(abs(swarm.nanite_volume - 94) < 0.01, "Landed item attack was not charged once") + patient.heal_overall_damage(1000, 1000) + patient.hitby(weapon, hitpush = FALSE) + TEST_ASSERT(abs(swarm.nanite_volume - 88) < 0.01, "Landed thrown attack was not charged once") + for(var/obj/item/bodypart/arm in attacker.hand_bodyparts) + arm.unarmed_damage_low = 20 + arm.unarmed_damage_high = 20 + patient.heal_overall_damage(1000, 1000) + patient.attack_hand(attacker, list(RIGHT_CLICK = FALSE)) + TEST_ASSERT(abs(swarm.nanite_volume - 82) < 0.01, "Landed unarmed attack was not charged once") + patient.heal_overall_damage(1000, 1000) + patient.apply_projectile_effects(projectile, BODY_ZONE_CHEST, patient.check_projectile_armor(BODY_ZONE_CHEST, projectile, TRUE)) + TEST_ASSERT(abs(swarm.nanite_volume - 76) < 0.01, "Landed projectile effects were not charged once") From 0ef0a6dd1eae295066d0d6536a49bcac9c4a8a43 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:52:34 -0700 Subject: [PATCH 027/105] Repair Monitoring, spreading and Sting --- code/game/machinery/computer/crew.dm | 42 +-- .../modules/nanites/code/programs/utility.dm | 34 +- .../unit_tests/voidcrew_nanite_research.dm | 329 ++++++++++++++++++ 3 files changed, 374 insertions(+), 31 deletions(-) diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index ab08ffaa957..467994927bc 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -204,7 +204,8 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) // VOIDCREW EDIT END var/list/results = list() - for(var/tracked_mob in GLOB.suit_sensors_list) + // voidcrew/modules/nanites: Monitoring shares the same scoped sensor feed. + for(var/tracked_mob in (GLOB.suit_sensors_list | SSnanites.nanite_monitored_mobs)) if(!tracked_mob) stack_trace("Null entry in suit sensors list.") continue @@ -225,25 +226,24 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) if(!voidcrew_crew_sensor_in_scope(tracked_living_mob, pos, hull, z, source_turf)) // VOIDCREW EDIT: crew sensor integration: scope and cache readings by the requesting device (voidcrew/edits/machinery/crew_monitor.dm) continue - var/mob/living/carbon/human/tracked_human = tracked_living_mob - - // Check their humanity. - if(!ishuman(tracked_human)) - stack_trace("Non-human mob is in suit_sensors_list: [tracked_living_mob] ([tracked_living_mob.type])") - continue - - // Check they have a uniform - var/obj/item/clothing/under/uniform = tracked_human.w_uniform - if (!istype(uniform)) - stack_trace("Human without a suit sensors compatible uniform is in suit_sensors_list: [tracked_human] ([tracked_human.type]) ([uniform?.type])") - continue - - // Check if their uniform is in a compatible mode. - if((uniform.has_sensor == NO_SENSORS) || !uniform.sensor_mode) - stack_trace("Human without active suit sensors is in suit_sensors_list: [tracked_human] ([tracked_human.type]) ([uniform.type])") - continue - - var/sensor_mode = uniform.sensor_mode + var/monitored = (tracked_living_mob in SSnanites.nanite_monitored_mobs) + var/obj/item/clothing/under/uniform + var/sensor_mode = SENSOR_COORDS + if(!monitored) + var/mob/living/carbon/human/tracked_human = tracked_living_mob + if(!ishuman(tracked_human)) + stack_trace("Non-human mob is in suit_sensors_list: [tracked_living_mob] ([tracked_living_mob.type])") + continue + + uniform = tracked_human.w_uniform + if(!istype(uniform)) + stack_trace("Human without a suit sensors compatible uniform is in suit_sensors_list: [tracked_human] ([tracked_human.type]) ([uniform?.type])") + continue + + if((uniform.has_sensor == NO_SENSORS) || !uniform.sensor_mode) + stack_trace("Human without active suit sensors is in suit_sensors_list: [tracked_human] ([tracked_human.type]) ([uniform.type])") + continue + sensor_mode = uniform.sensor_mode // The entry for this human var/list/entry = list( @@ -262,7 +262,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) entry["ijob"] = jobs[trim_assignment] // Broken sensors show garbage data - if (uniform.has_sensor == BROKEN_SENSORS) + if (!monitored && uniform.has_sensor == BROKEN_SENSORS) entry["life_status"] = rand(0,1) entry["area"] = pick_list (ION_FILE, "ionarea") entry["oxydam"] = rand(0,175) diff --git a/voidcrew/modules/nanites/code/programs/utility.dm b/voidcrew/modules/nanites/code/programs/utility.dm index 6f8a6f8ec17..73a45190360 100644 --- a/voidcrew/modules/nanites/code/programs/utility.dm +++ b/voidcrew/modules/nanites/code/programs/utility.dm @@ -28,19 +28,28 @@ /datum/nanite_program/monitoring name = "Monitoring" - desc = "The nanites monitor the host's vitals and location, sending them to the suit sensor network." + desc = "A quiet pulse follows the host's heartbeat." rogue_types = list(/datum/nanite_program/toxic) /datum/nanite_program/monitoring/enable_passive_effect() . = ..() SSnanites.nanite_monitored_mobs |= host_mob + GLOB.crewmonitor.data_by_scope.Cut() + GLOB.crewmonitor.last_update.Cut() host_mob.hud_set_nanite_indicator() /datum/nanite_program/monitoring/disable_passive_effect() . = ..() SSnanites.nanite_monitored_mobs -= host_mob + GLOB.crewmonitor.data_by_scope.Cut() + GLOB.crewmonitor.last_update.Cut() host_mob.hud_set_nanite_indicator() +/datum/nanite_program/monitoring/on_mob_remove() + . = ..() + if(host_mob in SSnanites.nanite_monitored_mobs) + disable_passive_effect() + /datum/nanite_program/self_scan name = "Host Scan" desc = "The nanites display a detailed readout of a body scan to the host." @@ -181,19 +190,18 @@ /datum/nanite_program/spreading name = "Infective Exo-Locomotion" - desc = "The nanites gain the ability to survive for brief periods outside of the human body, as well as the ability to start new colonies without an integration process; \ - resulting in an extremely infective strain of nanites." + desc = "A restless swarm that drifts between nearby bodies." use_rate = 1.50 rogue_types = list(/datum/nanite_program/aggressive_replication, /datum/nanite_program/necrotic) var/spread_cooldown = 0 /datum/nanite_program/spreading/active_effect() - if(spread_cooldown < world.time) + if(world.time < spread_cooldown) return - spread_cooldown = world.time + 50 + spread_cooldown = world.time + 5 SECONDS var/list/mob/living/carbon/human/target_hosts = list() for(var/mob/living/carbon/human/L in oview(5, host_mob)) - if(!prob(25)) + if(!roll_infection_chance(25)) continue if(!(L.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD))) continue @@ -201,7 +209,8 @@ if(!target_hosts.len) return var/mob/living/carbon/human/infectee = pick(target_hosts) - if(prob(100 - infectee.wear_suit.get_armor_rating(BIO))) + var/bio_protection = infectee.wear_suit ? infectee.wear_suit.get_armor_rating(BIO) : 0 + if(roll_infection_chance(100 - bio_protection)) //this will potentially take over existing nanites! infectee.AddComponent(/datum/component/nanites, null, 10) SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites) @@ -209,10 +218,10 @@ /datum/nanite_program/nanite_sting name = "Nanite Sting" - desc = "When triggered, projects a nearly invisible spike of nanites that attempts to infect a nearby non-host with a copy of the host's nanites cluster." + desc = "The swarm forms a fine needle beneath the skin." can_trigger = TRUE trigger_cost = 5 - trigger_cooldown = 100 + trigger_cooldown = 10 SECONDS rogue_types = list(/datum/nanite_program/glitch, /datum/nanite_program/toxic) /datum/nanite_program/nanite_sting/on_trigger(comm_message) @@ -225,13 +234,18 @@ consume_nanites(-5) return var/mob/living/carbon/human/infectee = pick(target_hosts) - if(prob(100 - infectee.wear_suit.get_armor_rating(BIO))) + var/bio_protection = infectee.wear_suit ? infectee.wear_suit.get_armor_rating(BIO) : 0 + if(roll_infection_chance(100 - bio_protection)) //unlike with Infective Exo-Locomotion, this can't take over existing nanites, because Nanite Sting only targets non-hosts. infectee.AddComponent(/datum/component/nanites, null, 5) SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites) log_game("[infectee] was infected by a nanite cluster by [key_name(host_mob)] at [AREACOORD(infectee)].") to_chat(infectee, span_warning("You feel a tiny prick.")) +/// Chance gate for infection candidates and their suit protection. +/datum/nanite_program/proc/roll_infection_chance(chance) + return prob(chance) + /datum/nanite_program/mitosis name = "Mitosis" desc = "The nanites gain the ability to self-replicate, using bluespace to power the process. Becomes more effective the more nanites are already in the host.\ diff --git a/voidcrew/modules/unit_tests/voidcrew_nanite_research.dm b/voidcrew/modules/unit_tests/voidcrew_nanite_research.dm index d97425efefa..ba7d00dbcae 100644 --- a/voidcrew/modules/unit_tests/voidcrew_nanite_research.dm +++ b/voidcrew/modules/unit_tests/voidcrew_nanite_research.dm @@ -143,3 +143,332 @@ TEST_ASSERT_EQUAL(controller.get_backup(backup_id), original, "Research separation discarded an existing cloud backup") TEST_ASSERT(program in original.nanites.programs, "Research separation erased an existing cloud program") qdel(controller) + +/// Only the rolls are controlled; range, eligibility, armor and synchronization stay real. +/datum/nanite_program/spreading/infection_test + var/list/infection_rolls = list() + +/datum/nanite_program/spreading/infection_test/roll_infection_chance(chance) + infection_rolls += chance + return chance > 0 + +/datum/nanite_program/nanite_sting/infection_test + var/list/infection_rolls = list() + +/datum/nanite_program/nanite_sting/infection_test/roll_infection_chance(chance) + infection_rolls += chance + return chance > 0 + +/mob/living/carbon/human/consistent/nanite_infection_test + var/infection_adjacent = TRUE + +/mob/living/carbon/human/consistent/nanite_infection_test/Adjacent(atom/neighbor, atom/target, atom/movable/mover) + return infection_adjacent && ..() + +/datum/armor/nanite_infection_test + bio = 60 + +/obj/item/clothing/suit/nanite_infection_test + armor_type = /datum/armor/nanite_infection_test + +/datum/unit_test/voidcrew_nanite_research/proc/monitor_entry(atom/source, mob/living/host) + var/list/matches = list() + for(var/list/entry as anything in GLOB.crewmonitor.update_data(source)) + if(entry["ref"] == REF(host)) + matches += list(entry) + TEST_ASSERT_EQUAL(length(matches), 1, "A monitored host must appear exactly once") + return matches[1] + +/datum/unit_test/voidcrew_nanite_research/proc/monitor_absent(atom/source, mob/living/host) + for(var/list/entry as anything in GLOB.crewmonitor.update_data(source)) + TEST_ASSERT_NOTEQUAL(entry["ref"], REF(host), "The monitor exposed an inactive or foreign host") + +/datum/unit_test/voidcrew_nanite_research/monitoring/Run() + var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent) + var/obj/item/source = allocate(/obj/item) + var/datum/component/nanites/swarm = patient.AddComponent(/datum/component/nanites) + var/datum/nanite_program/monitoring/program = allocate(/datum/nanite_program/monitoring) + swarm.add_program(null, program) + monitor_absent(source, patient) // Prime the sensor cache before activation. + program.on_process() + TEST_ASSERT_EQUAL(length(GLOB.crewmonitor.data_by_scope), 0, "Monitoring activation retained cached sensors") + TEST_ASSERT_EQUAL(length(GLOB.crewmonitor.last_update), 0, "Monitoring activation retained cache timestamps") + program.enable_passive_effect() + var/registrations = 0 + for(var/mob/living/registered in SSnanites.nanite_monitored_mobs) + if(registered == patient) + registrations++ + TEST_ASSERT_EQUAL(registrations, 1, "Repeated Monitoring activation duplicated its host") + patient.adjustBruteLoss(12) + patient.alpha = 0 + var/obj/item/card/id/id_card = allocate(/obj/item/card/id) + id_card.registered_name = "Nanite Patient" + id_card.assignment = "Medical Doctor" + patient.equip_to_slot(id_card, ITEM_SLOT_ID) + var/list/entry = monitor_entry(source, patient) + TEST_ASSERT_EQUAL(entry["name"], id_card.registered_name, "Uniformless Monitoring lost ID naming") + TEST_ASSERT_EQUAL(entry["assignment"], id_card.assignment, "Monitoring lost ID assignment") + TEST_ASSERT_EQUAL(entry["life_status"], patient.stat, "Monitoring lost life status") + TEST_ASSERT_EQUAL(entry["brutedam"], round(patient.getBruteLoss(), 1), "Monitoring lost brute damage") + TEST_ASSERT_EQUAL(entry["burndam"], round(patient.getFireLoss(), 1), "Monitoring lost burn damage") + TEST_ASSERT_EQUAL(entry["toxdam"], round(patient.getToxLoss(), 1), "Monitoring lost toxin damage") + TEST_ASSERT_EQUAL(entry["oxydam"], round(patient.getOxyLoss(), 1), "Monitoring lost oxygen damage") + TEST_ASSERT_EQUAL(entry["health"], round(patient.health, 1), "Monitoring lost health") + TEST_ASSERT_EQUAL(entry["area"], get_area_name(patient, format_text = TRUE), "Monitoring lost location") + TEST_ASSERT(!entry["can_track"], "Monitoring bypassed the host's tracking restrictions") + + var/obj/item/clothing/under/color/grey/uniform = allocate(/obj/item/clothing/under/color/grey) + uniform.has_sensor = HAS_SENSORS + uniform.sensor_mode = SENSOR_LIVING + patient.equip_to_slot(uniform, ITEM_SLOT_ICLOTHING) + patient.update_suit_sensors() + TEST_ASSERT(patient in GLOB.suit_sensors_list, "The deduplication fixture has no suit sensors") + GLOB.crewmonitor.data_by_scope.Cut() + entry = monitor_entry(source, patient) + TEST_ASSERT("area" in entry, "Low suit sensors suppressed Monitoring's location") + uniform.has_sensor = BROKEN_SENSORS + GLOB.crewmonitor.data_by_scope.Cut() + entry = monitor_entry(source, patient) + TEST_ASSERT_EQUAL(entry["health"], round(patient.health, 1), "Broken suit sensors corrupted Monitoring") + uniform.has_sensor = HAS_SENSORS + program.deactivate() + TEST_ASSERT_EQUAL(length(GLOB.crewmonitor.data_by_scope), 0, "Monitoring deactivation retained cached sensors") + TEST_ASSERT_EQUAL(length(GLOB.crewmonitor.last_update), 0, "Monitoring deactivation retained cache timestamps") + TEST_ASSERT(!(patient in SSnanites.nanite_monitored_mobs), "Deactivated Monitoring retained its registration") + entry = monitor_entry(source, patient) + TEST_ASSERT(!("area" in entry) && !("health" in entry), "Deactivation did not restore the uniform's sensor mode") + patient.temporarilyRemoveItemFromInventory(uniform, TRUE) + patient.update_suit_sensors() + GLOB.crewmonitor.data_by_scope.Cut() + monitor_absent(source, patient) + + program.activate() + program.on_process() + monitor_entry(source, patient) + qdel(program) + TEST_ASSERT(!(patient in SSnanites.nanite_monitored_mobs), "Deleted Monitoring retained its host") + TEST_ASSERT_EQUAL(length(GLOB.crewmonitor.data_by_scope), 0, "Program deletion retained cached Monitoring") + monitor_absent(source, patient) + program = allocate(/datum/nanite_program/monitoring) + swarm.add_program(null, program) + program.on_process() + monitor_entry(source, patient) + qdel(swarm) + TEST_ASSERT(!(patient in SSnanites.nanite_monitored_mobs), "Swarm deletion retained Monitoring") + TEST_ASSERT_EQUAL(length(GLOB.crewmonitor.data_by_scope), 0, "Swarm deletion retained cached Monitoring") + swarm = patient.AddComponent(/datum/component/nanites) + program = allocate(/datum/nanite_program/monitoring) + swarm.add_program(null, program) + program.on_process() + monitor_entry(source, patient) + qdel(patient) + TEST_ASSERT(!(patient in SSnanites.nanite_monitored_mobs), "Host deletion retained Monitoring") + TEST_ASSERT_EQUAL(length(GLOB.crewmonitor.data_by_scope), 0, "Host deletion retained cached Monitoring") + +/datum/unit_test/voidcrew_nanite_research/monitoring_scope + var/list/test_ports = list() + var/datum/turf_reservation/local_site + var/datum/turf_reservation/neighbour_site + +/datum/unit_test/voidcrew_nanite_research/monitoring_scope/Destroy() + for(var/obj/docking_port/mobile/voidcrew/port in test_ports) + qdel(port, force = TRUE) + test_ports = null + QDEL_LIST(allocated) + QDEL_NULL(local_site) + QDEL_NULL(neighbour_site) + return ..() + +/datum/unit_test/voidcrew_nanite_research/monitoring_scope/Run() + local_site = SSmapping.request_turf_block_reservation(4, 3, 1, null, /datum/turf_reservation, /turf/open/floor/iron) + TEST_ASSERT_NOTNULL(local_site, "Could not reserve the local sensor site") + var/turf/local_turf = local_site.bottom_left_turfs[1] + neighbour_site = SSmapping.request_turf_block_reservation(2, 2, 1, local_turf.z) + TEST_ASSERT_NOTNULL(neighbour_site, "Could not reserve a neighbouring sensor site") + var/turf/neighbour_turf = neighbour_site.bottom_left_turfs[1] + var/turf/foreign_turf = get_step(get_step(local_turf, EAST), EAST) + var/turf/away_turf = get_step(local_turf, NORTH) + for(var/turf/port_turf in list(local_turf, foreign_turf)) + var/obj/docking_port/mobile/voidcrew/port = new(port_turf) + test_ports += port + port.width = 1 + port.height = 1 + port.shuttle_areas[get_area(port_turf)] = TRUE + port.register() + var/list/hosts = list() + for(var/turf/host_turf in list(local_turf, foreign_turf, away_turf, neighbour_turf)) + var/mob/living/carbon/human/host = allocate(/mob/living/carbon/human/consistent, host_turf) + var/datum/component/nanites/swarm = host.AddComponent(/datum/component/nanites) + var/datum/nanite_program/monitoring/program = allocate(/datum/nanite_program/monitoring) + swarm.add_program(null, program) + program.on_process() + hosts += host + var/mob/living/local_host = hosts[1] + var/mob/living/foreign_host = hosts[2] + var/mob/living/away_host = hosts[3] + var/mob/living/neighbour_host = hosts[4] + TEST_ASSERT_EQUAL(voidcrew_crew_sensor_hull(local_host), test_ports[1], "Local hull fixture is not registered") + TEST_ASSERT_EQUAL(voidcrew_crew_sensor_hull(foreign_host), test_ports[2], "Foreign hull fixture is not registered") + TEST_ASSERT_NOTEQUAL(map_region_for_turf(local_turf), map_region_for_turf(neighbour_turf), "Site fixtures share a region") + monitor_entry(local_host, local_host) + monitor_entry(local_host, away_host) + monitor_absent(local_host, foreign_host) + monitor_absent(local_host, neighbour_host) + monitor_entry(foreign_host, foreign_host) + monitor_absent(foreign_host, local_host) // A hull cache must not cross to its neighbour. + monitor_entry(away_host, away_host) + monitor_absent(away_host, local_host) + monitor_absent(away_host, neighbour_host) + monitor_entry(neighbour_host, neighbour_host) + monitor_absent(neighbour_host, away_host) // Same z, different site and cache key. + +/datum/unit_test/voidcrew_nanite_research/infection + abstract_type = /datum/unit_test/voidcrew_nanite_research/infection + var/datum/turf_reservation/infection_block + var/mob/living/carbon/human/donor + var/mob/living/carbon/human/consistent/nanite_infection_test/target + var/datum/component/nanites/source_swarm + var/datum/nanite_program/infection_program + +/datum/unit_test/voidcrew_nanite_research/infection/Destroy() + QDEL_LIST(allocated) + QDEL_NULL(infection_block) + return ..() + +/datum/unit_test/voidcrew_nanite_research/infection/proc/setup_infection(program_type) + infection_block = SSmapping.request_turf_block_reservation(8, 3, 1, null, /datum/turf_reservation, /turf/open/floor/iron) + TEST_ASSERT_NOTNULL(infection_block, "Could not reserve the infection range fixture") + donor = allocate(/mob/living/carbon/human/consistent, infection_block.bottom_left_turfs[1]) + target = allocate(/mob/living/carbon/human/consistent/nanite_infection_test, get_step(donor, EAST)) + source_swarm = donor.AddComponent(/datum/component/nanites) + infection_program = allocate(program_type) + source_swarm.add_program(null, infection_program) + source_swarm.cloud_id = 91 + source_swarm.cloud_ship_ref = WEAKREF(donor) // Distinct pairing sentinel; never synced as a cloud. + source_swarm.next_sync = INFINITY + return TRUE + +/datum/unit_test/voidcrew_nanite_research/infection/proc/check_capacity_and_pairing() + var/datum/component/nanites/target_swarm = target.GetComponent(/datum/component/nanites) + TEST_ASSERT_NOTNULL(target_swarm, "A naked target did not receive nanites") + TEST_ASSERT(locate(infection_program.type) in target_swarm.programs, "Infection did not copy the donor's programming") + TEST_ASSERT_EQUAL(target_swarm.cloud_id, 0, "Infection inherited the donor's cloud ID") + TEST_ASSERT_NULL(target_swarm.cloud_ship_ref, "Infection inherited the donor's cloud pairing") + qdel(target_swarm) + var/obj/item/organ/cyberimp/cyberware/test_full_body/bulk = allocate(/obj/item/organ/cyberimp/cyberware/test_full_body) + TEST_ASSERT(bulk.Insert(target, TRUE), "Could not fill the target's capacity") + target_swarm = target.AddComponent(/datum/component/nanites) + var/datum/nanite_program/relay/incumbent = allocate(/datum/nanite_program/relay) + target_swarm.add_program(null, incumbent) + incumbent.activation_code = 17 + target_swarm.cloud_id = 92 + var/datum/weakref/own_pairing = WEAKREF(target) + target_swarm.cloud_ship_ref = own_pairing + target_swarm.next_sync = INFINITY + // Spreading may replace incumbents; Sting must refuse the existing host outright. + attempt_infection() + TEST_ASSERT(incumbent in target_swarm.programs, "Infection deleted an incumbent despite the capacity gate") + TEST_ASSERT_EQUAL(length(target_swarm.programs), 1, "Infection partially installed an over-capacity loadout") + TEST_ASSERT_EQUAL(incumbent.activation_code, 17, "Rejected infection changed incumbent settings") + TEST_ASSERT_EQUAL(target_swarm.cloud_id, 92, "Infection replaced the target's cloud ID") + TEST_ASSERT_EQUAL(target_swarm.cloud_ship_ref, own_pairing, "Infection replaced the target's cloud pairing") + qdel(target_swarm) + attempt_infection() // New hosts must also use the complete capacity gate. + target_swarm = target.GetComponent(/datum/component/nanites) + TEST_ASSERT_NOTNULL(target_swarm, "An over-capacity target did not receive its empty swarm") + TEST_ASSERT_EQUAL(length(target_swarm.programs), 0, "Infection bypassed capacity on a new host") + TEST_ASSERT_EQUAL(target_swarm.cloud_id, 0, "A rejected loadout inherited the donor's cloud") + TEST_ASSERT_NULL(target_swarm.cloud_ship_ref, "A rejected loadout inherited the donor's pairing") + +/datum/unit_test/voidcrew_nanite_research/infection/proc/attempt_infection() + if(istype(infection_program, /datum/nanite_program/spreading)) + var/datum/nanite_program/spreading/spreading = infection_program + spreading.spread_cooldown = world.time + spreading.active_effect() + else + infection_program.next_trigger = world.time + infection_program.trigger() + +/datum/unit_test/voidcrew_nanite_research/infection/spreading/Run() + TEST_ASSERT(setup_infection(/datum/nanite_program/spreading/infection_test), "Could not set up spreading") + var/datum/nanite_program/spreading/infection_test/program = infection_program + program.spread_cooldown = world.time + 1 + program.active_effect() + TEST_ASSERT_EQUAL(length(program.infection_rolls), 0, "Spreading ran before its cooldown expired") + program.spread_cooldown = world.time + var/attempt_time = world.time + program.active_effect() + TEST_ASSERT_EQUAL(program.spread_cooldown, attempt_time + 5 SECONDS, "Spreading lost its five-second spacing") + TEST_ASSERT_EQUAL(program.infection_rolls[1], 25, "Spreading changed its per-target probability") + TEST_ASSERT_EQUAL(program.infection_rolls[2], 100, "A naked target received suit BIO protection") + program.active_effect() + TEST_ASSERT_EQUAL(length(program.infection_rolls), 2, "Spreading repeated inside its cooldown") + check_capacity_and_pairing() + qdel(target.GetComponent(/datum/component/nanites)) + var/obj/item/organ/cyberimp/cyberware/test_full_body/bulk = target.get_organ_slot("voidcrew_test_chrome_bulk") + bulk.Remove(target, TRUE) + var/obj/item/clothing/suit/bio_suit/suit = allocate(/obj/item/clothing/suit/bio_suit) + target.equip_to_slot(suit, ITEM_SLOT_OCLOTHING) + attempt_infection() + TEST_ASSERT_NULL(target.GetComponent(/datum/component/nanites), "Spreading ignored full suit BIO protection") + TEST_ASSERT_EQUAL(program.infection_rolls[length(program.infection_rolls)], 0, "Spreading changed full BIO resistance") + target.temporarilyRemoveItemFromInventory(suit, TRUE) + var/obj/item/clothing/suit/nanite_infection_test/partial = allocate(/obj/item/clothing/suit/nanite_infection_test) + target.equip_to_slot(partial, ITEM_SLOT_OCLOTHING) + attempt_infection() + TEST_ASSERT_EQUAL(program.infection_rolls[length(program.infection_rolls)], 40, "Spreading changed partial BIO resistance") + qdel(target.GetComponent(/datum/component/nanites)) + target.temporarilyRemoveItemFromInventory(partial, TRUE) + var/turf/origin = get_turf(donor) + target.forceMove(locate(origin.x + 6, origin.y, origin.z)) + program.infection_rolls.Cut() + attempt_infection() + TEST_ASSERT_EQUAL(length(program.infection_rolls), 0, "Spreading reached beyond five tiles") + target.forceMove(locate(origin.x + 5, origin.y, origin.z)) + attempt_infection() + TEST_ASSERT_NOTNULL(target.GetComponent(/datum/component/nanites), "Spreading did not reach its five-tile boundary") + +/datum/unit_test/voidcrew_nanite_research/infection/sting/Run() + TEST_ASSERT(setup_infection(/datum/nanite_program/nanite_sting/infection_test), "Could not set up Sting") + var/datum/nanite_program/nanite_sting/infection_test/program = infection_program + var/initial_volume = source_swarm.nanite_volume + var/turf/origin = get_turf(donor) + target.forceMove(locate(origin.x + 2, origin.y, origin.z)) + program.trigger() + TEST_ASSERT_NULL(target.GetComponent(/datum/component/nanites), "Sting reached beyond one tile") + TEST_ASSERT_EQUAL(source_swarm.nanite_volume, initial_volume, "A Sting with no target did not refund its cost") + target.forceMove(get_step(donor, EAST)) + target.infection_adjacent = FALSE + attempt_infection() + TEST_ASSERT_NULL(target.GetComponent(/datum/component/nanites), "Sting bypassed adjacency") + target.infection_adjacent = TRUE + program.next_trigger = world.time + 1 + program.trigger() + TEST_ASSERT_EQUAL(length(program.infection_rolls), 0, "Sting ran before its cooldown expired") + var/attempt_time = world.time + attempt_infection() + TEST_ASSERT_EQUAL(program.next_trigger, attempt_time + 10 SECONDS, "Sting lost its ten-second cooldown") + TEST_ASSERT_EQUAL(source_swarm.nanite_volume, initial_volume - 5, "Sting changed its five-nanite trigger cost") + TEST_ASSERT_EQUAL(program.infection_rolls[1], 100, "A naked Sting target received suit BIO protection") + program.trigger() + TEST_ASSERT_EQUAL(source_swarm.nanite_volume, initial_volume - 5, "Sting consumed fuel during cooldown") + var/datum/component/nanites/target_swarm = target.GetComponent(/datum/component/nanites) + TEST_ASSERT_NOTNULL(target_swarm, "Sting did not infect an adjacent naked target") + var/target_volume = target_swarm.nanite_volume + attempt_infection() + TEST_ASSERT_EQUAL(length(program.infection_rolls), 1, "Sting attempted to reinfect an existing host") + TEST_ASSERT_EQUAL(target_swarm.nanite_volume, target_volume, "Sting added volume to an existing host") + check_capacity_and_pairing() + qdel(target.GetComponent(/datum/component/nanites)) + var/obj/item/organ/cyberimp/cyberware/test_full_body/bulk = target.get_organ_slot("voidcrew_test_chrome_bulk") + bulk.Remove(target, TRUE) + var/obj/item/clothing/suit/bio_suit/suit = allocate(/obj/item/clothing/suit/bio_suit) + target.equip_to_slot(suit, ITEM_SLOT_OCLOTHING) + attempt_infection() + TEST_ASSERT_NULL(target.GetComponent(/datum/component/nanites), "Sting ignored full suit BIO protection") + TEST_ASSERT_EQUAL(program.infection_rolls[length(program.infection_rolls)], 0, "Sting changed full BIO resistance") + target.temporarilyRemoveItemFromInventory(suit, TRUE) + var/obj/item/clothing/suit/nanite_infection_test/partial = allocate(/obj/item/clothing/suit/nanite_infection_test) + target.equip_to_slot(partial, ITEM_SLOT_OCLOTHING) + attempt_infection() + TEST_ASSERT_EQUAL(program.infection_rolls[length(program.infection_rolls)], 40, "Sting changed partial BIO resistance") From 3e443677dd3602bc41d0ea9de5f1c559538f99cc Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:58:10 -0700 Subject: [PATCH 028/105] Close nanite disk export arbitrage --- voidcrew/modules/cargo/exports.dm | 2 +- .../unit_tests/voidcrew_economy_metrics.dm | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/voidcrew/modules/cargo/exports.dm b/voidcrew/modules/cargo/exports.dm index 5f93b893cf9..08954e677aa 100644 --- a/voidcrew/modules/cargo/exports.dm +++ b/voidcrew/modules/cargo/exports.dm @@ -93,7 +93,7 @@ // ========== NANITE TECHNOLOGY ========== /datum/export/nanite_disk - cost = 200 + cost = 0 unit_name = "nanite program disk" export_types = list(/obj/item/disk/nanite_program) diff --git a/voidcrew/modules/unit_tests/voidcrew_economy_metrics.dm b/voidcrew/modules/unit_tests/voidcrew_economy_metrics.dm index d9ba0c1492a..f3737b0379b 100644 --- a/voidcrew/modules/unit_tests/voidcrew_economy_metrics.dm +++ b/voidcrew/modules/unit_tests/voidcrew_economy_metrics.dm @@ -99,3 +99,56 @@ SSmetrics.pending = old_pending SSmetrics.tallies = old_tallies return ..() + +/// Printable disks have no special export reward, regardless of their saved programs. +/datum/unit_test/voidcrew_nanite_disk_exports/Run() + if(!length(GLOB.exports_list)) + setupExports() + var/datum/export/nanite_disk/disk_export = locate(/datum/export/nanite_disk) in GLOB.exports_list + TEST_ASSERT_NOTNULL(disk_export, "The nanite disk export should exist") + TEST_ASSERT_EQUAL(disk_export.cost, 0, "Nanite disks should have no special export reward") + TEST_ASSERT_EQUAL(disk_export.init_cost, 0, "Non-elastic nanite disk valuation should also be zero") + + var/datum/design/nanite_disk/design = allocate(/datum/design/nanite_disk) + var/obj/item/disk/nanite_program/source_disk = allocate(design.build_path) + var/datum/nanite_program/source_program = new /datum/nanite_program/regenerative + source_program.trigger_code = 321 + source_disk.backup += source_program + + for(var/apply_elastic in list(FALSE, TRUE)) + var/datum/export_report/sale_report = allocate(/datum/export_report) + for(var/batch in 1 to 3) + for(var/disk_state in list("blank", "programmed", "copied")) + var/obj/item/disk/nanite_program/disk = allocate(design.build_path) + // Fabricated items retain the materials spent on their design. + disk.set_custom_materials(design.materials) + switch(disk_state) + if("programmed") + disk.backup += new /datum/nanite_program/regenerative + if("copied") + // The cloud controller saves backups through program.copy(). + var/datum/nanite_program/copied_program = source_program.copy() + disk.backup += copied_program + TEST_ASSERT(copied_program != source_program, "A copied disk should contain an independent program") + TEST_ASSERT_EQUAL(copied_program.trigger_code, 321, "The copied disk should retain its saved programming") + + var/context = "[disk_state] disk, batch [batch], elasticity [apply_elastic]" + TEST_ASSERT_EQUAL(disk_export.get_cost(disk, apply_elastic), 0, "[context] should have no special export value") + var/backup_count = length(disk.backup) + var/datum/export_report/quote = export_item_and_contents(disk, apply_elastic = apply_elastic, dry_run = TRUE) + TEST_ASSERT_NULL(quote.total_value[disk_export], "Dry-run valuation should not reward [context]") + TEST_ASSERT_NULL(quote.total_amount[disk_export], "Dry-run valuation should not count [context] as a special export") + TEST_ASSERT(!QDELETED(disk), "Dry-run valuation should preserve [context]") + TEST_ASSERT_EQUAL(length(disk.backup), backup_count, "Dry-run valuation should preserve the programs on [context]") + qdel(quote) + + var/list/recyclable = disk.get_material_composition() + TEST_ASSERT_EQUAL(recyclable[GET_MATERIAL_REF(/datum/material/iron)], 300, "[context] should retain its recyclable iron") + TEST_ASSERT_EQUAL(recyclable[GET_MATERIAL_REF(/datum/material/glass)], 100, "[context] should retain its recyclable glass") + export_item_and_contents(disk, apply_elastic = apply_elastic, dry_run = FALSE, external_report = sale_report) + TEST_ASSERT(QDELETED(disk), "An actual cargo export should consume [context]") + TEST_ASSERT_NULL(sale_report.total_value[disk_export], "Repeated manufacture/export should not reward [context]") + TEST_ASSERT_NULL(sale_report.total_amount[disk_export], "Repeated manufacture/export should not count [context] as a special export") + + disk_export.process() + TEST_ASSERT_EQUAL(disk_export.cost, 0, "Export price recovery should not restore a nanite disk reward") From 57c2fe00ffe5201ff6b747a85094ca45bfc43227 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:03:22 -0700 Subject: [PATCH 029/105] Starting-equipment regressions and first chaplain --- .../jobs/job_types/chaplain/chaplain.dm | 9 ++- .../unit_tests/voidcrew_ship_modules.dm | 78 +++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/code/modules/jobs/job_types/chaplain/chaplain.dm b/code/modules/jobs/job_types/chaplain/chaplain.dm index 6f84c0f840a..4c96c41f4f5 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain.dm @@ -42,6 +42,11 @@ if(!ishuman(spawned)) return var/mob/living/carbon/human/human_spawned = spawned + // VOIDCREW EDIT ADDITION START: Equip the first chaplain's holy weapon too. + var/nrt = GLOB.holy_weapon_type || /obj/item/nullrod + var/obj/item/nullrod/nullrod = new nrt(human_spawned) + human_spawned.put_in_hands(nullrod) + // VOIDCREW EDIT ADDITION END var/obj/item/book/bible/booze/holy_bible = new if(GLOB.religion) if(human_spawned.mind) @@ -55,9 +60,7 @@ holy_bible.inhand_icon_state = GLOB.bible_inhand_icon_state to_chat(human_spawned, span_boldnotice("There is already an established religion onboard the station. You are an acolyte of [GLOB.deity]. Defer to the Chaplain.")) human_spawned.equip_to_storage(holy_bible, ITEM_SLOT_BACK, indirect_action = TRUE, del_on_fail = TRUE) - var/nrt = GLOB.holy_weapon_type || /obj/item/nullrod - var/obj/item/nullrod/nullrod = new nrt(human_spawned) - human_spawned.put_in_hands(nullrod) + // VOIDCREW EDIT: Holy weapon creation moved before the religion branch. if(GLOB.religious_sect) GLOB.religious_sect.on_conversion(human_spawned) return diff --git a/voidcrew/modules/unit_tests/voidcrew_ship_modules.dm b/voidcrew/modules/unit_tests/voidcrew_ship_modules.dm index 8fe76e92923..3a45cef6abf 100644 --- a/voidcrew/modules/unit_tests/voidcrew_ship_modules.dm +++ b/voidcrew/modules/unit_tests/voidcrew_ship_modules.dm @@ -226,3 +226,81 @@ module.job_slots_add_by_theme -= "medical" actual = get_module_job_definitions(null, selections, slots, "medical") TEST_ASSERT_EQUAL(actual[1], shared[1], "removing an override did not restore the existing room crew") + +/// First and subsequent chaplains receive one holy weapon, even with occupied hands. +/datum/unit_test/voidcrew_chaplain_starting_equipment + var/original_religion + var/original_deity + var/original_bible_name + var/original_bible_icon_state + var/original_bible_inhand_icon_state + var/original_holy_weapon_type + var/datum/religion_sect/original_religious_sect + +/datum/unit_test/voidcrew_chaplain_starting_equipment/New() + ..() + original_religion = GLOB.religion + original_deity = GLOB.deity + original_bible_name = GLOB.bible_name + original_bible_icon_state = GLOB.bible_icon_state + original_bible_inhand_icon_state = GLOB.bible_inhand_icon_state + original_holy_weapon_type = GLOB.holy_weapon_type + original_religious_sect = GLOB.religious_sect + +/datum/unit_test/voidcrew_chaplain_starting_equipment/Destroy() + GLOB.religion = original_religion + GLOB.deity = original_deity + GLOB.bible_name = original_bible_name + GLOB.bible_icon_state = original_bible_icon_state + GLOB.bible_inhand_icon_state = original_bible_inhand_icon_state + GLOB.holy_weapon_type = original_holy_weapon_type + GLOB.religious_sect = original_religious_sect + return ..() + +/datum/unit_test/voidcrew_chaplain_starting_equipment/Run() + var/datum/job/chaplain/chaplain_job = allocate(/datum/job/chaplain) + GLOB.religious_sect = null + GLOB.bible_icon_state = null + GLOB.bible_inhand_icon_state = null + for(var/selected_weapon in list(null, /obj/item/nullrod/claymore)) + for(var/full_hands in list(FALSE, TRUE)) + GLOB.religion = null + GLOB.deity = null + GLOB.bible_name = null + GLOB.holy_weapon_type = selected_weapon + check_chaplain(chaplain_job, full_hands, selected_weapon || /obj/item/nullrod, HOLY_ROLE_HIGHPRIEST) + TEST_ASSERT(GLOB.religion, "The first chaplain did not establish a religion") + check_chaplain(chaplain_job, full_hands, selected_weapon || /obj/item/nullrod, HOLY_ROLE_PRIEST) + TEST_ASSERT_EQUAL(GLOB.holy_weapon_type, selected_weapon, "Spawning a chaplain changed the selected holy weapon") + +/datum/unit_test/voidcrew_chaplain_starting_equipment/proc/check_chaplain(datum/job/chaplain/chaplain_job, full_hands, expected_weapon, expected_role) + var/mob/living/carbon/human/consistent/chaplain = allocate(/mob/living/carbon/human/consistent) + chaplain.mind_initialize() + chaplain.equipOutfit(/datum/outfit/job/chaplain) + if(full_hands) + for(var/hand_index in 1 to length(chaplain.held_items)) + TEST_ASSERT(chaplain.put_in_hand(allocate(/obj/item/pen), hand_index), "Could not fill the chaplain's hands") + var/turf/spawn_turf = get_turf(chaplain) + var/list/previous_contents = spawn_turf.contents.Copy() + chaplain_job.after_spawn(chaplain, null) + + var/list/holy_weapons = chaplain.get_all_contents_type(/obj/item/nullrod) + for(var/obj/item/nullrod/dropped_weapon in (spawn_turf.contents - previous_contents)) + holy_weapons += dropped_weapon + var/context = "holy role [expected_role], full hands [full_hands], weapon [expected_weapon]" + TEST_ASSERT_EQUAL(length(holy_weapons), 1, "Chaplain must receive exactly one holy weapon ([context])") + var/obj/item/nullrod/holy_weapon = holy_weapons[1] + TEST_ASSERT_EQUAL(holy_weapon.type, expected_weapon, "Chaplain received the wrong holy weapon ([context])") + if(full_hands) + TEST_ASSERT_EQUAL(holy_weapon.loc, spawn_turf, "The holy weapon must drop at the chaplain's feet when hands are full") + TEST_ASSERT_EQUAL(chaplain.get_num_held_items(), 2, "The holy weapon displaced an existing held item") + else + TEST_ASSERT(chaplain.is_holding(holy_weapon), "The chaplain did not hold their holy weapon ([context])") + if(!GLOB.holy_weapon_type) + TEST_ASSERT(holy_weapon.GetComponent(/datum/component/subtype_picker), "The default null rod lost its weapon selection") + TEST_ASSERT_EQUAL(chaplain.mind.holy_role, expected_role, "Chaplain received the wrong holy role ([context])") + var/list/bibles = chaplain.get_all_contents_type(/obj/item/book/bible/booze) + TEST_ASSERT_EQUAL(length(bibles), 1, "Chaplain must retain their bible ([context])") + var/obj/item/book/bible/booze/holy_bible = bibles[1] + TEST_ASSERT_EQUAL(holy_bible.name, GLOB.bible_name, "Chaplain bible lost the established name") + TEST_ASSERT_EQUAL(holy_bible.deity_name, GLOB.deity, "Chaplain bible lost the established deity") From 2beb7796a6f778e598d5cd1794b47391292404e9 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:17:52 -0700 Subject: [PATCH 030/105] Limit alternate core sources --- .../basic/icemoon/ice_demon/ice_demon.dm | 3 +- .../supermatter/supermatter_extra_effects.dm | 16 +- tgstation.dme | 2 + .../modules/power/supermatter_anomalies.dm | 21 ++ voidcrew/modules/anomalies/core_rewards.dm | 77 ++++++ .../hostile/mining_mobs/ice_demon.dm | 3 +- .../modules/trade/shop_catalog_suit_vendor.dm | 8 +- voidcrew/modules/unit_tests/_unit_tests.dm | 1 + .../unit_tests/voidcrew_anomaly_rewards.dm | 242 ++++++++++++++++++ 9 files changed, 358 insertions(+), 15 deletions(-) create mode 100644 voidcrew/edits/modules/power/supermatter_anomalies.dm create mode 100644 voidcrew/modules/anomalies/core_rewards.dm create mode 100644 voidcrew/modules/unit_tests/voidcrew_anomaly_rewards.dm diff --git a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm index 282ae4d6f55..bd1501aa172 100644 --- a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm +++ b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm @@ -44,8 +44,7 @@ AddElement(/datum/element/simple_flying) /mob/living/basic/mining/ice_demon/death(gibbed) - if(prob(5)) - new /obj/item/raw_anomaly_core/bluespace(loc) + // VOIDCREW EDIT: Core rolls use the spawn-bound allowance in voidcrew/modules/anomalies/core_rewards.dm. return ..() /mob/living/basic/mining/demon_afterimage diff --git a/code/modules/power/supermatter/supermatter_extra_effects.dm b/code/modules/power/supermatter/supermatter_extra_effects.dm index 0724667300f..5ba978c76d1 100644 --- a/code/modules/power/supermatter/supermatter_extra_effects.dm +++ b/code/modules/power/supermatter/supermatter_extra_effects.dm @@ -163,22 +163,24 @@ var/turf/local_turf = pick(RANGE_TURFS(anomalyrange, anomalycenter)) if(!local_turf) return + // VOIDCREW EDIT CHANGE START - Coreless hazards: voidcrew/edits/modules/power/supermatter_anomalies.dm. switch(type) if(FLUX_ANOMALY) var/explosive = has_changed_lifespan ? FLUX_NO_EMP : FLUX_LIGHT_EMP - new /obj/effect/anomaly/flux(local_turf, has_changed_lifespan ? rand(25 SECONDS, 35 SECONDS) : null, FALSE, explosive) + new /obj/effect/anomaly/flux/supermatter(local_turf, has_changed_lifespan ? rand(25 SECONDS, 35 SECONDS) : null, FALSE, explosive) if(GRAVITATIONAL_ANOMALY) - new /obj/effect/anomaly/grav(local_turf, has_changed_lifespan ? rand(20 SECONDS, 30 SECONDS) : null, FALSE) + new /obj/effect/anomaly/grav/supermatter(local_turf, has_changed_lifespan ? rand(20 SECONDS, 30 SECONDS) : null, FALSE) if(PYRO_ANOMALY) - new /obj/effect/anomaly/pyro(local_turf, has_changed_lifespan ? rand(15 SECONDS, 25 SECONDS) : null, FALSE) + new /obj/effect/anomaly/pyro/supermatter(local_turf, has_changed_lifespan ? rand(15 SECONDS, 25 SECONDS) : null, FALSE) if(HALLUCINATION_ANOMALY) - new /obj/effect/anomaly/hallucination/supermatter(local_turf, has_changed_lifespan ? rand(15 SECONDS, 25 SECONDS) : null, FALSE) + new /obj/effect/anomaly/hallucination/supermatter/coreless(local_turf, has_changed_lifespan ? rand(15 SECONDS, 25 SECONDS) : null, FALSE) if(VORTEX_ANOMALY) - new /obj/effect/anomaly/bhole(local_turf, 2 SECONDS, FALSE) + new /obj/effect/anomaly/bhole/supermatter(local_turf, 2 SECONDS, FALSE) if(BIOSCRAMBLER_ANOMALY) - new /obj/effect/anomaly/bioscrambler/docile(local_turf, null, FALSE) + new /obj/effect/anomaly/bioscrambler/docile/supermatter(local_turf, null, FALSE) if(DIMENSIONAL_ANOMALY) - new /obj/effect/anomaly/dimensional(local_turf, null, FALSE) + new /obj/effect/anomaly/dimensional/supermatter(local_turf, null, FALSE) + // VOIDCREW EDIT CHANGE END #undef CHANCE_EQUATION_SLOPE #undef INTEGRITY_EXPONENTIAL_DEGREE diff --git a/tgstation.dme b/tgstation.dme index 0c9037cfd75..60aaf846277 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6904,6 +6904,7 @@ #include "voidcrew\edits\modules\mob\living\carbon\inventory.dm" #include "voidcrew\edits\modules\mod\modules\modules_supply.dm" #include "voidcrew\edits\modules\modular_computers\file_system\programs\budgetordering.dm" +#include "voidcrew\edits\modules\power\supermatter_anomalies.dm" #include "voidcrew\edits\modules\power\turbine\turbine.dm" #include "voidcrew\edits\modules\projectiles\boxes_magazines\_box_magazine.dm" #include "voidcrew\edits\modules\research\designs.dm" @@ -7026,6 +7027,7 @@ #include "voidcrew\modules\ambient_npcs\recruit.dm" #include "voidcrew\modules\ambient_npcs\stranded.dm" #include "voidcrew\modules\ambient_npcs\stranded_lifeboat.dm" +#include "voidcrew\modules\anomalies\core_rewards.dm" #include "voidcrew\modules\antag_ruins\antag_ruin.dm" #include "voidcrew\modules\antag_ruins\ascension.dm" #include "voidcrew\modules\antag_ruins\ascension_mech.dm" diff --git a/voidcrew/edits/modules/power/supermatter_anomalies.dm b/voidcrew/edits/modules/power/supermatter_anomalies.dm new file mode 100644 index 00000000000..3fe088b7eb5 --- /dev/null +++ b/voidcrew/edits/modules/power/supermatter_anomalies.dm @@ -0,0 +1,21 @@ +// Supermatter hazards retain their parent effects without generating a recoverable core. +/obj/effect/anomaly/flux/supermatter + anomaly_core = null + +/obj/effect/anomaly/grav/supermatter + anomaly_core = null + +/obj/effect/anomaly/pyro/supermatter + anomaly_core = null + +/obj/effect/anomaly/hallucination/supermatter/coreless + anomaly_core = null + +/obj/effect/anomaly/bhole/supermatter + anomaly_core = null + +/obj/effect/anomaly/bioscrambler/docile/supermatter + anomaly_core = null + +/obj/effect/anomaly/dimensional/supermatter + anomaly_core = null diff --git a/voidcrew/modules/anomalies/core_rewards.dm b/voidcrew/modules/anomalies/core_rewards.dm new file mode 100644 index 00000000000..2336f9338b7 --- /dev/null +++ b/voidcrew/modules/anomalies/core_rewards.dm @@ -0,0 +1,77 @@ +#define PLANET_ICE_DEMON_CORE_CAP 2 + +/obj/structure/overmap/planet + /// Shared by both demon variants, retained when the surface unloads or relocates. + var/ice_demon_cores_emitted = 0 + +/// Remember the source at spawn, before a demon can be carried to another site. +/datum/component/ice_demon_core_reward + var/datum/weakref/source_planet_ref + /// Preloaded surfaces get their overmap owner after their mapped mobs initialize. + var/turf/pending_spawn_turf + var/core_type + var/drop_chance + /// A failed first roll is final too; revival cannot buy another attempt. + var/attempted = FALSE + +/datum/component/ice_demon_core_reward/Initialize(core_type, drop_chance) + if(!isliving(parent)) + return COMPONENT_INCOMPATIBLE + src.core_type = core_type + src.drop_chance = drop_chance + var/turf/spawn_turf = get_turf(parent) + bind_source(spawn_turf) + if(!source_planet_ref && !SSovermap.initialized) + pending_spawn_turf = spawn_turf + RegisterSignal(SSovermap, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(on_overmap_initialized)) + +/datum/component/ice_demon_core_reward/proc/bind_source(turf/spawn_turf) + var/datum/map_footprint/footprint = map_region_for_turf(spawn_turf) + if(istype(footprint) && istype(footprint.owner, /obj/structure/overmap/planet)) + source_planet_ref = WEAKREF(footprint.owner) + +/datum/component/ice_demon_core_reward/proc/on_overmap_initialized(datum/source) + SIGNAL_HANDLER + UnregisterSignal(SSovermap, COMSIG_SUBSYSTEM_POST_INITIALIZE) + bind_source(pending_spawn_turf) + pending_spawn_turf = null + +/datum/component/ice_demon_core_reward/RegisterWithParent() + RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(on_death)) + +/datum/component/ice_demon_core_reward/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_LIVING_DEATH) + +/datum/component/ice_demon_core_reward/Destroy(force) + UnregisterSignal(SSovermap, COMSIG_SUBSYSTEM_POST_INITIALIZE) + pending_spawn_turf = null + source_planet_ref = null + return ..() + +/datum/component/ice_demon_core_reward/proc/on_death(mob/living/source, gibbed) + SIGNAL_HANDLER + if(attempted) + return + attempted = TRUE + if(!prob(drop_chance) || pending_spawn_turf) + return + var/obj/structure/overmap/planet/source_planet = source_planet_ref?.resolve() + // A deleted source cannot turn a transported demon into an unrestricted reward. + if(source_planet_ref && (!source_planet || source_planet.ice_demon_cores_emitted >= PLANET_ICE_DEMON_CORE_CAP)) + return + var/atom/destination = source.drop_location() + if(!destination) + return + var/obj/item/core = new core_type(destination) + if(!QDELETED(core) && source_planet) + source_planet.ice_demon_cores_emitted++ + +/mob/living/basic/mining/ice_demon/Initialize(mapload) + . = ..() + AddComponent(/datum/component/ice_demon_core_reward, /obj/item/raw_anomaly_core/bluespace, 5) + +/mob/living/simple_animal/hostile/asteroid/old_demon/Initialize(mapload) + . = ..() + AddComponent(/datum/component/ice_demon_core_reward, /obj/item/assembly/signaler/anomaly/bluespace, 20) + +#undef PLANET_ICE_DEMON_CORE_CAP diff --git a/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm b/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm index 9f6813270b1..6dceb0742f7 100644 --- a/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm +++ b/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm @@ -62,6 +62,5 @@ move_resist = MOVE_RESIST_DEFAULT pull_force = PULL_FORCE_DEFAULT new /obj/item/stack/ore/bluespace_crystal(loc, 10) - if(prob(20)) - new /obj/item/assembly/signaler/anomaly/bluespace(loc) + // Core rolls use the shared spawn-bound allowance in anomalies/core_rewards.dm. return ..() diff --git a/voidcrew/modules/trade/shop_catalog_suit_vendor.dm b/voidcrew/modules/trade/shop_catalog_suit_vendor.dm index 9787ef08644..b8343255f06 100644 --- a/voidcrew/modules/trade/shop_catalog_suit_vendor.dm +++ b/voidcrew/modules/trade/shop_catalog_suit_vendor.dm @@ -213,8 +213,8 @@ exclusive_rewards = list( /obj/item/mod/control/pre_equipped/magnate, /obj/item/mod/control/pre_equipped/safeguard, - /obj/item/mod/module/anomaly_locked/kinesis/prebuilt, - /obj/item/mod/module/anomaly_locked/teleporter/prebuilt, + /obj/item/mod/module/anomaly_locked/kinesis/prebuilt/locked, + /obj/item/mod/module/anomaly_locked/teleporter/prebuilt/locked, ) trader_lines = list( TRADER_LINE_SALE = list( @@ -874,8 +874,8 @@ /datum/shop_sku/fitter/rare/mod_antigrav category = "Mobility" name = "MOD anti-gravity module (cored)" - desc = "An anti-gravity module with a gravitational anomaly core already seated, so it works the moment it's installed. Wick does not say where the core came from." - item_path = /obj/item/mod/module/anomaly_locked/antigrav/prebuilt + desc = "An anti-gravity module with a sealed core. Wick does not say where it came from." + item_path = /obj/item/mod/module/anomaly_locked/antigrav/prebuilt/locked price_vouchers = 2 price_credits = 2400 diff --git a/voidcrew/modules/unit_tests/_unit_tests.dm b/voidcrew/modules/unit_tests/_unit_tests.dm index e59bdc52456..6ce95631a4a 100644 --- a/voidcrew/modules/unit_tests/_unit_tests.dm +++ b/voidcrew/modules/unit_tests/_unit_tests.dm @@ -29,6 +29,7 @@ #include "voidcrew_ambient_recruiters.dm" #include "voidcrew_ambient_strays.dm" #include "voidcrew_ammo_box_materials.dm" +#include "voidcrew_anomaly_rewards.dm" #include "voidcrew_anomaly_trade.dm" #include "voidcrew_assault_pod.dm" #include "voidcrew_autopilot_course.dm" diff --git a/voidcrew/modules/unit_tests/voidcrew_anomaly_rewards.dm b/voidcrew/modules/unit_tests/voidcrew_anomaly_rewards.dm new file mode 100644 index 00000000000..c12e849133c --- /dev/null +++ b/voidcrew/modules/unit_tests/voidcrew_anomaly_rewards.dm @@ -0,0 +1,242 @@ +/// Small footprints borrow the test level without owning its ground or teardown. +/datum/unit_test/voidcrew_anomaly_rewards + abstract_type = /datum/unit_test/voidcrew_anomaly_rewards + var/list/planets = list() + +/datum/unit_test/voidcrew_anomaly_rewards/Destroy() + for(var/obj/structure/overmap/planet/planet in planets) + planet.footprint = null + planet.mapzone = null + planets.Cut() + return ..() + +/datum/unit_test/voidcrew_anomaly_rewards/proc/attach_surface(obj/structure/overmap/planet/planet, turf/site) + var/datum/map_footprint/footprint = allocate(/datum/map_footprint, null, "planet", 1, planet) + footprint.attach_level(SSmapping.z_list[site.z]) + footprint.set_rect(site.x, site.y, 1, 1) + planet.footprint = footprint + planet.loaded = TRUE + return footprint + +/datum/unit_test/voidcrew_anomaly_rewards/proc/make_planet(turf/site, band = 1) + var/obj/structure/overmap/planet/planet = allocate(/obj/structure/overmap/planet) + planets += planet + planet.zone_band = band // ZONE_GREEN/YELLOW/RED are included after test files. + attach_surface(planet, site) + return planet + +/datum/unit_test/voidcrew_anomaly_rewards/proc/make_demon(demon_type, turf/site, chance = 100) + var/mob/living/demon = allocate(demon_type, site) + var/datum/component/ice_demon_core_reward/reward = demon.GetComponent(/datum/component/ice_demon_core_reward) + TEST_ASSERT_NOTNULL(reward, "[demon_type] has no core reward component") + if(istype(demon, /mob/living/basic/mining/ice_demon)) + var/mob/living/basic/mining/ice_demon/watcher = demon + TEST_ASSERT_EQUAL(reward.drop_chance, 5, "Watcher core probability changed") + TEST_ASSERT_EQUAL(watcher.crusher_loot, /obj/item/crusher_trophy/ice_demon_cube, "Watcher lost its crusher trophy") + watcher.basic_mob_flags &= ~DEL_ON_DEATH + else + var/mob/living/simple_animal/hostile/asteroid/old_demon/primordial = demon + TEST_ASSERT_EQUAL(reward.drop_chance, 20, "Primordial core probability changed") + primordial.del_on_death = FALSE + reward.drop_chance = chance + return demon + +/datum/unit_test/voidcrew_anomaly_rewards/proc/cores_on(turf/site) + . = 0 + for(var/obj/item/item in site) + if(istype(item, /obj/item/raw_anomaly_core) || istype(item, /obj/item/assembly/signaler/anomaly)) + .++ + +/datum/unit_test/voidcrew_anomaly_rewards/proc/ore_on(turf/site) + . = 0 + for(var/obj/item/stack/ore/bluespace_crystal/ore in site) + . += ore.amount + +/// The two-core allowance is shared by raw and stabilized drops in every zone. +/datum/unit_test/voidcrew_anomaly_rewards/combined_cap/Run() + for(var/band in 1 to 3) + var/turf/site = locate(run_loc_floor_bottom_left.x + band - 1, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z) + var/obj/structure/overmap/planet/planet = make_planet(site, band) + var/mob/living/watcher = make_demon(/mob/living/basic/mining/ice_demon, site) + watcher.death(FALSE) + TEST_ASSERT_EQUAL(ore_on(site), 3, "Watcher ore drop changed") + TEST_ASSERT_NOTNULL(locate(/obj/item/raw_anomaly_core/bluespace) in site, "Watcher did not emit its raw core") + var/mob/living/primordial = make_demon(/mob/living/simple_animal/hostile/asteroid/old_demon, site) + primordial.death(FALSE) + TEST_ASSERT_EQUAL(ore_on(site), 13, "Primordial ore drop changed") + TEST_ASSERT_NOTNULL(locate(/obj/item/assembly/signaler/anomaly/bluespace) in site, "Primordial did not emit its stabilized core") + for(var/demon_type in list(/mob/living/basic/mining/ice_demon, /mob/living/simple_animal/hostile/asteroid/old_demon)) + var/mob/living/excess = make_demon(demon_type, site) + excess.death(FALSE) + TEST_ASSERT_EQUAL(cores_on(site), 2, "Band [band] bypassed PLANET_ICE_DEMON_CORE_CAP") + TEST_ASSERT_EQUAL(planet.ice_demon_cores_emitted, 2, "The shared counter does not match emitted items") + TEST_ASSERT_EQUAL(ore_on(site), 26, "The core cap suppressed ore") + +/// Both successful and failed first rolls remain final after repeated deaths and revival. +/datum/unit_test/voidcrew_anomaly_rewards/repeated_deaths/Run() + var/turf/site = run_loc_floor_bottom_left + var/list/demon_types = list(/mob/living/basic/mining/ice_demon, /mob/living/simple_animal/hostile/asteroid/old_demon) + for(var/demon_type in demon_types) + var/obj/structure/overmap/planet/planet = make_planet(site) + var/mob/living/missed = make_demon(demon_type, site, 0) + missed.death(FALSE) + TEST_ASSERT_EQUAL(planet.ice_demon_cores_emitted, 0, "A failed roll consumed the allowance") + var/datum/component/ice_demon_core_reward/reward = missed.GetComponent(/datum/component/ice_demon_core_reward) + reward.drop_chance = 100 + missed.death(FALSE) + missed.revive(HEAL_ALL) + TEST_ASSERT_EQUAL(missed.stat, CONSCIOUS, "The failed-roll fixture did not revive") + missed.death(FALSE) + TEST_ASSERT_EQUAL(cores_on(site), 0, "A failed roll was rerolled by death or revival") + var/mob/living/success = make_demon(demon_type, site) + success.death(FALSE) + success.death(FALSE) + success.revive(HEAL_ALL) + TEST_ASSERT_EQUAL(success.stat, CONSCIOUS, "The successful-roll fixture did not revive") + success.death(FALSE) + TEST_ASSERT_EQUAL(cores_on(site), 1, "A successful roll was repeated by death or revival") + TEST_ASSERT_EQUAL(planet.ice_demon_cores_emitted, 1, "Repeated deaths changed the source allowance") + // Retire this footprint before the next variant borrows the same test tile. + qdel(planet.footprint) + planet.footprint = null + for(var/obj/item/item in site) + qdel(item) + +/// Real unload/relocation replaces the footprint, while transported demons retain their source. +/datum/unit_test/voidcrew_anomaly_rewards/transport_reload/Run() + var/turf/home = run_loc_floor_bottom_left + var/turf/away = get_step(home, EAST) + var/turf/reloaded = get_step(home, NORTH) + var/obj/structure/overmap/planet/source = make_planet(home) + var/obj/structure/overmap/planet/neighbour = make_planet(away) + var/mob/living/first = make_demon(/mob/living/basic/mining/ice_demon, home) + var/mob/living/transported = make_demon(/mob/living/simple_animal/hostile/asteroid/old_demon, home) + first.forceMove(away) + transported.forceMove(away) + first.death(FALSE) + TEST_ASSERT_EQUAL(source.ice_demon_cores_emitted, 1, "Transport escaped the source allowance") + TEST_ASSERT_EQUAL(neighbour.ice_demon_cores_emitted, 0, "A transported demon charged its destination") + // An empty level list exercises the real teardown without wiping borrowed test ground. + var/datum/map_zone/zone = allocate(/datum/map_zone) + zone.slots = list(source.footprint) + zone.slot_capacity = 1 + source.footprint.zone = zone + source.mapzone = zone + var/datum/map_footprint/old_footprint = source.footprint + TEST_ASSERT(source.unload_level(), "The source planet did not unload") + TEST_ASSERT(QDELETED(old_footprint), "Unloading did not replace the old footprint") + TEST_ASSERT_EQUAL(source.ice_demon_cores_emitted, 1, "Unloading or relocation reset the allowance") + attach_surface(source, reloaded) + transported.death(FALSE) + TEST_ASSERT_EQUAL(source.ice_demon_cores_emitted, 2, "A transported demon lost its source after unload") + var/mob/living/excess = make_demon(/mob/living/basic/mining/ice_demon, reloaded) + excess.death(FALSE) + TEST_ASSERT_EQUAL(cores_on(reloaded), 0, "Reloading reset the allowance") + var/mob/living/local = make_demon(/mob/living/simple_animal/hostile/asteroid/old_demon, away) + local.death(FALSE) + TEST_ASSERT_EQUAL(neighbour.ice_demon_cores_emitted, 1, "Independent planets shared an allowance") + TEST_ASSERT_EQUAL(cores_on(away), 3, "Transport or independent planets lost an allowed core") + +/// Roundstart surfaces receive their marker after mapped mobs, using the original spawn tile. +/datum/unit_test/voidcrew_anomaly_rewards/preloaded_source/Run() + var/turf/home = run_loc_floor_bottom_left + var/turf/away = get_step(home, EAST) + var/was_initialized = SSovermap.initialized + SSovermap.initialized = FALSE + var/mob/living/demon = make_demon(/mob/living/basic/mining/ice_demon, home) + SSovermap.initialized = was_initialized + var/datum/component/ice_demon_core_reward/reward = demon.GetComponent(/datum/component/ice_demon_core_reward) + TEST_ASSERT_EQUAL(reward.pending_spawn_turf, home, "The early spawn did not remember its source tile") + var/obj/structure/overmap/planet/source = make_planet(home) + var/obj/structure/overmap/planet/neighbour = make_planet(away) + demon.forceMove(away) + reward.on_overmap_initialized(SSovermap) + TEST_ASSERT_EQUAL(reward.source_planet_ref?.resolve(), source, "Early-spawn adoption followed a moved demon") + TEST_ASSERT_NULL(reward.pending_spawn_turf, "Early-spawn adoption retained a turf reference") + demon.death(FALSE) + TEST_ASSERT_EQUAL(source.ice_demon_cores_emitted, 1, "The preloaded source did not consume its allowance") + TEST_ASSERT_EQUAL(neighbour.ice_demon_cores_emitted, 0, "Preloaded adoption charged the destination") + +/// Drive every supermatter spawn branch, with and without changed lifespans. +/datum/unit_test/voidcrew_anomaly_rewards/supermatter/Run() + var/list/hazards = list( + FLUX_ANOMALY = /obj/effect/anomaly/flux/supermatter, + GRAVITATIONAL_ANOMALY = /obj/effect/anomaly/grav/supermatter, + PYRO_ANOMALY = /obj/effect/anomaly/pyro/supermatter, + HALLUCINATION_ANOMALY = /obj/effect/anomaly/hallucination/supermatter/coreless, + VORTEX_ANOMALY = /obj/effect/anomaly/bhole/supermatter, + BIOSCRAMBLER_ANOMALY = /obj/effect/anomaly/bioscrambler/docile/supermatter, + DIMENSIONAL_ANOMALY = /obj/effect/anomaly/dimensional/supermatter, + ) + for(var/hazard in hazards) + for(var/changed_lifespan in list(FALSE, TRUE)) + supermatter_anomaly_gen(run_loc_floor_bottom_left, hazard, 0, changed_lifespan) + var/obj/effect/anomaly/anomaly = locate(/obj/effect/anomaly) in run_loc_floor_bottom_left + TEST_ASSERT_NOTNULL(anomaly, "Supermatter failed to spawn [hazard]") + TEST_ASSERT_EQUAL(anomaly.type, hazards[hazard], "Supermatter used the wrong hazard subtype") + TEST_ASSERT_NULL(anomaly.anomaly_core, "Supermatter created a core inside [hazard]") + if(istype(anomaly, /obj/effect/anomaly/hallucination/supermatter)) + var/obj/effect/anomaly/hallucination/hallucination = anomaly + TEST_ASSERT(!hallucination.spawn_decoys, "The coreless hallucination hazard regained decoys") + if(hazard == VORTEX_ANOMALY) + TEST_ASSERT_EQUAL(anomaly.lifespan, 2 SECONDS, "Supermatter vortex lifespan changed") + else if(!changed_lifespan) + TEST_ASSERT_EQUAL(anomaly.lifespan, initial(anomaly.lifespan), "Default hazard lifespan changed") + anomaly.anomalyNeutralize() + TEST_ASSERT(QDELETED(anomaly), "The coreless hazard did not neutralize") + TEST_ASSERT_EQUAL(cores_on(run_loc_floor_bottom_left), 0, "Neutralizing [hazard] yielded a core") + var/obj/effect/anomaly/grav/ordinary = allocate(/obj/effect/anomaly/grav) + TEST_ASSERT_NOTNULL(ordinary.anomaly_core, "Supermatter's core suppression affected ordinary anomalies") + +/// Catalog entries supply functioning modules whose seated cores resist the real tool path. +/datum/unit_test/voidcrew_anomaly_rewards/trader_modules/Run() + var/datum/outpost_shop/vendor/suit_fitter/shop = allocate(/datum/outpost_shop/vendor/suit_fitter) + var/list/module_types = list() + for(var/reward in shop.exclusive_rewards) + if(ispath(reward, /obj/item/mod/module/anomaly_locked)) + module_types += reward + var/datum/shop_sku/fitter/rare/mod_antigrav/sku = allocate(/datum/shop_sku/fitter/rare/mod_antigrav) + module_types += sku.item_path + TEST_ASSERT_EQUAL(length(module_types), 3, "The fitter no longer offers all three anomaly modules") + TEST_ASSERT(/obj/item/mod/module/anomaly_locked/kinesis/prebuilt/locked in module_types, "The kinesis reward is not locked") + TEST_ASSERT(/obj/item/mod/module/anomaly_locked/teleporter/prebuilt/locked in module_types, "The teleporter reward is not locked") + TEST_ASSERT(/obj/item/mod/module/anomaly_locked/antigrav/prebuilt/locked in module_types, "The anti-gravity SKU is not locked") + var/mob/living/carbon/human/wearer = allocate(/mob/living/carbon/human/consistent) + var/obj/item/screwdriver/tool = allocate(/obj/item/screwdriver) + for(var/module_type in module_types) + wearer.forceMove(run_loc_floor_bottom_left) + var/obj/item/mod/control/pre_equipped/suit = allocate(/obj/item/mod/control/pre_equipped) + var/obj/item/mod/module/anomaly_locked/module = allocate(module_type) + TEST_ASSERT_NOTNULL(module.core, "[module_type] arrived without a core") + TEST_ASSERT(!module.core_removable, "[module_type] has an extractable core") + var/obj/item/assembly/signaler/anomaly/seated_core = module.core + module.screwdriver_act(wearer, tool) + TEST_ASSERT_EQUAL(module.core, seated_core, "The screwdriver extracted [module_type]'s core") + TEST_ASSERT_EQUAL(seated_core.loc, module, "The seated core escaped its module") + suit.install(module) + TEST_ASSERT_EQUAL(module.mod, suit, "[module_type] could not be installed") + suit.wearer = wearer + suit.active = TRUE + module.part_activated = TRUE + TEST_ASSERT(module.activate(), "[module_type] could not activate") + // Keep the ability check independent of any initial use cooldown. + COOLDOWN_RESET(module, cooldown_timer) + TEST_ASSERT(module.on_active_process(1), "[module_type] failed its powered core check") + if(istype(module, /obj/item/mod/module/anomaly_locked/antigrav)) + TEST_ASSERT(!wearer.has_gravity(), "The locked anti-gravity module did not work") + else if(istype(module, /obj/item/mod/module/anomaly_locked/kinesis)) + var/obj/item/mod/module/anomaly_locked/kinesis/kinesis = module + var/obj/item/target = allocate(/obj/item, get_step(run_loc_floor_bottom_left, EAST)) + // The cursor catcher requires a real client; exercise the use and targeting gates headlessly. + TEST_ASSERT(kinesis.range_check(target), "The locked kinesis module cannot reach a nearby item") + TEST_ASSERT(kinesis.can_grab(target), "The locked kinesis module rejected an ordinary item") + TEST_ASSERT(kinesis.used(), "The locked kinesis module failed its ability use check") + else + var/obj/item/mod/module/anomaly_locked/teleporter/teleporter = module + teleporter.teleport_time = 0 + var/turf/destination = get_step(run_loc_floor_bottom_left, NORTH) + teleporter.on_select_use(destination) + TEST_ASSERT_EQUAL(get_turf(wearer), destination, "The locked teleporter did not teleport") + module.deactivate(FALSE) + suit.uninstall(module) + suit.wearer = null From 6ced2a355db37647ac0b5ecbaeb5c3bd7c5e7f73 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:18:39 -0700 Subject: [PATCH 031/105] Nanite armor and defib review fixes --- voidcrew/modules/cyberware/ware_legend.dm | 10 ++-- .../modules/nanites/code/programs/healing.dm | 10 ++-- .../unit_tests/armor_partial_modifiers.dm | 16 ++++++ .../unit_tests/voidcrew_combat_metrics.dm | 50 +++++++++++++++++++ 4 files changed, 77 insertions(+), 9 deletions(-) diff --git a/voidcrew/modules/cyberware/ware_legend.dm b/voidcrew/modules/cyberware/ware_legend.dm index acfc6943157..aa1c1ec9356 100644 --- a/voidcrew/modules/cyberware/ware_legend.dm +++ b/voidcrew/modules/cyberware/ware_legend.dm @@ -818,14 +818,13 @@ /datum/action/cooldown/cyberware/piledriver_leap/proc/crush_victim(mob/living/jumper, mob/living/victim) if(QDELETED(victim) || QDELETED(jumper)) return - var/blocked = victim.run_armor_check(attack_flag = MELEE) if(iscarbon(victim)) var/mob/living/carbon/carbon_victim = victim - if(prob(CYBERWARE_PILEDRIVER_CRUSH_SPREAD_CHANCE)) + if(should_spread_crush_damage()) carbon_victim.apply_damage( CYBERWARE_PILEDRIVER_CRUSH_DAMAGE, BRUTE, - blocked = blocked, + blocked = 0, // Forced damage bypasses armor, including nanite armor accounting. forced = TRUE, spread_damage = TRUE, attack_direction = jumper.dir, @@ -839,7 +838,7 @@ victim.apply_damage( CYBERWARE_PILEDRIVER_CRUSH_DAMAGE, BRUTE, - blocked = blocked, + blocked = 0, forced = TRUE, attack_direction = jumper.dir, ) @@ -853,6 +852,9 @@ ) log_combat(jumper, victim, "crushed with a Meteor Piledriver landing") +/datum/action/cooldown/cyberware/piledriver_leap/proc/should_spread_crush_damage() + return prob(CYBERWARE_PILEDRIVER_CRUSH_SPREAD_CHANCE) + #undef CYBERWARE_CASCADE_WINDOW #undef CYBERWARE_CASCADE_CRASH #undef CYBERWARE_CASCADE_DODGE_CHANCE diff --git a/voidcrew/modules/nanites/code/programs/healing.dm b/voidcrew/modules/nanites/code/programs/healing.dm index 9f2721f9365..05c073f5829 100644 --- a/voidcrew/modules/nanites/code/programs/healing.dm +++ b/voidcrew/modules/nanites/code/programs/healing.dm @@ -233,24 +233,24 @@ /datum/nanite_program/defib/proc/zap(datum/weakref/intended_host) var/mob/living/carbon/patient = intended_host?.resolve() - if(QDELETED(patient) || host_mob != patient || !check_revivable()) + if(QDELETED(patient) || host_mob != patient || !check_revivable() || capacity_blocked()) return playsound(patient, 'sound/machines/defib/defib_charge.ogg', 50, FALSE) sleep(3 SECONDS) - if(QDELETED(src) || QDELETED(patient) || host_mob != patient) + if(QDELETED(src) || QDELETED(patient) || host_mob != patient || capacity_blocked()) return playsound(patient, 'sound/machines/defib/defib_zap.ogg', 50, FALSE) - if(!defibrillate()) + if(!defibrillate() && !capacity_blocked()) playsound(patient, 'sound/machines/defib/defib_failed.ogg', 50, FALSE) /// Rechecked after the windup, immediately before healing and revival. /datum/nanite_program/defib/proc/defibrillate() - if(!check_revivable()) + if(!check_revivable() || capacity_blocked()) return FALSE var/mob/living/carbon/C = host_mob C.heal_for_defib() C.set_heartattack(FALSE) - if(!C.revive_from("nanites")) + if(capacity_blocked() || !C.revive_from("nanites")) return FALSE playsound(C, 'sound/machines/defib/defib_success.ogg', 50, FALSE) C.emote("gasp") diff --git a/voidcrew/modules/unit_tests/armor_partial_modifiers.dm b/voidcrew/modules/unit_tests/armor_partial_modifiers.dm index 0e6ce992ef3..8263ff48ecf 100644 --- a/voidcrew/modules/unit_tests/armor_partial_modifiers.dm +++ b/voidcrew/modules/unit_tests/armor_partial_modifiers.dm @@ -103,6 +103,22 @@ chest.receive_damage(20, blocked = 30, wound_bonus = CANT_WOUND) TEST_ASSERT_EQUAL(swarm.nanite_volume, before, "Forced, nonphysical, zero, healing or direct limb damage spent nanites") +/// Exercise the real forced spread hit with a nonzero armor check, without relying on RNG. +/datum/action/cooldown/cyberware/piledriver_leap/nanite_accounting_test/should_spread_crush_damage() + return TRUE + +/datum/unit_test/armor_partial_modifiers/nanites/forced_piledriver/Run() + setup() + var/mob/living/carbon/human/jumper = allocate(/mob/living/carbon/human/consistent) + var/obj/item/organ/cyberimp/cyberware/piledriver/frame = allocate(/obj/item/organ/cyberimp/cyberware/piledriver) + var/datum/action/cooldown/cyberware/piledriver_leap/nanite_accounting_test/leap = allocate(/datum/action/cooldown/cyberware/piledriver_leap/nanite_accounting_test, frame) + TEST_ASSERT_EQUAL(patient.run_armor_check(attack_flag = MELEE, silent = TRUE), 30, "Forced-hit fixture has no armor to bypass") + var/before = swarm.nanite_volume + leap.crush_victim(jumper, patient) + TEST_ASSERT(abs(patient.getBruteLoss() - 60) <= DAMAGE_PRECISION, "Forced Piledriver spread damage was reduced by armor") // CYBERWARE_PILEDRIVER_CRUSH_DAMAGE + TEST_ASSERT_EQUAL(swarm.nanite_volume, before, "Forced Piledriver damage spent nanites on bypassed armor") + TEST_ASSERT(hardening.passive_enabled && refractive.passive_enabled, "Forced damage disabled funded nanite armor") + /datum/armor/nanite_accounting_test melee = 75 bullet = 75 diff --git a/voidcrew/modules/unit_tests/voidcrew_combat_metrics.dm b/voidcrew/modules/unit_tests/voidcrew_combat_metrics.dm index e99eee462bb..990c95c18bc 100644 --- a/voidcrew/modules/unit_tests/voidcrew_combat_metrics.dm +++ b/voidcrew/modules/unit_tests/voidcrew_combat_metrics.dm @@ -11,6 +11,7 @@ var/patient_number = 0 var/shocks = 0 var/nested_restored = FALSE + var/obj/item/organ/cyberimp/cyberware/governor_delete/defib_governor /datum/unit_test/voidcrew_combat_metrics/Run() for(var/hit in list("attacked", "shot", "threw and hit", "punched", "kicked")) @@ -445,6 +446,55 @@ TEST_ASSERT_EQUAL(shocks, 0, "A windup failure emitted success effects") TEST_ASSERT_EQUAL(revival_count(windup), 0, "A windup failure was logged as success") program.host_mob = null + check_nanite_capacity_windup() + +/datum/unit_test/voidcrew_combat_metrics/proc/check_nanite_capacity_windup() + var/mob/living/carbon/human/consistent/voidcrew_revival_test/body = patient() + defib_governor = allocate(/obj/item/organ/cyberimp/cyberware/governor_delete) + var/obj/item/organ/cyberimp/cyberware/test_heavy/heavy = allocate(/obj/item/organ/cyberimp/cyberware/test_heavy) + TEST_ASSERT(defib_governor.Insert(body, TRUE), "Could not install the defib capacity governor") + TEST_ASSERT(heavy.Insert(body, TRUE), "Could not install the defib capacity load") + var/datum/component/nanites/swarm = body.AddComponent(/datum/component/nanites) + STOP_PROCESSING(SSnanites, swarm) + swarm.regen_rate = 0 + var/datum/nanite_program/defib/program = allocate(/datum/nanite_program/defib) + TEST_ASSERT_EQUAL(swarm.add_program(null, program), 1, "Could not install the capacity defib fixture") // COMPONENT_PROGRAM_INSTALLED + body.setOxyLoss(250) + body.death() + TEST_ASSERT(program.check_revivable() && !program.capacity_blocked(), "The capacity defib fixture cannot start") + shocks = 0 + RegisterSignal(body, COMSIG_LIVING_MINOR_SHOCK, PROC_REF(note_shock)) + var/health_before = body.health + addtimer(CALLBACK(defib_governor, TYPE_PROC_REF(/obj/item/organ, Remove), body, TRUE), 1) + program.zap(WEAKREF(body)) + TEST_ASSERT(program.capacity_blocked(), "Removing Governor Delete did not overload the defib host") + TEST_ASSERT_EQUAL(body.health, health_before, "Nanites healed after losing capacity during windup") + TEST_ASSERT(!program.defibrillate(), "Direct defibrillation ignored the capacity gate") + TEST_ASSERT_EQUAL(body.health, health_before, "Direct defibrillation healed an overloaded host") + TEST_ASSERT_EQUAL(body.revive_calls, 0, "An overloaded nanite program attempted revival") + TEST_ASSERT_EQUAL(body.stat, DEAD, "Nanites revived after losing capacity during windup") + TEST_ASSERT_EQUAL(shocks, 0, "A capacity windup failure emitted success effects") + TEST_ASSERT_EQUAL(revival_count(body), 0, "A capacity windup failure was logged as success") + + // Healing can notify other systems; capacity must still hold when revival is attempted. + TEST_ASSERT(defib_governor.Insert(body, TRUE), "Could not restore capacity before healing") + RegisterSignal(body, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(remove_defib_governor_on_heal)) + TEST_ASSERT(!program.defibrillate(), "Nanites revived after losing capacity during healing") + TEST_ASSERT(program.capacity_blocked(), "The healing callback did not remove capacity") + TEST_ASSERT(body.health > health_before, "The capacity callback did not run during healing") + TEST_ASSERT_EQUAL(body.revive_calls, 0, "Nanites attempted revival after healing removed capacity") + TEST_ASSERT_EQUAL(body.stat, DEAD, "Healing capacity loss revived the host") + TEST_ASSERT_EQUAL(shocks, 0, "Healing capacity loss emitted success effects") + TEST_ASSERT_EQUAL(revival_count(body), 0, "Healing capacity loss was logged as success") + TEST_ASSERT(defib_governor.Insert(body, TRUE), "Could not restore capacity after healing") + TEST_ASSERT(program.defibrillate(), "Nanite defibrillation did not recover with capacity") + TEST_ASSERT_EQUAL(revival_count(body, "nanites"), 1, "Recovered defibrillation lost its attribution") + defib_governor = null + +/datum/unit_test/voidcrew_combat_metrics/proc/remove_defib_governor_on_heal(mob/living/carbon/body) + SIGNAL_HANDLER + UnregisterSignal(body, COMSIG_LIVING_HEALTH_UPDATE) + defib_governor.Remove(body, TRUE) /datum/unit_test/voidcrew_combat_metrics/proc/blacklist_during_windup(mob/living/body) ADD_TRAIT(body, TRAIT_DEFIB_BLACKLISTED, INNATE_TRAIT) From 10da47d45639201f8a03c7574ed377f817bce608 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:33:22 -0700 Subject: [PATCH 032/105] NPC zone profile core, infrastructure spawn routes and populations --- code/datums/components/spawner.dm | 18 +- code/datums/mapgen/CaveGenerator.dm | 5 +- .../objects/effects/spawners/random/random.dm | 5 + tgstation.dme | 3 + voidcrew/_DEFINES/overmap_zones.dm | 4 +- voidcrew/controllers/subsystem/planet_mobs.dm | 21 +- voidcrew/datums/mapgen/biomes/_biome.dm | 3 +- voidcrew/modules/loot/themes/expedition.dm | 3 - voidcrew/modules/loot/themes/industrial.dm | 3 - voidcrew/modules/loot/themes/occult.dm | 6 - voidcrew/modules/loot/themes/plunder.dm | 3 - voidcrew/modules/loot/themes/syndicate.dm | 3 - voidcrew/modules/loot/zone_mobs.dm | 17 +- voidcrew/modules/npc_scaling/damage.dm | 39 ++ voidcrew/modules/npc_scaling/spawn_hooks.dm | 83 ++++ voidcrew/modules/npc_scaling/zone_profiles.dm | 193 +++++++++ voidcrew/modules/unit_tests/_unit_tests.dm | 1 + .../unit_tests/voidcrew_npc_zone_profiles.dm | 367 ++++++++++++++++++ 18 files changed, 730 insertions(+), 47 deletions(-) create mode 100644 voidcrew/modules/npc_scaling/damage.dm create mode 100644 voidcrew/modules/npc_scaling/spawn_hooks.dm create mode 100644 voidcrew/modules/npc_scaling/zone_profiles.dm create mode 100644 voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm diff --git a/code/datums/components/spawner.dm b/code/datums/components/spawner.dm index 4e7d24ebcc8..7b3fbf0c9c4 100644 --- a/code/datums/components/spawner.dm +++ b/code/datums/components/spawner.dm @@ -33,6 +33,10 @@ src.max_spawn_per_attempt = max_spawn_per_attempt src.spawn_distance = spawn_distance src.spawn_distance_exclude = spawn_distance_exclude + // VOIDCREW EDIT ADDITION START: npc_scaling pins the environmental source now. + var/atom/spawner = parent + spawner.get_npc_spawn_context() + // VOIDCREW EDIT ADDITION END // If set, doesn't instantly spawn a creature when the spawner component is applied. if(initial_spawn_delay) COOLDOWN_START(src, spawn_delay, spawn_time) @@ -109,19 +113,26 @@ for(var/i in 1 to adjusted_spawn_count) var/atom/created var/turf/picked_spot + // VOIDCREW EDIT: a fresh construction context inherits the parent's pinned site. + var/datum/npc_spawn_context/context = new(spawner) if(spawn_distance == 1) - created = new chosen_mob_type(spawner.loc) + created = spawn_npc_in_zone(chosen_mob_type, spawner.loc, context, FALSE) // VOIDCREW EDIT: npc_scaling else if(spawn_distance >= 1 && spawn_distance_exclude >= 1) picked_spot = pick(turf_peel(spawn_distance, spawn_distance_exclude, spawner.loc, view_based = TRUE)) if(!picked_spot) picked_spot = pick(circle_range_turfs(spawner.loc, spawn_distance)) if(picked_spot == spawner.loc) SEND_SIGNAL(spawner, COMSIG_SPAWNER_SPAWNED_DEFAULT) - created = new chosen_mob_type(picked_spot) + created = spawn_npc_in_zone(chosen_mob_type, picked_spot, context, FALSE) // VOIDCREW EDIT: npc_scaling else if (spawn_distance >= 1) picked_spot = pick(circle_range_turfs(spawner.loc, spawn_distance)) - created = new chosen_mob_type(picked_spot) + created = spawn_npc_in_zone(chosen_mob_type, picked_spot, context, FALSE) // VOIDCREW EDIT: npc_scaling + + // VOIDCREW EDIT ADDITION START + if(QDELETED(created)) + continue + // VOIDCREW EDIT ADDITION END created.flags_1 |= (spawner.flags_1 & ADMIN_SPAWNED_1) spawned_things += WEAKREF(created) @@ -138,6 +149,7 @@ SEND_SIGNAL(src, COMSIG_SPAWNER_SPAWNED, created) RegisterSignal(created, COMSIG_QDELETING, PROC_REF(on_deleted)) spawn_callback?.Invoke(created) + context.finalize() // VOIDCREW EDIT: npc_scaling runs after faction and callback setup. if (spawn_text) diff --git a/code/datums/mapgen/CaveGenerator.dm b/code/datums/mapgen/CaveGenerator.dm index f7d8f2d08ef..152302a3acc 100644 --- a/code/datums/mapgen/CaveGenerator.dm +++ b/code/datums/mapgen/CaveGenerator.dm @@ -382,7 +382,10 @@ weighted_megafauna_spawn_list.Remove(picked_mob) megafauna_spawn_list = expand_weights(weighted_megafauna_spawn_list) megas_allowed = megas_allowed && length(megafauna_spawn_list) - new picked_mob(target_turf) + // VOIDCREW EDIT ADDITION START: npc_scaling pins this generating site. + var/datum/npc_spawn_context/context = new(src, role = is_megafauna ? "boss" : "auto", source_turf = target_turf) + spawn_npc_in_zone(picked_mob, target_turf, context) + // VOIDCREW EDIT ADDITION END spawned_something = TRUE // VOIDCREW EDIT: worldgen_yield, not CHECK_TICK - mid-round asteroid/field // builds run this under the worldgen queue and must share its budget diff --git a/code/game/objects/effects/spawners/random/random.dm b/code/game/objects/effects/spawners/random/random.dm index 9614c4a1781..718150fcaca 100644 --- a/code/game/objects/effects/spawners/random/random.dm +++ b/code/game/objects/effects/spawners/random/random.dm @@ -114,6 +114,11 @@ * type_path_to_make - what are we spawning? **/ /obj/effect/spawner/random/proc/make_item(spawn_loc, type_path_to_make) + // VOIDCREW EDIT ADDITION START: npc_scaling also catches Initialize replacements. + if(ispath(type_path_to_make, /mob/living) || ispath(type_path_to_make, /obj/structure/spawner)) + var/datum/npc_spawn_context/context = new(src) + return spawn_npc_in_zone(type_path_to_make, spawn_loc, context) + // VOIDCREW EDIT ADDITION END return new type_path_to_make(spawn_loc) ///If the spawner has a spawn_scatter_radius set, this creates a list of nearby turfs available that are in view and have an unblocked line to them. diff --git a/tgstation.dme b/tgstation.dme index 60aaf846277..995b321a75f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7351,6 +7351,9 @@ #include "voidcrew\modules\nanites\code\programs\supression.dm" #include "voidcrew\modules\nanites\code\programs\utility.dm" #include "voidcrew\modules\nanites\code\programs\weapon.dm" +#include "voidcrew\modules\npc_scaling\damage.dm" +#include "voidcrew\modules\npc_scaling\spawn_hooks.dm" +#include "voidcrew\modules\npc_scaling\zone_profiles.dm" #include "voidcrew\modules\npc_ships\code\_defines.dm" #include "voidcrew\modules\npc_ships\code\admin_verbs.dm" #include "voidcrew\modules\npc_ships\code\boarding_pod.dm" diff --git a/voidcrew/_DEFINES/overmap_zones.dm b/voidcrew/_DEFINES/overmap_zones.dm index 5c7bd5dbd6d..ab2751eb393 100644 --- a/voidcrew/_DEFINES/overmap_zones.dm +++ b/voidcrew/_DEFINES/overmap_zones.dm @@ -110,8 +110,8 @@ * planet - roughly 60 permanent hostiles on top of the 15 SSplanet_mobs allows. */ #define ZONE_PLANET_SPAWNER_BUDGET_GREEN 3 -#define ZONE_PLANET_SPAWNER_BUDGET_YELLOW 5 -#define ZONE_PLANET_SPAWNER_BUDGET_RED 8 +#define ZONE_PLANET_SPAWNER_BUDGET_YELLOW 3 +#define ZONE_PLANET_SPAWNER_BUDGET_RED 3 /// Minimum tiles between two structure spawners on a planet. Keeps the budget spread out /// instead of letting the whole allowance land in one corner of the map. diff --git a/voidcrew/controllers/subsystem/planet_mobs.dm b/voidcrew/controllers/subsystem/planet_mobs.dm index 82decbe7e91..ba6718aa84a 100644 --- a/voidcrew/controllers/subsystem/planet_mobs.dm +++ b/voidcrew/controllers/subsystem/planet_mobs.dm @@ -25,8 +25,7 @@ SUBSYSTEM_DEF(planet_mobs) /// Max managed mobs across ALL planets var/global_mob_cap = 150 - /// Base cap on managed mobs for any one planet, before the zone-band scaling in - /// mob_cap_for_band(). Per PLANET, not per z-level: a packed level can hold several + /// Cap on managed mobs for any one planet. Per PLANET, not per z-level: a packed level can hold several /// tenants and each of them gets its own budget, exactly as it would have on a level /// of its own. var/per_planet_mob_cap = 15 @@ -136,19 +135,8 @@ SUBSYSTEM_DEF(planet_mobs) trackers_here |= tracker return tracker -/** - * A planet's share of the mob budget for its zone band. - * - * A flat cap muted the density half of danger scaling: deeper bands roll more spawns, then - * the cap threw the surplus away. Scale it modestly instead. The global cap still bounds - * the whole galaxy. - */ +/// Every band has the same fauna budget; profiles supply the zone's stat scaling. /datum/controller/subsystem/planet_mobs/proc/mob_cap_for_band(zone_band) - switch(zone_band) - if(ZONE_YELLOW) - return round(per_planet_mob_cap * 1.2) // 18 at the default 15 - if(ZONE_RED) - return round(per_planet_mob_cap * 1.5) // 22 at the default 15 return per_planet_mob_cap /** @@ -307,7 +295,7 @@ SUBSYSTEM_DEF(planet_mobs) return TRUE return FALSE -/// Spawns up to this planet's own zone-scaled cap from its candidate turfs, less `already_spawned` +/// Spawns up to this planet's own cap from its candidate turfs, less `already_spawned` /// (the planet's people, spawned first out of the same cap). Returns how many mobs it actually spawned. /datum/controller/subsystem/planet_mobs/proc/spawn_for_tracker(datum/planet_mob_tracker/tracker, already_spawned = 0) var/list/spawn_turfs = tracker.surface_spawn_turfs @@ -362,7 +350,8 @@ SUBSYSTEM_DEF(planet_mobs) if(!mob_type) continue - new mob_type(candidate) + var/datum/npc_spawn_context/context = new(tracker, tracker.zone_band, source_turf = candidate) + spawn_npc_in_zone(mob_type, candidate, context) spawned++ total_managed_mobs++ diff --git a/voidcrew/datums/mapgen/biomes/_biome.dm b/voidcrew/datums/mapgen/biomes/_biome.dm index d28fd10022a..6ef081c4196 100644 --- a/voidcrew/datums/mapgen/biomes/_biome.dm +++ b/voidcrew/datums/mapgen/biomes/_biome.dm @@ -125,7 +125,8 @@ break if(can_spawn) - new picked_mob(new_turf) + var/datum/npc_spawn_context/context = new(src, source_turf = new_turf) + spawn_npc_in_zone(picked_mob, new_turf, context) new_turf.flags_1 |= NO_LAVA_GEN diff --git a/voidcrew/modules/loot/themes/expedition.dm b/voidcrew/modules/loot/themes/expedition.dm index 2d6e8bde8bf..9bef02b93fe 100644 --- a/voidcrew/modules/loot/themes/expedition.dm +++ b/voidcrew/modules/loot/themes/expedition.dm @@ -128,9 +128,6 @@ /// tendril chest, the cache they guard is the prize. /obj/effect/zone_mobs/wildlife/boss name = "zone mob spawner (wildlife boss)" - count_green = list(1, 1) - count_yellow = list(1, 1) - count_red = list(1, 1) mobs_green = list( /mob/living/basic/mining/goliath = 1, ) diff --git a/voidcrew/modules/loot/themes/industrial.dm b/voidcrew/modules/loot/themes/industrial.dm index 09dfcb318a6..506103a787a 100644 --- a/voidcrew/modules/loot/themes/industrial.dm +++ b/voidcrew/modules/loot/themes/industrial.dm @@ -123,9 +123,6 @@ /obj/effect/zone_mobs/robot/boss name = "zone mob spawner (robot boss)" - count_green = list(1, 1) - count_yellow = list(1, 1) - count_red = list(1, 2) mobs_green = list( /mob/living/basic/hivebot/strong = 1, ) diff --git a/voidcrew/modules/loot/themes/occult.dm b/voidcrew/modules/loot/themes/occult.dm index 0188b8b4325..8dc6833fb6f 100644 --- a/voidcrew/modules/loot/themes/occult.dm +++ b/voidcrew/modules/loot/themes/occult.dm @@ -114,9 +114,6 @@ /obj/effect/zone_mobs/cult/boss name = "zone mob spawner (cult boss)" - count_green = list(1, 1) - count_yellow = list(1, 1) - count_red = list(1, 1) mobs_green = list( /mob/living/basic/construct/artificer/hostile = 1, ) @@ -147,9 +144,6 @@ /obj/effect/zone_mobs/undead/boss name = "zone mob spawner (undead boss)" - count_green = list(1, 1) - count_yellow = list(1, 1) - count_red = list(1, 1) mobs_green = list( /mob/living/basic/skeleton/templar = 1, ) diff --git a/voidcrew/modules/loot/themes/plunder.dm b/voidcrew/modules/loot/themes/plunder.dm index 7dee57694e0..a6cfe31ba06 100644 --- a/voidcrew/modules/loot/themes/plunder.dm +++ b/voidcrew/modules/loot/themes/plunder.dm @@ -121,9 +121,6 @@ /// The pirate setpiece: a captain holding the vault, a proper boss in the red. /obj/effect/zone_mobs/pirate/boss name = "zone mob spawner (pirate boss)" - count_green = list(1, 1) - count_yellow = list(1, 1) - count_red = list(1, 1) mobs_green = list( /mob/living/basic/trooper/pirate/faction/grey/captain = 1, /mob/living/basic/trooper/pirate/faction/skeleton/captain = 1, diff --git a/voidcrew/modules/loot/themes/syndicate.dm b/voidcrew/modules/loot/themes/syndicate.dm index e63595fc913..90bcbd499be 100644 --- a/voidcrew/modules/loot/themes/syndicate.dm +++ b/voidcrew/modules/loot/themes/syndicate.dm @@ -137,9 +137,6 @@ /obj/effect/zone_mobs/syndicate/boss name = "zone mob spawner (syndicate boss)" - count_green = list(1, 1) - count_yellow = list(1, 1) - count_red = list(1, 1) mobs_green = list( /mob/living/basic/trooper/syndicate/melee/sword = 1, ) diff --git a/voidcrew/modules/loot/zone_mobs.dm b/voidcrew/modules/loot/zone_mobs.dm index e73d3437723..284115aa4f7 100644 --- a/voidcrew/modules/loot/zone_mobs.dm +++ b/voidcrew/modules/loot/zone_mobs.dm @@ -20,7 +20,7 @@ * back to green (the weakest table), so a broken resolution can never flood * a ruin. * - * The /boss variants are single-slot setpiece markers: green gets the + * The /boss variants are setpiece markers: green gets the * theme's lieutenant, red gets the real monster. "Real monster" tops out at * elite-tier ("harder versions of normal mobs"). Megafauna are BANNED from * the zone system, and from ruin maps outside the purpose-built boss-arena @@ -44,22 +44,26 @@ var/list/mobs_yellow var/list/mobs_red /// Spawn count ranges per zone: list(min, max) - var/list/count_green = list(0, 1) + var/list/count_green = list(1, 2) var/list/count_yellow = list(1, 2) - var/list/count_red = list(2, 3) + var/list/count_red = list(1, 2) + /// Explicit setpiece role; shared mob types must not infer it from their name. + var/npc_role = "auto" /// How far spawns scatter from the marker var/scatter_radius = 2 /** * Runtime spawns (mission waves) can pass a count override: * new /obj/effect/zone_mobs/pirate(T, list(1, 2)) guarantees 1-2 spawns in - * green/yellow and one extra in red, regardless of the theme's defaults. + * every band, regardless of the theme's defaults. */ /obj/effect/zone_mobs/Initialize(mapload, list/count_override) + if(npc_role == "auto" && npc_zone_boss_type(type)) + npc_role = "boss" if(islist(count_override) && length(count_override) >= 2) count_green = count_override count_yellow = count_override - count_red = list(count_override[1] + 1, count_override[2] + 1) + count_red = count_override . = ..() return INITIALIZE_HINT_LATELOAD @@ -102,7 +106,8 @@ if(!mob_path) continue var/turf/spot = length(open_turfs) ? pick_n_take(open_turfs) : get_turf(src) - new mob_path(spot) + var/datum/npc_spawn_context/context = new(src, zone_type, npc_role) + spawn_npc_in_zone(mob_path, spot, context) /** * Open, unblocked turfs around the marker the pack can scatter onto. diff --git a/voidcrew/modules/npc_scaling/damage.dm b/voidcrew/modules/npc_scaling/damage.dm new file mode 100644 index 00000000000..56c4a5aa973 --- /dev/null +++ b/voidcrew/modules/npc_scaling/damage.dm @@ -0,0 +1,39 @@ +/// Capture this NUMBER on delayed effects, so creator deletion cannot change damage. +/mob/living/proc/get_npc_zone_damage_factor() + if(npc_zone_applied && is_npc_zone_exempt()) + exempt_npc_zone() + return npc_zone_damage_factor + +/// Raw ability input by default. Set already_scaled for a roll of scaled melee bounds. +/// Delayed effects pass their captured numeric factor instead of retaining a mob. +/proc/npc_zone_damage(raw_damage, source_or_factor, already_scaled = FALSE) + if(already_scaled) + return raw_damage + var/factor = 1 + if(isliving(source_or_factor)) + var/mob/living/source = source_or_factor + factor = source.get_npc_zone_damage_factor() + else if(isnum(source_or_factor)) + factor = source_or_factor + return raw_damage * factor + +/// Always pass RAW weapon force/bounds, including when re-equipping the same weapon. +/mob/living/proc/set_npc_zone_melee(raw_lower, raw_upper) + npc_zone_original_melee_lower = raw_lower + npc_zone_original_melee_upper = raw_upper + var/factor = get_npc_zone_damage_factor() + melee_damage_lower = raw_lower * factor + melee_damage_upper = raw_upper * factor + +/obj/projectile + /// A reused/reflected projectile retains its first factor, never multiplying twice. + var/npc_zone_damage_scaled = FALSE + var/npc_zone_damage_factor = 1 + +/mob/living/proc/npc_zone_projectile(datum/source, obj/projectile/projectile) + SIGNAL_HANDLER + if(projectile.npc_zone_damage_scaled) + return + projectile.npc_zone_damage_scaled = TRUE + projectile.npc_zone_damage_factor = get_npc_zone_damage_factor() + projectile.damage *= projectile.npc_zone_damage_factor diff --git a/voidcrew/modules/npc_scaling/spawn_hooks.dm b/voidcrew/modules/npc_scaling/spawn_hooks.dm new file mode 100644 index 00000000000..2b592e1a742 --- /dev/null +++ b/voidcrew/modules/npc_scaling/spawn_hooks.dm @@ -0,0 +1,83 @@ +/// Construction scope only; InitAtom does not sleep. Nested spawn calls restore it. +GLOBAL_VAR(npc_zone_construction_context) + +/** + * The single constructor for profiled producers. A context is per construction, + * including its replacement chain. Pass finalize = FALSE when the caller still + * has body/weapon/faction setup to do; call context.finalize() afterwards. + * Returns the surviving replacement when Initialize deletes the requested body. + * Non-mob outputs (nests, portals) keep the context for their later spawns. + * constructor_args, when supplied, are the Initialize arguments after location. + */ +/proc/spawn_npc_in_zone(spawn_type, atom/location, datum/npc_spawn_context/context, finalize = TRUE, list/constructor_args) + var/datum/npc_spawn_context/previous = GLOB.npc_zone_construction_context + GLOB.npc_zone_construction_context = context + var/list/spawn_args = list(location) + if(constructor_args) + spawn_args += constructor_args + var/atom/created = new spawn_type(arglist(spawn_args)) + GLOB.npc_zone_construction_context = previous + if(QDELETED(created)) + for(var/datum/weakref/body_ref as anything in context.bodies) + var/mob/living/body = body_ref.resolve() + if(!QDELETED(body)) + created = body + break + else + created.npc_spawn_context = context + if(isliving(created)) + context.bodies |= WEAKREF(created) + if(finalize) + context.finalize() + return created + +/// Pin an environmental parent's source before its first emission, not at child death. +/atom/proc/get_npc_spawn_context() + if(!npc_spawn_context) + npc_spawn_context = GLOB.npc_zone_construction_context || new /datum/npc_spawn_context(src) + return npc_spawn_context + +// The initialization-complete signal is emitted even for INITIALIZE_HINT_QDEL. +// Wrapping InitAtom keeps context active through the ENTIRE subtype Initialize, +// including replacement rolls after ..(), without modifying those mob types. +/datum/controller/subsystem/atoms/InitAtom(atom/target, from_template = FALSE, list/arguments) + if(!isliving(target) || QDELETED(target)) + return ..() + var/datum/npc_spawn_context/previous = GLOB.npc_zone_construction_context + var/datum/npc_spawn_context/context = previous + var/owns_context = FALSE + if(isliving(target)) + context ||= target.npc_spawn_context + if(!context && arguments && arguments[1]) + context = new /datum/npc_spawn_context(target) + owns_context = TRUE + if(context) + GLOB.npc_zone_construction_context = context + target.npc_spawn_context = context + context.bodies |= WEAKREF(target) + RegisterSignal(target, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE, PROC_REF(npc_zone_initialized)) + . = ..() + GLOB.npc_zone_construction_context = previous + if(owns_context || (context?.ready_to_finalize && previous != context)) + context.finalize() + +/datum/controller/subsystem/atoms/proc/npc_zone_initialized(mob/living/source) + SIGNAL_HANDLER + UnregisterSignal(source, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE) + if(QDELETED(source)) + return + source.npc_zone_initialization_complete = TRUE + // Ownership can change long after spawn. Signals are installed once per body. + RegisterSignal(source, list(COMSIG_MOB_LOGIN, COMSIG_MOB_MIND_INITIALIZED, COMSIG_MOB_MIND_TRANSFERRED_INTO), PROC_REF(npc_zone_owned)) + RegisterSignal(source, COMSIG_LIVING_BEFRIENDED, PROC_REF(npc_zone_befriended)) + if(source.npc_zone_ready) + source.finalize_npc_zone() + +/datum/controller/subsystem/atoms/proc/npc_zone_owned(mob/living/source) + SIGNAL_HANDLER + source.exempt_npc_zone() + +/datum/controller/subsystem/atoms/proc/npc_zone_befriended(mob/living/source, mob/living/friend) + SIGNAL_HANDLER + if(friend && (friend.client || friend.mind || friend.npc_zone_exempt)) + source.exempt_npc_zone() diff --git a/voidcrew/modules/npc_scaling/zone_profiles.dm b/voidcrew/modules/npc_scaling/zone_profiles.dm new file mode 100644 index 00000000000..45d1c73a443 --- /dev/null +++ b/voidcrew/modules/npc_scaling/zone_profiles.dm @@ -0,0 +1,193 @@ +/** + * Spawn contract: create a context BEFORE construction, use spawn_npc_in_zone(), + * finish source-specific body/weapon/faction setup, then context.finalize(). + * Roles are "auto" (hostile gate + named boss types), "ordinary", "boss", or + * "exempt". Explicit combat roles also cover setpieces with otherwise passive AI. + * Never edit a context's source, zone or role after construction. Unresolved zones + * resolve once against source_turf, never against a moving mob's current location. + */ +/datum/npc_spawn_context + var/source_id + var/source_type + var/turf/source_turf + var/zone_type + var/role + var/exempt = FALSE + /// Carries a caller's finalization request across deferred map initialization. + var/ready_to_finalize = FALSE + /// Weak references include replacements; discarded precursors are skipped. + var/list/bodies = list() + var/datum/zone_resolver/resolver + +/datum/npc_spawn_context/New(datum/source, zone_type, role = "auto", exempt = FALSE, turf/source_turf) + var/atom/source_atom = isatom(source) ? source : null + var/datum/npc_spawn_context/inherited = source_atom?.npc_spawn_context + src.source_id = inherited ? inherited.source_id : REF(source) + src.source_type = inherited ? inherited.source_type : source?.type + src.source_turf = inherited ? inherited.source_turf : (source_turf || get_turf(source_atom)) + src.zone_type = isnull(zone_type) ? inherited?.zone_type : zone_type + src.role = role + src.exempt = exempt || role == "exempt" || source_atom?.npc_zone_exempt || inherited?.exempt + if(isliving(source)) + var/mob/living/owner = source + src.exempt ||= owner.is_npc_zone_exempt() + if(isnull(src.zone_type)) + // Start after New returns: zone_resolver may invoke its callback synchronously. + addtimer(CALLBACK(src, PROC_REF(resolve_zone)), 0) + +/datum/npc_spawn_context/Destroy() + QDEL_NULL(resolver) + bodies = null + source_turf = null + return ..() + +/datum/npc_spawn_context/proc/resolve_zone() + if(!isnull(zone_type)) + return + resolver = new /datum/zone_resolver(source_turf, CALLBACK(src, PROC_REF(on_zone_resolved))) + +/datum/npc_spawn_context/proc/on_zone_resolved(resolved_zone) + if(!isnull(zone_type)) + return + zone_type = isnull(resolved_zone) ? ZONE_GREEN : resolved_zone + for(var/datum/weakref/body_ref as anything in bodies) + var/mob/living/body = body_ref.resolve() + if(body?.npc_zone_ready) + body.finalize_npc_zone() + +/// Call after ALL source-specific setup, including on replacement bodies. +/datum/npc_spawn_context/proc/finalize() + ready_to_finalize = TRUE + for(var/datum/weakref/body_ref as anything in bodies) + var/mob/living/body = body_ref.resolve() + if(!QDELETED(body)) + body.finalize_npc_zone(src) + +/atom + /// Also carried by environmental parents so later children use the pinned source. + var/datum/npc_spawn_context/npc_spawn_context + /// Permanent ownership opt-out. Child contexts copy it even after a profile is removed. + var/npc_zone_exempt = FALSE + +/mob/living + var/npc_zone_initialization_complete = FALSE + var/npc_zone_ready = FALSE + var/npc_zone_applied = FALSE + var/npc_zone_role + var/npc_zone_health_factor = 1 + var/npc_zone_damage_factor = 1 + var/npc_zone_original_max_health + var/npc_zone_original_melee_lower + var/npc_zone_original_melee_upper + +/// Approved boss classification, including marker types that grant a boss role +/// to otherwise ordinary bodies. Other setpiece producers pass "boss" explicitly. +/proc/npc_zone_boss_type(candidate_type) + var/static/list/boss_types = list( + /mob/living/simple_animal/hostile/megafauna, + /mob/living/simple_animal/hostile/asteroid/elite, + /mob/living/basic/boss, + /mob/living/basic/trooper/pirate/faction/boss, + /mob/living/basic/bounty_criminal/boss, + /mob/living/basic/bounty_criminal/kingpin, + /mob/living/basic/bounty_lair_boss, + /mob/living/basic/lich, + /mob/living/basic/trooper/pirate/faction/silverscale/captain, + /mob/living/basic/trooper/pirate/faction/skeleton/captain, + /mob/living/basic/trooper/pirate/faction/grey/captain, + /mob/living/basic/trooper/pirate/faction/lustrous/captain, + /mob/living/basic/trooper/pirate/faction/interdyne/captain, + /mob/living/basic/trooper/pirate/faction/irs/captain, + /mob/living/basic/trooper/pirate/faction/medieval/captain, + /mob/living/simple_animal/hostile/asteroid/old_demon, + /mob/living/basic/mining/wolf/alpha, + /mob/living/simple_animal/hostile/asteroid/polarbear/warrior, + /obj/effect/zone_mobs/bug/boss, + /obj/effect/zone_mobs/cult/boss, + /obj/effect/zone_mobs/pirate/boss, + /obj/effect/zone_mobs/robot/boss, + /obj/effect/zone_mobs/syndicate/boss, + /obj/effect/zone_mobs/undead/boss, + /obj/effect/zone_mobs/wildlife/boss, + ) + for(var/boss_type in boss_types) + if(ispath(candidate_type, boss_type)) + return TRUE + return FALSE + +/// Environmental auto gate: passive fauna and mobs without autonomous AI stay baseline. +/mob/living/proc/is_npc_zone_hostile() + return ishostile(src) || (isbasicmob(src) && ai_controller && combat_mode) + +/mob/living/proc/is_npc_zone_exempt() + return npc_zone_exempt || npc_spawn_context?.exempt || client || mind || (FACTION_NEUTRAL in faction) + +/mob/living/proc/finalize_npc_zone(datum/npc_spawn_context/context) + if(QDELETED(src)) + return + if(!npc_spawn_context) + npc_spawn_context = context + context = npc_spawn_context + if(!context) + return + context.bodies |= WEAKREF(src) + npc_zone_ready = TRUE + if(!npc_zone_initialization_complete) + return + if(is_npc_zone_exempt()) + exempt_npc_zone() + return + if(npc_zone_applied || isnull(context.zone_type)) + return + if(!isbasicmob(src) && !isanimal(src)) + return + if(context.role == "auto" && !is_npc_zone_hostile()) + return + npc_zone_role = (context.role == "boss" || npc_zone_boss_type(type)) ? "boss" : "ordinary" + npc_zone_original_max_health = maxHealth + npc_zone_original_melee_lower = melee_damage_lower + npc_zone_original_melee_upper = melee_damage_upper + switch(context.zone_type) + if(ZONE_YELLOW) + npc_zone_health_factor = npc_zone_role == "boss" ? 1.15 : 1.35 + npc_zone_damage_factor = npc_zone_role == "boss" ? 1.1 : 1.15 + if(ZONE_RED) + npc_zone_health_factor = npc_zone_role == "boss" ? 1.3 : 1.8 + npc_zone_damage_factor = npc_zone_role == "boss" ? 1.2 : 1.35 + npc_zone_applied = TRUE + set_npc_zone_health(npc_zone_original_max_health) + set_npc_zone_melee(npc_zone_original_melee_lower, npc_zone_original_melee_upper) + RegisterSignal(src, COMSIG_PROJECTILE_FIRER_BEFORE_FIRE, PROC_REF(npc_zone_projectile)) + +/// Use for raw max-health changes (posse size, phases). Retains the selected factor. +/mob/living/proc/set_npc_zone_health(raw_max_health) + npc_zone_original_max_health = raw_max_health + resize_npc_zone_health(raw_max_health * npc_zone_health_factor) + +/// Basic and legacy simple animals both store ALL physical damage in bruteloss. +/// Scale the damage store too, so updatehealth/healing/revival cannot undo the resize. +/mob/living/proc/resize_npc_zone_health(new_max_health) + if(maxHealth <= 0 || new_max_health <= 0) + return + var/ratio = new_max_health / maxHealth + bruteloss *= ratio + // Preserve any nonstandard extra loss stores too; do not change stamina. + oxyloss *= ratio + toxloss *= ratio + fireloss *= ratio + setMaxHealth(new_max_health) + updatehealth() + +/// Source producers call this for recruits, guards, pets, arena mobs and summons. +/// Removal is permanent and preserves health fraction, including on wounded bodies. +/mob/living/proc/exempt_npc_zone() + npc_zone_exempt = TRUE + if(!npc_zone_applied) + return + UnregisterSignal(src, COMSIG_PROJECTILE_FIRER_BEFORE_FIRE) + npc_zone_applied = FALSE + npc_zone_health_factor = 1 + npc_zone_damage_factor = 1 + resize_npc_zone_health(npc_zone_original_max_health) + melee_damage_lower = npc_zone_original_melee_lower + melee_damage_upper = npc_zone_original_melee_upper diff --git a/voidcrew/modules/unit_tests/_unit_tests.dm b/voidcrew/modules/unit_tests/_unit_tests.dm index 6ce95631a4a..25503881a42 100644 --- a/voidcrew/modules/unit_tests/_unit_tests.dm +++ b/voidcrew/modules/unit_tests/_unit_tests.dm @@ -104,6 +104,7 @@ #include "voidcrew_nanite_research.dm" #include "voidcrew_npc_boarding_docking.dm" #include "voidcrew_npc_disarm.dm" +#include "voidcrew_npc_zone_profiles.dm" #include "voidcrew_outpost_admin.dm" #include "voidcrew_outpost_admin_bays.dm" #include "voidcrew_outpost_admin_checkpoints.dm" diff --git a/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm new file mode 100644 index 00000000000..49214d61cfd --- /dev/null +++ b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm @@ -0,0 +1,367 @@ +// Voidcrew defines are included after the test harness: zones below are 1/2/3. +/mob/living/basic/npc_zone_test + health = 100 + maxHealth = 100 + melee_damage_lower = 10 + melee_damage_upper = 20 + combat_mode = TRUE + faction = list(FACTION_HOSTILE) + ai_controller = /datum/ai_controller/basic_controller/simple/simple_hostile + unsuitable_atmos_damage = 0 + unsuitable_cold_damage = 0 + unsuitable_heat_damage = 0 + +/mob/living/simple_animal/hostile/npc_zone_test + health = 100 + maxHealth = 100 + melee_damage_lower = 10 + melee_damage_upper = 20 + unsuitable_atmos_damage = 0 + unsuitable_cold_damage = 0 + unsuitable_heat_damage = 0 + +/// Deterministic equivalent of the wolf/ice-demon Initialize replacement rolls. +/mob/living/basic/npc_zone_test/replacement/Initialize(mapload) + . = ..() + new /mob/living/basic/npc_zone_test(loc) + return INITIALIZE_HINT_QDEL + +/obj/effect/spawner/random/npc_zone_test + loot = list() + +/obj/effect/spawner/random/npc_zone_test/Initialize(mapload) + . = ..() + return INITIALIZE_HINT_NORMAL + +/datum/unit_test/voidcrew_npc_zone_profiles/Run() + var/turf/location = run_loc_floor_bottom_left + var/list/health_factors = list(list(1, 1.35, 1.8), list(1, 1.15, 1.3)) + var/list/damage_factors = list(list(1, 1.15, 1.35), list(1, 1.1, 1.2)) + for(var/mob_type in list(/mob/living/basic/npc_zone_test, /mob/living/simple_animal/hostile/npc_zone_test)) + for(var/role_index in 1 to 2) + for(var/zone in 1 to 3) + var/role = role_index == 1 ? "ordinary" : "boss" + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, zone, role) + var/mob/living/body = spawn_npc_in_zone(mob_type, location, context, FALSE) + body.setBruteLoss(40) + context.finalize() + var/health_factor = health_factors[role_index][zone] + var/damage_factor = damage_factors[role_index][zone] + TEST_ASSERT(abs(body.maxHealth - 100 * health_factor) < 0.001, "[mob_type]/[role]/[zone]: wrong max health") + TEST_ASSERT(abs(body.health / body.maxHealth - 0.6) < 0.001, "Finalization healed a wounded [mob_type]") + body.updatehealth() + TEST_ASSERT(abs(body.health / body.maxHealth - 0.6) < 0.001, "updatehealth lost scaled damage") + TEST_ASSERT(abs(body.melee_damage_upper - 20 * damage_factor) < 0.001, "Wrong melee factor") + context.finalize() + body.forceMove(run_loc_floor_top_right) + body.finalize_npc_zone(allocate(/datum/npc_spawn_context, src, 1, "boss")) + TEST_ASSERT_EQUAL(body.npc_spawn_context, context, "Movement/repeated calls replaced the pinned context") + TEST_ASSERT(abs(body.maxHealth - 100 * health_factor) < 0.001, "Repeated finalization stacked health") + body.fully_heal() + TEST_ASSERT_EQUAL(body.health, body.maxHealth, "Healing lost the scaled maximum") + body.death() + body.revive(ADMIN_HEAL_ALL) + TEST_ASSERT(abs(body.maxHealth - 100 * health_factor) < 0.001, "Revival selected a different maximum") + body.setBruteLoss(body.maxHealth * 0.4) + body.set_npc_zone_melee(30, 40) + body.set_npc_zone_melee(30, 40) + TEST_ASSERT(abs(body.melee_damage_upper - 40 * damage_factor) < 0.001, "Replacing a weapon stacked its raw force") + body.set_npc_zone_health(200) + TEST_ASSERT(abs(body.maxHealth - 200 * health_factor) < 0.001, "Raw posse/phase health lost its factor") + TEST_ASSERT(abs(body.health / body.maxHealth - 0.6) < 0.001, "Raw health change healed the body") + body.exempt_npc_zone() + TEST_ASSERT_EQUAL(body.maxHealth, 200, "Exemption did not restore the current raw max health") + TEST_ASSERT(abs(body.health / body.maxHealth - 0.6) < 0.001, "Exemption changed health fraction") + TEST_ASSERT_EQUAL(body.melee_damage_upper, 40, "Exemption did not restore raw weapon force") + context.finalize() + TEST_ASSERT(!body.npc_zone_applied, "Exemption was reversed by repeated finalization") + qdel(body) + +/datum/unit_test/voidcrew_npc_zone_damage/Run() + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, 3) + var/mob/living/body = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, run_loc_floor_bottom_left, context) + var/obj/projectile/bullet/projectile = allocate(/obj/projectile/bullet) + var/raw_damage = projectile.damage + SEND_SIGNAL(body, COMSIG_PROJECTILE_FIRER_BEFORE_FIRE, projectile) + SEND_SIGNAL(body, COMSIG_PROJECTILE_FIRER_BEFORE_FIRE, projectile) + TEST_ASSERT(abs(projectile.damage - raw_damage * 1.35) < 0.001, "A reused projectile multiplied damage twice") + TEST_ASSERT_EQUAL(npc_zone_damage(10, body), 13.5, "Raw scripted ability did not scale") + TEST_ASSERT_EQUAL(npc_zone_damage(13.5, body, TRUE), 13.5, "Already-scaled melee input scaled twice") + var/delayed_factor = body.get_npc_zone_damage_factor() + qdel(body) + TEST_ASSERT_EQUAL(npc_zone_damage(10, delayed_factor), 13.5, "Delayed damage lost its numeric factor after creator deletion") + +/datum/unit_test/voidcrew_npc_zone_exemptions/Run() + var/turf/location = run_loc_floor_bottom_left + // Producers for pets, recruits, guards, arenas and summons share this opt-out. + for(var/child_role in list("ordinary", "boss")) + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, 3, "exempt") + var/mob/living/body = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, location, context) + TEST_ASSERT(!body.npc_zone_applied, "Explicit source exemption failed") + var/datum/npc_spawn_context/child_context = allocate(/datum/npc_spawn_context, body, 3, child_role) + var/mob/living/child = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, location, child_context) + TEST_ASSERT(!child.npc_zone_applied, "An exempt descendant lost exemption to its [child_role] role") + qdel(body) + qdel(child) + var/datum/npc_spawn_context/passive_context = allocate(/datum/npc_spawn_context, src, 3) + var/mob/living/basic/passive = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, location, passive_context, FALSE) + passive.combat_mode = FALSE + passive_context.finalize() + TEST_ASSERT(!passive.npc_zone_applied, "Passive ambient fauna received a hostile profile") + qdel(passive) + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, 3) + var/mob/living/body = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, location, context) + body.setBruteLoss(90) + var/mob/living/basic/friend = allocate(/mob/living/basic/npc_zone_test, location) + friend.exempt_npc_zone() + body.befriend(friend) + TEST_ASSERT(!body.npc_zone_applied && body.npc_zone_exempt, "Player-owned taming did not remove the profile") + TEST_ASSERT(abs(body.health / body.maxHealth - 0.5) < 0.001, "Taming healed the body") + qdel(body) + for(var/ownership_signal in list(COMSIG_MOB_LOGIN, COMSIG_MOB_MIND_TRANSFERRED_INTO)) + context = allocate(/datum/npc_spawn_context, src, 3) + body = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, location, context) + SEND_SIGNAL(body, ownership_signal) + TEST_ASSERT(!body.npc_zone_applied && body.npc_zone_exempt, "Ownership signal left a profile active") + qdel(body) + context = allocate(/datum/npc_spawn_context, src, 3) + body = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, location, context) + body.mind_initialize() + TEST_ASSERT(!body.npc_zone_applied && body.npc_zone_exempt, "Mind initialization left a profile active") + qdel(body) + +/datum/unit_test/voidcrew_npc_zone_bosses/Run() + for(var/boss_type in list( + /mob/living/simple_animal/hostile/megafauna, + /mob/living/simple_animal/hostile/asteroid/elite, + /mob/living/basic/boss, + /mob/living/basic/trooper/pirate/faction/boss, + /mob/living/basic/bounty_criminal/boss, + /mob/living/basic/bounty_criminal/kingpin, + /mob/living/basic/bounty_lair_boss, + /mob/living/basic/lich, + /mob/living/basic/trooper/pirate/faction/silverscale/captain, + /mob/living/basic/trooper/pirate/faction/skeleton/captain, + /mob/living/basic/trooper/pirate/faction/grey/captain, + /mob/living/basic/trooper/pirate/faction/lustrous/captain, + /mob/living/basic/trooper/pirate/faction/interdyne/captain, + /mob/living/basic/trooper/pirate/faction/irs/captain, + /mob/living/basic/trooper/pirate/faction/medieval/captain, + /mob/living/simple_animal/hostile/asteroid/old_demon, + /mob/living/basic/mining/wolf/alpha, + /mob/living/simple_animal/hostile/asteroid/polarbear/warrior, + )) + TEST_ASSERT(npc_zone_boss_type(boss_type), "Approved boss type missing: [boss_type]") + TEST_ASSERT(!npc_zone_boss_type(/mob/living/basic/npc_zone_test), "An ordinary mob was classified as a boss") + // Research's count overrides belong to W1, but its setpiece role is core policy. + var/obj/effect/zone_mobs/bug/boss/research_marker = allocate(/obj/effect/zone_mobs/bug/boss) + TEST_ASSERT_EQUAL(research_marker.npc_role, "boss", "Research marker did not select the explicit boss role") + qdel(research_marker) + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, 3) + var/mob/living/body = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, run_loc_floor_bottom_left, context, FALSE) + body.name = "Captain Boss Kingpin" + body.setMaxHealth(10000) + body.setBruteLoss(0) + context.finalize() + TEST_ASSERT_EQUAL(body.npc_zone_role, "ordinary", "Name/health inferred boss status") + qdel(body) + +/datum/unit_test/voidcrew_npc_zone_replacements/Run() + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, 2) + var/mob/living/body = spawn_npc_in_zone(/mob/living/basic/npc_zone_test/replacement, run_loc_floor_bottom_left, context, FALSE) + TEST_ASSERT(istype(body, /mob/living/basic/npc_zone_test) && !QDELETED(body), "Constructor failed to return the surviving replacement") + TEST_ASSERT(!body.npc_zone_applied, "Replacement finalized before caller setup") + body.setMaxHealth(200) + body.setBruteLoss(50) + context.finalize() + TEST_ASSERT_EQUAL(body.maxHealth, 270, "Replacement lost context or caller health setup") + TEST_ASSERT(abs(body.health / body.maxHealth - 0.75) < 0.001, "Replacement finalization lost existing damage") + TEST_ASSERT_EQUAL(body.npc_spawn_context.source_id, context.source_id, "Replacement lost source identity") + qdel(body) + // A caller may spawn while map initialization is deferred. Its finalization + // request must reach a replacement that did not exist when finalize() ran. + context = allocate(/datum/npc_spawn_context, src, 3) + var/old_state = SSatoms.initialized + SSatoms.initialized = INITIALIZATION_INSSATOMS + var/mob/living/pending = spawn_npc_in_zone(/mob/living/basic/npc_zone_test/replacement, run_loc_floor_bottom_left, context) + SSatoms.initialized = old_state + TEST_ASSERT(!pending.npc_zone_applied, "Deferred body finalized before Initialize") + SSatoms.InitAtom(pending, FALSE, list(TRUE)) + body = locate(/mob/living/basic/npc_zone_test) in run_loc_floor_bottom_left + TEST_ASSERT_NOTNULL(body, "Deferred constructor lost its replacement") + if(body) + TEST_ASSERT_EQUAL(body.maxHealth, 180, "Deferred replacement lost the earlier finalization request") + qdel(body) + +/datum/unit_test/voidcrew_npc_zone_routes/Run() + var/turf/location = run_loc_floor_bottom_left + // Random spawners use the same replacement-aware constructor. + var/obj/effect/spawner/random/npc_zone_test/random_spawner = allocate(/obj/effect/spawner/random/npc_zone_test, location) + random_spawner.npc_spawn_context = allocate(/datum/npc_spawn_context, src, 3) + var/mob/living/body = random_spawner.make_item(location, /mob/living/basic/npc_zone_test/replacement) + TEST_ASSERT_EQUAL(body.maxHealth, 180, "Random spawner replacement escaped the profile") + qdel(body) + // Biome and cave generation resolve their generating turf, never a z-only band. + var/area/site_area = get_area(location) + var/old_flags = site_area.area_flags + site_area.area_flags |= MOB_SPAWN_ALLOWED + var/datum/biome/biome = allocate(/datum/biome) + biome.mob_spawn_list = list(/mob/living/basic/npc_zone_test = 1) + biome.mob_spawn_chance = 100 + biome.generate_features(location) + body = locate(/mob/living/basic/npc_zone_test) in location + TEST_ASSERT_NOTNULL(body?.npc_spawn_context, "Biome route omitted spawn context") + if(body) + TEST_ASSERT_EQUAL(body.npc_spawn_context.source_turf, location, "Biome pinned the wrong site") + body.npc_spawn_context.on_zone_resolved(2) + TEST_ASSERT_EQUAL(body.maxHealth, 135, "Biome route did not finalize after resolution") + qdel(body) + var/datum/map_generator/cave_generator/cave = allocate(/datum/map_generator/cave_generator) + cave.possible_biomes = null + cave.open_turf_types = list(location.type) + cave.mob_spawn_list = list(/mob/living/basic/npc_zone_test) + cave.mob_spawn_chance = 100 + cave.populate_terrain(list(location), site_area) + body = locate(/mob/living/basic/npc_zone_test) in location + TEST_ASSERT_NOTNULL(body?.npc_spawn_context, "Cave/asteroid route omitted spawn context") + if(body) + body.npc_spawn_context.on_zone_resolved(3) + TEST_ASSERT_EQUAL(body.maxHealth, 180, "Cave route did not finalize") + qdel(body) + site_area.area_flags = old_flags + // All owned marker themes use 1-2, and explicit setpiece roles survive shared types. + for(var/marker_type in list(/obj/effect/zone_mobs/wildlife, /obj/effect/zone_mobs/asteroid, /obj/effect/zone_mobs/wildlife/boss, /obj/effect/zone_mobs/robot/boss, /obj/effect/zone_mobs/cult/boss, /obj/effect/zone_mobs/undead/boss, /obj/effect/zone_mobs/pirate/boss, /obj/effect/zone_mobs/syndicate/boss)) + var/obj/effect/zone_mobs/marker = allocate(marker_type) + if(npc_zone_boss_type(marker_type)) + TEST_ASSERT_EQUAL(marker.npc_role, "boss", "[marker_type] did not select the boss role") + for(var/list/counts in list(marker.count_green, marker.count_yellow, marker.count_red)) + TEST_ASSERT_EQUAL(counts[1], 1, "[marker_type] minimum count differs") + TEST_ASSERT_EQUAL(counts[2], 2, "[marker_type] maximum count differs") + qdel(marker) + // Initialize in nullspace so the resolver cannot race this explicit do_spawn(). + var/obj/effect/zone_mobs/marker = allocate(/obj/effect/zone_mobs, null, list(1, 2)) + marker.forceMove(location) + marker.mobs_red = list(/mob/living/basic/npc_zone_test = 1) + marker.npc_role = "boss" + marker.do_spawn(3) + var/count = 0 + for(var/mob/living/basic/npc_zone_test/guard in range(3, location)) + count++ + TEST_ASSERT_EQUAL(guard.npc_zone_role, "boss", "Marker setpiece role was lost") + TEST_ASSERT_EQUAL(guard.maxHealth, 130, "Marker output used the ordinary factor") + qdel(guard) + TEST_ASSERT(count >= 1 && count <= 2, "Marker count escaped the 1-2 budget") + qdel(marker) + for(var/band in 1 to 3) + TEST_ASSERT_EQUAL(SSplanet_mobs.mob_cap_for_band(band), 15, "Band [band] does not have the flat fauna cap") + +/datum/unit_test/voidcrew_npc_zone_deferred/Run() + var/turf/location = run_loc_floor_bottom_left + var/datum/planet_mob_tracker/tracker = allocate(/datum/planet_mob_tracker) + tracker.surface_z = location.z + tracker.zone_band = 2 + tracker.mob_cap = 1 + tracker.surface_spawn_turfs[location] = /mob/living/basic/npc_zone_test/replacement + var/old_total = SSplanet_mobs.total_managed_mobs + SSplanet_mobs.total_managed_mobs = 0 + var/spawned = SSplanet_mobs.spawn_for_tracker(tracker) + SSplanet_mobs.total_managed_mobs = old_total + TEST_ASSERT_EQUAL(spawned, 1, "Deferred fauna fixture failed to emit a mob") + var/mob/living/basic/npc_zone_test/body = locate() in location + TEST_ASSERT_NOTNULL(body, "Deferred fauna lost the replacement") + if(body) + TEST_ASSERT_EQUAL(body.maxHealth, 135, "Deferred fauna ignored the tracker band") + TEST_ASSERT_EQUAL(body.npc_spawn_context.source_id, REF(tracker), "Deferred fauna lost tracker identity") + qdel(body) + +/datum/unit_test/voidcrew_npc_zone_spawner + var/mob/living/watcher + var/watched_z + +/datum/unit_test/voidcrew_npc_zone_spawner/Destroy() + if(watched_z) + SSmobs.clients_by_zlevel[watched_z] -= watcher + return ..() + +/datum/unit_test/voidcrew_npc_zone_spawner/proc/setup_body(mob/living/body) + TEST_ASSERT(FACTION_HOSTILE in body.faction, "Spawner callback ran before faction assignment") + TEST_ASSERT(!body.npc_zone_applied, "Spawner finalized before its setup callback") + body.setMaxHealth(200) + body.setBruteLoss(50) + +/datum/unit_test/voidcrew_npc_zone_spawner/Run() + var/turf/location = run_loc_floor_bottom_left + watcher = allocate(/mob/living/basic, location) + watched_z = location.z + SSmobs.clients_by_zlevel[watched_z] |= watcher + for(var/list/distances in list(list(1, 0), list(2, 1), list(2, 0))) + var/obj/structure/parent = allocate(/obj/structure, location) + parent.npc_spawn_context = allocate(/datum/npc_spawn_context, src, 3, "auto", FALSE, location) + var/datum/component/spawner/spawner = parent.AddComponent(/datum/component/spawner, \ + spawn_types = list(/mob/living/basic/npc_zone_test/replacement), \ + faction = list(FACTION_HOSTILE), spawn_callback = CALLBACK(src, PROC_REF(setup_body)), \ + spawn_distance = distances[1], spawn_distance_exclude = distances[2]) + spawner.try_spawn_mob() + TEST_ASSERT_EQUAL(length(spawner.spawned_things), 1, "Component branch [distances[1]]/[distances[2]] lost its output") + for(var/datum/weakref/body_ref as anything in spawner.spawned_things) + var/mob/living/body = body_ref.resolve() + TEST_ASSERT_EQUAL(body.maxHealth, 360, "Component finalized before callback health setup") + TEST_ASSERT(abs(body.health / body.maxHealth - 0.75) < 0.001, "Component scaling healed the output") + qdel(body) + qdel(parent) + +/// The map parser constructs atoms before SSatoms initializes them. Exercise that +/// delayed path with a replacement, plus two adjacent site footprints on one z. +/datum/unit_test/voidcrew_npc_zone_packed + var/list/sites = list() + var/list/overmap_turfs = list() + var/zones_were_active + +/datum/unit_test/voidcrew_npc_zone_packed/Destroy() + SSovermap_zones.zones_active = zones_were_active + for(var/obj/structure/overmap/planet/site as anything in sites) + site.mapzone = null + site.footprint = null + for(var/turf/open/overmap/tile as anything in overmap_turfs) + tile.current_zone = null + tile.ChangeTurf(overmap_turfs[tile]) + return ..() + +/datum/unit_test/voidcrew_npc_zone_packed/Run() + zones_were_active = SSovermap_zones.zones_active + SSovermap_zones.zones_active = TRUE + var/turf/base = run_loc_floor_bottom_left + var/list/locations = list(get_step(base, NORTH), get_step(get_step(base, NORTH), EAST)) + for(var/band in list(1, 3)) + var/turf/token = band == 1 ? base : get_step(base, EAST) + var/old_type = token.type + var/turf/open/overmap/overmap_tile = token.ChangeTurf(/turf/open/overmap) + overmap_turfs[overmap_tile] = old_type + overmap_tile.current_zone = allocate(/datum/overmap_zone, band) + var/turf/inside = locations[band == 1 ? 1 : 2] + var/datum/map_zone/zone = allocate(/datum/map_zone) + zone.z_levels = list(reservation) + var/datum/map_footprint/footprint = allocate(/datum/map_footprint) + footprint.z_value = inside.z + footprint.set_rect(inside.x, inside.y, 1, 1) + var/obj/structure/overmap/planet/site = allocate(/obj/structure/overmap/planet, overmap_tile) + sites += site + site.mapzone = zone + site.footprint = footprint + TEST_ASSERT_EQUAL(SSovermap_zones.get_zone_type_anywhere(inside), band, "Packed fixture resolved its neighbour's band") + var/old_state = SSatoms.initialized + SSatoms.initialized = INITIALIZATION_INSSATOMS + var/mob/living/basic/npc_zone_test/mapped = new /mob/living/basic/npc_zone_test/replacement(inside) + SSatoms.initialized = old_state + SSatoms.InitAtom(mapped, FALSE, list(TRUE)) + var/mob/living/basic/npc_zone_test/body = locate() in inside + TEST_ASSERT_NOTNULL(body, "Mapped Initialize replacement vanished") + if(!body) + continue + body.npc_spawn_context.resolve_zone() + TEST_ASSERT_EQUAL(body.npc_spawn_context.zone_type, band, "Mapped replacement resolved a different site") + TEST_ASSERT_EQUAL(body.maxHealth, band == 1 ? 100 : 180, "Mapped replacement used its neighbour's factor") + body.forceMove(locations[band == 1 ? 2 : 1]) + body.finalize_npc_zone() + TEST_ASSERT_EQUAL(body.npc_spawn_context.zone_type, band, "Moving a mapped hostile retiered it") + qdel(body) From ac948083a1323670fadbe519789435a4a2333cb9 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:47:38 -0700 Subject: [PATCH 033/105] NPC zone profile: NPC ships, boarding and bounties --- voidcrew/modules/bounties/bounty_admin.dm | 3 +- voidcrew/modules/bounties/bounty_boss.dm | 27 ++- voidcrew/modules/bounties/bounty_boss_kits.dm | 22 ++- voidcrew/modules/bounties/bounty_criminal.dm | 29 +++- voidcrew/modules/bounties/bounty_kingpin.dm | 13 +- voidcrew/modules/bounties/bounty_lair.dm | 10 +- .../modules/bounties/bounty_lair_mafia.dm | 28 ++-- voidcrew/modules/bounties/bounty_outpost.dm | 3 +- voidcrew/modules/bounties/bounty_weapons.dm | 3 +- .../derelict_outposts/derelict_themes.dm | 20 +-- voidcrew/modules/npc_ships/code/_defines.dm | 15 +- .../modules/npc_ships/code/admin_verbs.dm | 4 +- .../code/behaviors/ship_combat_behaviors.dm | 17 +- .../modules/npc_ships/code/boarding_pod.dm | 33 ++-- .../npc_ships/code/npc_combat_interface.dm | 12 +- voidcrew/modules/npc_ships/code/npc_ship.dm | 26 +-- .../npc_ships/code/npc_ship_controller.dm | 155 ++++++++--------- .../unit_tests/voidcrew_bounty_lair_mafia.dm | 41 +++-- .../unit_tests/voidcrew_derelict_themes.dm | 7 +- .../voidcrew_npc_boarding_docking.dm | 123 ++++++++++++++ .../unit_tests/voidcrew_npc_zone_profiles.dm | 156 ++++++++++++++++++ 21 files changed, 538 insertions(+), 209 deletions(-) diff --git a/voidcrew/modules/bounties/bounty_admin.dm b/voidcrew/modules/bounties/bounty_admin.dm index b8bb991cd77..721a17dfc7e 100644 --- a/voidcrew/modules/bounties/bounty_admin.dm +++ b/voidcrew/modules/bounties/bounty_admin.dm @@ -868,7 +868,8 @@ ADMIN_VERB(bounty_panel, R_ADMIN, "Bounty Panel", "Spawn, post, give out, list a var/datum/criminal_bounty/posting = wanted.posting() if(posting && (posting.placement_kind != BOUNTY_PLACEMENT_TRADER_OUTPOST || posting.outpost_site?.resolve() != outpost)) posting = null - var/mob/living/basic/bounty_criminal/decoy/decoy = new(decoy_spot(center)) + var/datum/npc_spawn_context/context = wanted.bounty_profile_context() + var/mob/living/basic/bounty_criminal/decoy/decoy = spawn_npc_in_zone(/mob/living/basic/bounty_criminal/decoy, decoy_spot(center), context, FALSE) decoy.outpost_become(wanted, decoy_record, posting, outpost, bounty_outpost_display_name(outpost), bounty_outpost_display_desc(outpost), bounty_outpost_outfit(outpost)) if(posting) posting.decoys += WEAKREF(decoy) diff --git a/voidcrew/modules/bounties/bounty_boss.dm b/voidcrew/modules/bounties/bounty_boss.dm index 2d66ba67a9a..94d389fabdf 100644 --- a/voidcrew/modules/bounties/bounty_boss.dm +++ b/voidcrew/modules/bounties/bounty_boss.dm @@ -191,7 +191,7 @@ GLOBAL_LIST_EMPTY(bounty_boss_barricades) if(attack_sound) playsound(target, attack_sound, 50, TRUE) target.visible_message(span_danger("[src] [attack_verb_continuous] [target]!")) - boss_hit(target, rand(melee_damage_lower, melee_damage_upper), melee_damage_type, MELEE, 0, armour_penetration) + boss_hit(target, rand(melee_damage_lower, melee_damage_upper), melee_damage_type, MELEE, 0, armour_penetration, TRUE) SEND_SIGNAL(src, COMSIG_HOSTILE_POST_ATTACKINGTARGET, target, TRUE) if(!ignore_cooldown) changeNext_move(melee_attack_cooldown) @@ -473,8 +473,11 @@ GLOBAL_LIST_EMPTY(bounty_boss_barricades) if(!length(table) || !count) return FALSE var/wanted = table[clamp(count, 1, length(table))] + var/raw_health = wanted + wanted *= npc_zone_health_factor if(wanted <= maxHealth) return FALSE + npc_zone_original_max_health = raw_health var/share = maxHealth > 0 ? health / maxHealth : 1 setMaxHealth(wanted) if(boss_tired) @@ -553,7 +556,8 @@ GLOBAL_LIST_EMPTY(bounty_boss_barricades) * One hit from an ability on `victim`: `damage` of `damage_type` against `armour_flag` armour, and * a knockdown. A mech takes it on its hull (H2). */ -/mob/living/basic/bounty_criminal/boss/proc/boss_hit(atom/victim, damage, damage_type = BRUTE, armour_flag = MELEE, knockdown = 0, armour_penetration = 0) +/mob/living/basic/bounty_criminal/boss/proc/boss_hit(atom/victim, damage, damage_type = BRUTE, armour_flag = MELEE, knockdown = 0, armour_penetration = 0, already_scaled = FALSE) + damage = npc_zone_damage(damage, src, already_scaled) if(ismecha(victim)) var/obj/vehicle/sealed/mecha/mech = victim mech.take_damage(damage, damage_type, armour_flag, TRUE, get_dir(mech, src), armour_penetration) @@ -1160,6 +1164,7 @@ GLOBAL_LIST_EMPTY(bounty_boss_barricades) var/list/turfs /// The boss whose fire it is, for who it may hurt var/datum/weakref/boss_ref + var/damage_factor = 1 /obj/effect/bounty_boss_fire_pool/Initialize(mapload, list/fire_turfs, lifetime, mob/living/basic/bounty_criminal/boss/boss, landing_damage = 0) . = ..() @@ -1174,6 +1179,7 @@ GLOBAL_LIST_EMPTY(bounty_boss_barricades) if(!length(turfs)) return INITIALIZE_HINT_QDEL boss_ref = boss ? WEAKREF(boss) : null + damage_factor = boss ? boss.get_npc_zone_damage_factor() : 1 // Invisible, but the light comes from here: sit it where the fire is. var/turf/middle = turfs[round((length(turfs) + 1) / 2)] if(middle != loc) @@ -1205,13 +1211,13 @@ GLOBAL_LIST_EMPTY(bounty_boss_barricades) continue if(ismecha(thing)) var/obj/vehicle/sealed/mecha/mech = thing - mech.take_damage(max(damage, BOUNTY_BOSS_BURNING_DAMAGE), BURN, FIRE, FALSE) + mech.take_damage(npc_zone_damage(max(damage, BOUNTY_BOSS_BURNING_DAMAGE), damage_factor), BURN, FIRE, FALSE) continue var/mob/living/victim = thing if(damage > 0) - victim.apply_damage(damage, BURN, blocked = victim.run_armor_check(null, FIRE, silent = TRUE), spread_damage = TRUE) + victim.apply_damage(npc_zone_damage(damage, damage_factor), BURN, blocked = victim.run_armor_check(null, FIRE, silent = TRUE), spread_damage = TRUE) to_chat(victim, span_userdanger("You're caught in the flames!")) - victim.apply_status_effect(/datum/status_effect/bounty_boss_burning) + victim.apply_status_effect(/datum/status_effect/bounty_boss_burning, damage_factor) /obj/effect/bounty_boss_fire_pool/proc/burn_out() qdel(src) @@ -1229,6 +1235,15 @@ GLOBAL_LIST_EMPTY(bounty_boss_barricades) alert_type = null /// The flames on them var/mutable_appearance/flames + var/damage_factor = 1 + +/datum/status_effect/bounty_boss_burning/on_creation(mob/living/new_owner, factor = 1) + damage_factor = factor + return ..() + +/datum/status_effect/bounty_boss_burning/refresh(mob/living/new_owner, factor = 1) + damage_factor = factor + return ..() /datum/status_effect/bounty_boss_burning/on_apply() if(owner.stat != CONSCIOUS || HAS_TRAIT(owner, TRAIT_NOFIRE)) @@ -1241,7 +1256,7 @@ GLOBAL_LIST_EMPTY(bounty_boss_barricades) if(owner.stat != CONSCIOUS) qdel(src) return - owner.apply_damage(BOUNTY_BOSS_BURNING_DAMAGE, BURN, blocked = owner.run_armor_check(null, FIRE, silent = TRUE), spread_damage = TRUE) + owner.apply_damage(npc_zone_damage(BOUNTY_BOSS_BURNING_DAMAGE, damage_factor), BURN, blocked = owner.run_armor_check(null, FIRE, silent = TRUE), spread_damage = TRUE) /datum/status_effect/bounty_boss_burning/on_remove() if(flames) diff --git a/voidcrew/modules/bounties/bounty_boss_kits.dm b/voidcrew/modules/bounties/bounty_boss_kits.dm index 2b70bce6227..22bfcd86bb2 100644 --- a/voidcrew/modules/bounties/bounty_boss_kits.dm +++ b/voidcrew/modules/bounties/bounty_boss_kits.dm @@ -673,6 +673,7 @@ /// Who it catches, and how hard var/radius = BOUNTY_DEMOLITIONIST_GRENADE_RADIUS var/damage = BOUNTY_DEMOLITIONIST_GRENADE_DAMAGE + var/damage_factor = 1 var/knockdown = BOUNTY_DEMOLITIONIST_GRENADE_KNOCKDOWN /// What it breaks, and how hard var/object_radius = BOUNTY_DEMOLITIONIST_GRENADE_OBJECT_RADIUS @@ -688,6 +689,7 @@ return INITIALIZE_HINT_QDEL GLOB.bounty_boss_explosives += src boss_ref = boss ? WEAKREF(boss) : null + damage_factor = boss ? boss.get_npc_zone_damage_factor() : 1 structure_tally = list(BOUNTY_BOSS_ABILITY_STRUCTURE_CAP) ring = new(get_turf(src), fuse, COLOR_RED, "target_circle") ring.transform = matrix() * (radius * 2 + 1) @@ -729,12 +731,12 @@ if(!(isliving(victim) || ismecha(victim)) || !may_hit(victim, boss) || !bounty_boss_clear_line(here, get_turf(victim))) continue if(boss) - boss.boss_hit(victim, damage, BRUTE, BOMB, knockdown) + boss.boss_hit(victim, npc_zone_damage(damage, damage_factor), BRUTE, BOMB, knockdown, already_scaled = TRUE) else if(ismecha(victim)) - victim.take_damage(damage, BRUTE, BOMB, FALSE) + victim.take_damage(npc_zone_damage(damage, damage_factor), BRUTE, BOMB, FALSE) else var/mob/living/person = victim - person.apply_damage(damage, BRUTE, BODY_ZONE_CHEST, person.run_armor_check(BODY_ZONE_CHEST, BOMB, silent = TRUE)) + person.apply_damage(npc_zone_damage(damage, damage_factor), BRUTE, BODY_ZONE_CHEST, person.run_armor_check(BODY_ZONE_CHEST, BOMB, silent = TRUE)) if(knockdown) person.Knockdown(knockdown) qdel(src) @@ -841,7 +843,7 @@ /mob/living/basic/bounty_criminal/boss/ghost/proc/boss_cut(mob/living/victim) if(QDELETED(victim) || victim.stat == DEAD) return - victim.apply_status_effect(/datum/status_effect/bounty_boss_bleed) + victim.apply_status_effect(/datum/status_effect/bounty_boss_bleed, get_npc_zone_damage_factor()) boss_cuts++ if(boss_cuts >= BOUNTY_GHOST_CUTS_BEFORE_BREAKOFF) boss_cuts = 0 @@ -1022,7 +1024,7 @@ boss.boss_hit(victim, BOUNTY_GHOST_DASH_DAMAGE, BRUTE, MELEE, 0, BOUNTY_GHOST_DASH_AP) return var/mob/living/person = victim - person.apply_damage(BOUNTY_GHOST_DASH_DAMAGE, BRUTE, BODY_ZONE_CHEST, person.run_armor_check(BODY_ZONE_CHEST, MELEE, armour_penetration = BOUNTY_GHOST_DASH_AP, silent = TRUE), sharpness = SHARP_EDGED) + person.apply_damage(npc_zone_damage(BOUNTY_GHOST_DASH_DAMAGE, boss), BRUTE, BODY_ZONE_CHEST, person.run_armor_check(BODY_ZONE_CHEST, MELEE, armour_penetration = BOUNTY_GHOST_DASH_AP, silent = TRUE), sharpness = SHARP_EDGED) boss.boss_cut(person) /// Cloak: the air around it shimmers, then it fades to a faint distortion that half of all hits miss @@ -1060,11 +1062,17 @@ alert_type = null /// Cuts bleeding var/cuts = 1 + var/damage_factor = 1 + +/datum/status_effect/bounty_boss_bleed/on_creation(mob/living/new_owner, factor = 1) + damage_factor = factor + return ..() /datum/status_effect/bounty_boss_bleed/on_apply() return owner.stat == CONSCIOUS -/datum/status_effect/bounty_boss_bleed/refresh(effect, ...) +/datum/status_effect/bounty_boss_bleed/refresh(mob/living/new_owner, factor = 1) + damage_factor = factor . = ..() cuts++ @@ -1073,7 +1081,7 @@ qdel(src) return var/rate = min(cuts * BOUNTY_GHOST_BLEED_PER_CUT, BOUNTY_GHOST_BLEED_CAP) - owner.apply_damage(rate, BRUTE, spread_damage = TRUE) + owner.apply_damage(npc_zone_damage(rate, damage_factor), BRUTE, spread_damage = TRUE) owner.bleed(rate) // ===== HEAVY ===== diff --git a/voidcrew/modules/bounties/bounty_criminal.dm b/voidcrew/modules/bounties/bounty_criminal.dm index e4ef0fc148d..b07705225da 100644 --- a/voidcrew/modules/bounties/bounty_criminal.dm +++ b/voidcrew/modules/bounties/bounty_criminal.dm @@ -163,8 +163,11 @@ if(!where) return null var/criminal_type = bounty_criminal_type(record, posting) - var/mob/living/basic/bounty_criminal/criminal = new criminal_type(where) + var/atom/site = posting?.site_ref?.resolve() + var/datum/npc_spawn_context/context = new(site || where, null, "ordinary", source_turf = site ? get_turf(site) : where) + var/mob/living/basic/bounty_criminal/criminal = spawn_npc_in_zone(criminal_type, where, context, FALSE) criminal.body_setup(record, posting) + context.finalize() return criminal /// The criminal type for `record` wanted on `posting`: meek, normal, or the mini-boss of its kit. A mini-boss never goes to a trader outpost; a normal criminal stands in (D-A8). @@ -275,9 +278,24 @@ /mob/living/basic/bounty_criminal/proc/body_match(mob/living/basic/bounty_criminal/other) if(QDELETED(other) || other == src) return - maxHealth = other.maxHealth - setBruteLoss(other.getBruteLoss()) + // Copy raw stats before finalizing the inherited profile, never its scaled pool. + var/datum/npc_spawn_context/context = npc_spawn_context + if(!context || context.source_id != other.npc_spawn_context?.source_id) + context = other.bounty_profile_context() + if(npc_zone_applied) + UnregisterSignal(src, COMSIG_PROJECTILE_FIRER_BEFORE_FIRE) + melee_damage_lower = npc_zone_original_melee_lower + melee_damage_upper = npc_zone_original_melee_upper + npc_zone_applied = FALSE + npc_zone_health_factor = 1 + npc_zone_damage_factor = 1 + npc_spawn_context = context + maxHealth = other.npc_zone_applied ? other.npc_zone_original_max_health : other.maxHealth + var/health_share = other.maxHealth > 0 ? other.health / other.maxHealth : 1 + setBruteLoss(maxHealth * (1 - health_share)) updatehealth() + context.bodies |= WEAKREF(src) + context.finalize() set_varspeed(other.speed) damage_coeff[STAMINA] = other.damage_coeff[STAMINA] stamina_regen_time = other.stamina_regen_time @@ -287,6 +305,11 @@ max_stamina_slowdown = other.max_stamina_slowdown make_stamina_slowable() +/// Decoys use the source's selected role before construction, including named boss bodies. +/mob/living/basic/bounty_criminal/proc/bounty_profile_context() + var/role = npc_zone_role || (npc_zone_boss_type(type) ? "boss" : npc_spawn_context?.role || "ordinary") + return new /datum/npc_spawn_context(src, null, role) + // ===== THE SITE ===== /** diff --git a/voidcrew/modules/bounties/bounty_kingpin.dm b/voidcrew/modules/bounties/bounty_kingpin.dm index 75378fd52dc..212a8c22d44 100644 --- a/voidcrew/modules/bounties/bounty_kingpin.dm +++ b/voidcrew/modules/bounties/bounty_kingpin.dm @@ -1236,7 +1236,9 @@ GLOBAL_LIST_EMPTY(bounty_kingpin_marks) /datum/bounty_kingpin_crew/proc/spawn_goon(turf/post, weapon = BOUNTY_GOON_WEAPON_PISTOL) if(!post) return null - var/mob/living/basic/bounty_kingpin_goon/goon = new(post) + var/mob/living/basic/bounty_criminal/kingpin/kingpin = kingpin_ref?.resolve() + var/datum/npc_spawn_context/context = new(kingpin || post, null, "ordinary", source_turf = post) + var/mob/living/basic/bounty_kingpin_goon/goon = spawn_npc_in_zone(/mob/living/basic/bounty_kingpin_goon, post, context, FALSE) goon.goon_weapon = weapon goon.goon_post = post goon.goon_rounds = bounty_kingpin_goon_mag(weapon) @@ -1255,6 +1257,7 @@ GLOBAL_LIST_EMPTY(bounty_kingpin_marks) goon.goon_post_dir = facing || SOUTH goon.setDir(goon.goon_post_dir) add_goon(goon) + context.finalize() return goon /// Makes `goon` one of the crew @@ -2469,13 +2472,15 @@ GLOBAL_LIST_EMPTY(bounty_kingpin_marks) /proc/bounty_kingpin_setup(turf/seat, list/posts, datum/bounty_record/record) if(!seat) return null - var/mob/living/basic/bounty_criminal/kingpin/kingpin = new(seat) + var/datum/npc_spawn_context/context = new(seat, null, "boss") + var/mob/living/basic/bounty_criminal/kingpin/kingpin = spawn_npc_in_zone(/mob/living/basic/bounty_criminal/kingpin, seat, context, FALSE) kingpin.kingpin_crew = new /datum/bounty_kingpin_crew(kingpin, seat) kingpin.body_setup(record, null) var/obj/structure/overmap/trader_outpost/outpost = get_trader_outpost_for_turf(seat) if(outpost) kingpin.body_set_site(outpost) kingpin.kingpin_sit() + context.finalize() for(var/list/post as anything in posts) kingpin.kingpin_crew.crew_posts += list(post.Copy()) kingpin.kingpin_crew.spawn_goon(post[1], post[2]) @@ -2934,3 +2939,7 @@ SUBSYSTEM_DEF(bounty_kingpin) if(!posting) return panel.refuse(user, "The kingpin couldn't be posted.") return "post the kingpin bounty on [posting.record?.name || "nobody"] at [posting.board_site_name || "the black market"]" + +/// His lounge faction stays neutral; his explicit boss encounter is still profiled. +/mob/living/basic/bounty_criminal/kingpin/is_npc_zone_exempt() + return npc_zone_exempt || npc_spawn_context?.exempt || client || mind diff --git a/voidcrew/modules/bounties/bounty_lair.dm b/voidcrew/modules/bounties/bounty_lair.dm index 35e63a6382f..c23df9f8138 100644 --- a/voidcrew/modules/bounties/bounty_lair.dm +++ b/voidcrew/modules/bounties/bounty_lair.dm @@ -538,7 +538,10 @@ if(!ispath(boss_type, /mob/living)) log_mapping("BOUNTY LAIR: [name] has a boss landmark with no mob type at [AREACOORD(home)]") continue - lair_adopt_boss(new boss_type(home)) + var/datum/npc_spawn_context/context = new(src, null, "boss") + var/mob/living/boss = spawn_npc_in_zone(boss_type, home, context, FALSE) + lair_adopt_boss(boss) + context.finalize() for(var/obj/effect/landmark/bounty_lair_gatekeeper/mark as anything in keeper_marks) if(QDELETED(mark)) @@ -551,7 +554,10 @@ if(!ispath(keeper_type, /mob/living)) log_mapping("BOUNTY LAIR: [name] has a gatekeeper landmark with no mob type at [AREACOORD(home)]") continue - lair_add_gatekeeper(new keeper_type(home)) + var/datum/npc_spawn_context/context = new(src, null, "boss") + var/mob/living/keeper = spawn_npc_in_zone(keeper_type, home, context, FALSE) + lair_add_gatekeeper(keeper) + context.finalize() lair_leash_goons() lair_goon_timer = addtimer(CALLBACK(src, PROC_REF(lair_leash_goons)), BOUNTY_LAIR_GOON_LEASH_DELAY, TIMER_STOPPABLE) diff --git a/voidcrew/modules/bounties/bounty_lair_mafia.dm b/voidcrew/modules/bounties/bounty_lair_mafia.dm index 3c2913c6004..796e4eb45f9 100644 --- a/voidcrew/modules/bounties/bounty_lair_mafia.dm +++ b/voidcrew/modules/bounties/bounty_lair_mafia.dm @@ -573,7 +573,7 @@ GLOBAL_LIST_EMPTY(bounty_mafia_rooms) for(var/mob/living/pilot in suit.occupants) if(rocket_volley) rocket_volley[REF(pilot)] = TRUE - return suit.take_damage(BOUNTY_MECH_ROCKET_EXOSUIT_DAMAGE, BRUTE, BULLET, TRUE, get_dir(suit, src)) + return suit.take_damage(npc_zone_damage(BOUNTY_MECH_ROCKET_EXOSUIT_DAMAGE, npc_zone_damage_factor), BRUTE, BULLET, TRUE, get_dir(suit, src)) /obj/projectile/bullet/bounty_mafia_rocket/on_hit(atom/target, blocked = 0, pierce_hit) . = ..() @@ -614,7 +614,7 @@ GLOBAL_LIST_EMPTY(bounty_mafia_rooms) if(rocket_volley) rocket_volley[key] = TRUE var/blocked = victim.run_armor_check(BODY_ZONE_CHEST, BULLET, silent = TRUE) - victim.apply_damage(damage, BRUTE, BODY_ZONE_CHEST, blocked) + victim.apply_damage(npc_zone_damage(damage, npc_zone_damage_factor, npc_zone_damage_scaled), BRUTE, BODY_ZONE_CHEST, blocked) victim.Knockdown(BOUNTY_MECH_ROCKET_KNOCKDOWN) to_chat(victim, span_userdanger("A rocket bursts right at your feet!")) . += victim @@ -1112,14 +1112,11 @@ GLOBAL_LIST_EMPTY(bounty_mafia_rooms) /** * The club's goons. On P11's map every room has one of these; its room (the marker's area) fixes the crew - * (bounty_mafia_room_crew()). Anywhere else it rolls 3-5 from the zone table like any other theme. Goons + * (bounty_mafia_room_crew()). Each marker rolls 1-2 from its room's weighted roster. Goons * only spawn on tiles of the marker's own room. */ /obj/effect/zone_mobs/mafia name = "zone mob spawner (mafia)" - count_green = list(3, 4) - count_yellow = list(3, 5) - count_red = list(4, 5) scatter_radius = 3 mobs_green = list( /mob/living/basic/trooper/russian/mafia = 4, @@ -1143,10 +1140,11 @@ GLOBAL_LIST_EMPTY(bounty_mafia_rooms) if(!crew) return ..() var/list/open_turfs = get_scatter_turfs() - for(var/mob_path in crew) - for(var/i in 1 to crew[mob_path]) - var/turf/spot = length(open_turfs) ? pick_n_take(open_turfs) : get_turf(src) - new mob_path(spot) + for(var/i in 1 to rand(1, 2)) + var/mob_path = pick_weight(crew) + var/turf/spot = length(open_turfs) ? pick_n_take(open_turfs) : get_turf(src) + var/datum/npc_spawn_context/context = new(src, zone_type, "ordinary") + spawn_npc_in_zone(mob_path, spot, context) /obj/effect/zone_mobs/mafia/get_scatter_turfs() var/area/room = get_area(src) @@ -1516,8 +1514,11 @@ GLOBAL_LIST_EMPTY(bounty_mafia_rooms) return FALSE var/list/table = mech_health_table() var/wanted = table[clamp(count, 1, length(table))] + var/raw_health = wanted + wanted *= npc_zone_health_factor if(wanted <= maxHealth) return FALSE + npc_zone_original_max_health = raw_health setMaxHealth(wanted) updatehealth() if(announce && count > 1) @@ -1595,8 +1596,7 @@ GLOBAL_LIST_EMPTY(bounty_mafia_rooms) mech_engaged = list() mech_grudge = list() adjust_health(-getBruteLoss()) - setMaxHealth(BOUNTY_MECH_HEALTH_1) - updatehealth() + set_npc_zone_health(BOUNTY_MECH_HEALTH_1) ai_controller?.clear_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET) visible_message(span_notice("[src] vents steam as its repair arms fold away. It looks as good as new.")) @@ -1877,7 +1877,8 @@ GLOBAL_LIST_EMPTY(bounty_mafia_rooms) var/obj/structure/bounty_mafia_wreck/wreck = new(spot) wreck.setDir(dir) var/turf/exit = mech_exit_turf(spot) - var/mob/living/basic/bounty_lair_boss/mafia_don/don = new(exit || spot) + var/datum/npc_spawn_context/context = new(src, null, "boss") + var/mob/living/basic/bounty_lair_boss/mafia_don/don = spawn_npc_in_zone(/mob/living/basic/bounty_lair_boss/mafia_don, exit || spot, context, FALSE) don.posting_ref = posting_ref don.don_wreck_ref = WEAKREF(wreck) // Whoever broke his machine, he knows @@ -1891,6 +1892,7 @@ GLOBAL_LIST_EMPTY(bounty_mafia_rooms) don.real_name = posting.record.name SEND_SIGNAL(src, COMSIG_BOUNTY_MAFIA_DON_EJECTED, don) don.don_on_eject() + context.finalize() return don /// The open tile beside `wreck_spot`, in its arena, farthest from the hunters diff --git a/voidcrew/modules/bounties/bounty_outpost.dm b/voidcrew/modules/bounties/bounty_outpost.dm index 0f7f8ccb82b..138e96136b2 100644 --- a/voidcrew/modules/bounties/bounty_outpost.dm +++ b/voidcrew/modules/bounties/bounty_outpost.dm @@ -207,7 +207,8 @@ GLOBAL_LIST_INIT(bounty_outpost_trader_react_lines, list( // If a line ever names a crime, it names the same one for everybody if(decoy_record) decoy_record.crime = record.crime - var/mob/living/basic/bounty_criminal/decoy/decoy = new(spot) + var/datum/npc_spawn_context/context = fugitive.bounty_profile_context() + var/mob/living/basic/bounty_criminal/decoy/decoy = spawn_npc_in_zone(/mob/living/basic/bounty_criminal/decoy, spot, context, FALSE) var/atom/anchor = (length(free_stools) && prob(50)) ? pick_n_take(free_stools) : null decoy.outpost_become(fugitive, decoy_record, src, outpost, display_name, display_desc, outfit, anchor) decoys += WEAKREF(decoy) diff --git a/voidcrew/modules/bounties/bounty_weapons.dm b/voidcrew/modules/bounties/bounty_weapons.dm index b173c94c03b..d4f4fac0902 100644 --- a/voidcrew/modules/bounties/bounty_weapons.dm +++ b/voidcrew/modules/bounties/bounty_weapons.dm @@ -192,8 +192,7 @@ GLOBAL_LIST_EMPTY(bounty_real_weapons) /// Puts its hand numbers on `fighter`'s own blow. The blow's timing stays the fighter's. /datum/bounty_real_weapon/proc/apply_melee(mob/living/basic/fighter) read_melee() - fighter.melee_damage_lower = force_low - fighter.melee_damage_upper = force_high + fighter.set_npc_zone_melee(force_low, force_high) fighter.melee_damage_type = damage_type fighter.sharpness = sharpness fighter.wound_bonus = wound_bonus diff --git a/voidcrew/modules/derelict_outposts/derelict_themes.dm b/voidcrew/modules/derelict_outposts/derelict_themes.dm index 22a7fd5b41c..4d4175bc53c 100644 --- a/voidcrew/modules/derelict_outposts/derelict_themes.dm +++ b/voidcrew/modules/derelict_outposts/derelict_themes.dm @@ -720,7 +720,7 @@ // The boss first, at its anchor var/turf/boss_tile = (boss_anchor && hostile_can_start(boss_anchor, generator)) ? boss_anchor : pick_hostile_tile(legal, spawned, boss_anchor, FALSE) if(boss_tile) - add_hostile(theme, theme.boss_type, boss_tile, red ? DERELICT_BOSS_HEALTH_MULT_RED : DERELICT_BOSS_HEALTH_MULT_YELLOW, spawned) + add_hostile(theme, theme.boss_type, boss_tile, "boss", spawned) else log_mapping("Derelict outpost [site.true_name]: no room for its [theme.name] boss.") // Then the roster, taking the anchors in turn so every cluster is guarded @@ -741,7 +741,7 @@ if(!tile) log_mapping("Derelict outpost [site.true_name]: no room for a [hostile_type].") continue - add_hostile(theme, hostile_type, tile, red ? DERELICT_HEALTH_MULT_RED : DERELICT_HEALTH_MULT_YELLOW, spawned) + add_hostile(theme, hostile_type, tile, "ordinary", spawned) /** * A start tile for one hostile from `legal`, spaced DERELICT_HOSTILE_SPACING from the others (1 if nothing fits). @@ -772,19 +772,13 @@ return null /// Spawns one hostile of `hostile_type` on `tile`, readies, scales and leashes it. Returns it, or null. -/datum/derelict_scene/proc/add_hostile(datum/derelict_theme/theme, hostile_type, turf/tile, multiplier, list/mob/living/spawned) - var/mob/living/hostile = new hostile_type(tile) +/datum/derelict_scene/proc/add_hostile(datum/derelict_theme/theme, hostile_type, turf/tile, role, list/mob/living/spawned) + var/datum/npc_spawn_context/context = new(site, site.derelict_band, role) + var/mob/living/hostile = spawn_npc_in_zone(hostile_type, tile, context, FALSE) if(QDELETED(hostile)) - // A mi-go can come out as its rare variant, which takes its place on the tile - hostile = null - for(var/mob/living/replacement in tile) - if(istype(replacement, hostile_type) && !QDELETED(replacement) && !(replacement in spawned)) - hostile = replacement - break - if(!hostile) - return null + return null theme.prepare_hostile(hostile) - scale_npc_ship_pirate_health(hostile, multiplier) + context.finalize() hostile.AddComponent(/datum/component/derelict_leash, site) site.derelict_hostiles += WEAKREF(hostile) spawned += hostile diff --git a/voidcrew/modules/npc_ships/code/_defines.dm b/voidcrew/modules/npc_ships/code/_defines.dm index 335fd1b08bb..d1c533268ea 100644 --- a/voidcrew/modules/npc_ships/code/_defines.dm +++ b/voidcrew/modules/npc_ships/code/_defines.dm @@ -121,10 +121,7 @@ GLOBAL_LIST_EMPTY(patrol_stagger_counter) #define COMSIG_BOARDING_ESCALATED "boarding_escalated" // Fired when player aggression escalates to full combat // Boarding timing constants -#define NPC_BOARDING_WAVE_COUNT 3 // Number of waves before boss -/// Yellow zone raids are a single crew-scaled wave with no boss - the pirate -/// leaves once it's repelled. Red keeps the full gauntlet above. -#define NPC_BOARDING_WAVE_COUNT_YELLOW 1 +#define NPC_BOARDING_WAVE_COUNT 1 // One crew-sized wave, then a boss in red #define NPC_BOARDING_WAVE_COOLDOWN (30 SECONDS) // Time between waves #define NPC_BOARDING_DISENGAGE_DELAY (10 SECONDS) // Time before pirates leave after victory #define NPC_BOARDING_WAVE_TIME_LIMIT (3 MINUTES) // Max time per wave before escalation @@ -139,16 +136,6 @@ GLOBAL_LIST_EMPTY(patrol_stagger_counter) #define NPC_SHIP_COMBAT_MAX_BOARDERS 10 // Max hostile mobs during ship combat phase #define NPC_SHIP_COMBAT_POD_COOLDOWN (15 SECONDS) // Cooldown between boarding pod volleys -// Boarding difficulty -/// Health multiplier for crew aboard an NPC ship and for anything it drops on you -/// in a boarding pod. Applied at the spawn site by scale_npc_ship_pirate_health() -/// rather than on the mob definitions, because ruin zone spawners, planet spawns -/// and bounty missions reuse the same faction pirate types and are tuned for their -/// own zone bands. -#define NPC_PIRATE_CREW_HEALTH_MULT 1.8 -/// Same, for the faction boss that drops in after the last wave is repelled. -#define NPC_PIRATE_BOSS_HEALTH_MULT 1.6 - // ========== NPC HULL WEALTH ========== // What a pirate is carrying in its own accounts, and therefore what a crew can // take back off it with a data siphon. Rolled per hull from the faction's diff --git a/voidcrew/modules/npc_ships/code/admin_verbs.dm b/voidcrew/modules/npc_ships/code/admin_verbs.dm index fb320e40619..e0c9bbb8c9c 100644 --- a/voidcrew/modules/npc_ships/code/admin_verbs.dm +++ b/voidcrew/modules/npc_ships/code/admin_verbs.dm @@ -91,7 +91,8 @@ ADMIN_VERB(spawn_npc_pirate, R_SPAWN|R_DEBUG, "Spawn NPC Pirate", "Spawn an NPC var/setup_patrol = tgui_alert(user, "Set up door-to-door patrol AI? (Requires being on a ship)", "Patrol AI", list("Yes", "No")) // Spawn the pirate - var/mob/living/basic/trooper/pirate/spawned_pirate = new mob_path(spawn_turf) + var/datum/npc_spawn_context/context = new(spawn_turf, null, "ordinary") + var/mob/living/basic/trooper/pirate/spawned_pirate = spawn_npc_in_zone(mob_path, spawn_turf, context, FALSE) if(!spawned_pirate) to_chat(user, span_warning("Failed to spawn pirate.")) return @@ -142,6 +143,7 @@ ADMIN_VERB(spawn_npc_pirate, R_SPAWN|R_DEBUG, "Spawn NPC Pirate", "Spawn an NPC else to_chat(user, span_notice("Spawned [spawned_pirate.name] ([selected_faction] - [selected_type]) without patrol AI.")) + context.finalize() message_admins("[key_name_admin(user)] spawned NPC pirate: [spawned_pirate.name] ([selected_faction] - [selected_type]) at [AREACOORD(spawn_turf)]") log_admin("[key_name(user)] spawned NPC pirate: [spawned_pirate.name] ([selected_faction] - [selected_type]) at [AREACOORD(spawn_turf)]") BLACKBOX_LOG_ADMIN_VERB("Spawn NPC Pirate") diff --git a/voidcrew/modules/npc_ships/code/behaviors/ship_combat_behaviors.dm b/voidcrew/modules/npc_ships/code/behaviors/ship_combat_behaviors.dm index 8d5383e6817..cd27b2e20e3 100644 --- a/voidcrew/modules/npc_ships/code/behaviors/ship_combat_behaviors.dm +++ b/voidcrew/modules/npc_ships/code/behaviors/ship_combat_behaviors.dm @@ -359,11 +359,11 @@ * Hailing behavior - pirate is demanding tribute, waiting for player response. * During this phase: * - Pirate follows target but doesn't attack - * - Player can answer via holopad → NEGOTIATING + * - Player can answer via holopad → NEGOTIATING * - Player can escape (moving is OK during hailing) - * - Player locks weapons → immediate COMBAT - * - Player fires on pirate → immediate COMBAT - * - 20 seconds pass without answer → escalation + * - Player locks weapons → immediate COMBAT + * - Player fires on pirate → immediate COMBAT + * - 20 seconds pass without answer → escalation * * What "escalation" means depends on the hail: red opens fire, a broke target * gets boarded, and a yellow-band shakedown gets its accounts drained by the @@ -692,16 +692,7 @@ if(target_has_shields) return AI_BEHAVIOR_DELAY - // Check if we've hit the max boarder cap (10 mobs max during ship combat) - var/current_boarders = count_hostile_mobs_on_ship(target) - if(current_boarders >= NPC_SHIP_COMBAT_MAX_BOARDERS) - return AI_BEHAVIOR_DELAY - - // Calculate number of pods to launch (don't exceed the cap) var/pod_count = rand(ship.boarding_pods_min, ship.boarding_pods_max) - pod_count = min(pod_count, NPC_SHIP_COMBAT_MAX_BOARDERS - current_boarders) - if(pod_count <= 0) - return AI_BEHAVIOR_DELAY // Fire the boarding pods! if(combat.fire_boarding_pods(target, pod_count)) diff --git a/voidcrew/modules/npc_ships/code/boarding_pod.dm b/voidcrew/modules/npc_ships/code/boarding_pod.dm index acce9b0ccca..c3e6d07b6d0 100644 --- a/voidcrew/modules/npc_ships/code/boarding_pod.dm +++ b/voidcrew/modules/npc_ships/code/boarding_pod.dm @@ -11,25 +11,32 @@ GLOBAL_VAR_INIT(boarding_spawn_total, 1) /// Global proc to create a boarding pod drop at a target location /// Returns the boarder mob so the caller can register signals (e.g. death tracking) -/proc/create_boarding_pod(turf/target_turf, obj/structure/overmap/ship/target_ship, obj/structure/overmap/ship/npc/source_ship, mob_type) +/proc/create_boarding_pod(turf/target_turf, obj/structure/overmap/ship/target_ship, obj/structure/overmap/ship/npc/source_ship, mob_type, datum/npc_spawn_context/encounter, budget_reserved = FALSE) if(!target_turf || !mob_type) return null // Combat volleys call this on a timer; the target may have docked since firing. if(QDELETED(target_ship) || QDELETED(source_ship) || target_ship.state != OVERMAP_SHIP_FLYING || source_ship.state != OVERMAP_SHIP_FLYING) return null + var/datum/ai_controller/npc_ship/controller = source_ship.ai_controller + if(!istype(controller) || controller.get_target() != target_ship) + return null + controller.capture_boarding_encounter(target_ship) + if(encounter && encounter != controller.boarding_context) + return null + if(!budget_reserved && !controller.reserve_boarders(target_ship, 1)) + return null + var/datum/npc_spawn_context/context = new(target_ship, controller.boarding_context.zone_type, "ordinary", source_turf = controller.boarding_context.source_turf) + // Create the boarding pod with the mob inside var/obj/structure/closet/supplypod/boarding/pod = new() // Create the boarder mob and put it in the pod - var/mob/living/boarder = new mob_type(pod) + var/mob/living/boarder = spawn_npc_in_zone(mob_type, pod, context) if(!boarder) qdel(pod) return null - // Boarders are tougher than the same mob type is out in a ruin - scale_npc_ship_pirate_health(boarder) - // Store references for the pod pod.target_ship = target_ship pod.source_ship = source_ship @@ -210,21 +217,27 @@ GLOBAL_VAR_INIT(boarding_spawn_total, 1) if(QDELETED(target_ship) || QDELETED(source_ship) || target_ship.state != OVERMAP_SHIP_FLYING || source_ship.state != OVERMAP_SHIP_FLYING) return null + var/datum/ai_controller/npc_ship/controller = source_ship.ai_controller + if(!istype(controller) || controller.get_target() != target_ship) + return null + controller.capture_boarding_encounter(target_ship) + if(!controller.is_red_zone_raid() || controller.boarding_boss_sent) + return null + controller.boarding_boss_sent = TRUE + var/datum/npc_spawn_context/context = new(target_ship, controller.boarding_context.zone_type, "boss", source_turf = controller.boarding_context.source_turf) + // Create the boss boarding pod var/obj/structure/closet/supplypod/boarding/boss/pod = new() // Create the boss mob and put it in the pod - var/mob/living/basic/trooper/pirate/faction/boss/boss = new mob_type(pod) + var/mob/living/basic/trooper/pirate/faction/boss/boss = spawn_npc_in_zone(mob_type, pod, context, FALSE) if(!boss) qdel(pod) return null - // Scaled after Initialize() so bosses that set their health there (silverscale) - // are multiplied off their real pool, not the var default - scale_npc_ship_pirate_health(boss, NPC_PIRATE_BOSS_HEALTH_MULT) - // Set up boss-specific properties boss.parent_ship = source_ship + context.finalize() // Store references for the pod pod.target_ship = target_ship diff --git a/voidcrew/modules/npc_ships/code/npc_combat_interface.dm b/voidcrew/modules/npc_ships/code/npc_combat_interface.dm index a4a958c8b9a..ba4b83f7c7f 100644 --- a/voidcrew/modules/npc_ships/code/npc_combat_interface.dm +++ b/voidcrew/modules/npc_ships/code/npc_combat_interface.dm @@ -482,16 +482,26 @@ if(!spawn_types || !length(spawn_types)) return FALSE + var/datum/ai_controller/npc_ship/controller = owner_ship.ai_controller + if(!istype(controller) || controller.get_target() != target_ship) + return FALSE + pod_count = controller.reserve_boarders(target_ship, pod_count) + if(!pod_count) + return controller.deploy_combat_boss(target_ship) + // Set up patrol distribution for this wave GLOB.boarding_spawn_index = 0 GLOB.boarding_spawn_total = pod_count var/pods_launched = 0 + controller.boarding_pending += pod_count // Launch pods at different locations on the target ship for(var/i in 1 to pod_count) var/turf/target_turf = get_random_target_turf(target_ship) if(!target_turf) + controller.boarding_pending-- + controller.boarding_committed-- continue // Pick a random mob type for this pod @@ -500,7 +510,7 @@ // Create the boarding pod with a slight delay between launches // Uses supplypod system - pod falls from above, lands, opens to reveal mob var/launch_delay = (i - 1) * 0.5 SECONDS - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(create_boarding_pod), target_turf, target_ship, owner_ship, mob_type), launch_delay) + controller.boarding_timers += addtimer(CALLBACK(controller, TYPE_PROC_REF(/datum/ai_controller/npc_ship, deploy_combat_boarder), target_turf, target_ship, mob_type, controller.boarding_context), launch_delay, TIMER_STOPPABLE) pods_launched++ if(pods_launched > 0) diff --git a/voidcrew/modules/npc_ships/code/npc_ship.dm b/voidcrew/modules/npc_ships/code/npc_ship.dm index 6e1adcc12a3..f2a57bad866 100644 --- a/voidcrew/modules/npc_ships/code/npc_ship.dm +++ b/voidcrew/modules/npc_ships/code/npc_ship.dm @@ -329,23 +329,6 @@ /obj/structure/overmap/ship/npc/proc/set_patrol_mode() set_movement_mode(NPC_MOVEMENT_PATROL) -/** - * Scales up a freshly spawned NPC ship pirate's health pool. - * - * NPC ship crew and boarding pod mobs are the same types the ruin zone spawners, - * planet spawns and bounty missions use, and those are balanced per zone band - - * so the "fighting a ship" difficulty lives here at the spawn site instead of on - * the mob definitions. It also picks up bosses that set their health in - * Initialize() rather than as a var default. - * - * Only valid on an undamaged mob: health is rebuilt from the new maxHealth. - */ -/proc/scale_npc_ship_pirate_health(mob/living/pirate, multiplier = NPC_PIRATE_CREW_HEALTH_MULT) - if(QDELETED(pirate) || multiplier <= 1) - return - pirate.maxHealth = round(pirate.maxHealth * multiplier) - pirate.updatehealth() - /** * Spawns crew aboard the ship using per-ship crew configuration. * Override crew_min, crew_max, and crew_types in subtypes for different crews. @@ -391,11 +374,12 @@ // Spawn captain first with ship key if(captain_type && length(valid_turfs)) var/turf/captain_loc = pick_n_take(valid_turfs) - var/mob/living/basic/captain = new captain_type(captain_loc) - scale_npc_ship_pirate_health(captain) + var/datum/npc_spawn_context/context = new(src, pool_zone_type, "boss") + var/mob/living/basic/captain = spawn_npc_in_zone(captain_type, captain_loc, context, FALSE) // Give captain the ship key - stored in contents, drops on death var/obj/item/ship_key/key = new(null, src) key.forceMove(captain) + context.finalize() // Track captain and register death signal tracked_crew += captain RegisterSignal(captain, COMSIG_LIVING_DEATH, PROC_REF(on_crew_death)) @@ -405,8 +389,8 @@ for(var/i in 1 to min(crew_count, length(valid_turfs))) var/turf/spawn_loc = pick_n_take(valid_turfs) var/mob_type = pick(crew_types) - var/mob/living/crewmember = new mob_type(spawn_loc) - scale_npc_ship_pirate_health(crewmember) + var/datum/npc_spawn_context/context = new(src, pool_zone_type, "ordinary") + var/mob/living/crewmember = spawn_npc_in_zone(mob_type, spawn_loc, context) // Track crew and register death signal tracked_crew += crewmember RegisterSignal(crewmember, COMSIG_LIVING_DEATH, PROC_REF(on_crew_death)) diff --git a/voidcrew/modules/npc_ships/code/npc_ship_controller.dm b/voidcrew/modules/npc_ships/code/npc_ship_controller.dm index f38d53ec3ed..f354152716e 100644 --- a/voidcrew/modules/npc_ships/code/npc_ship_controller.dm +++ b/voidcrew/modules/npc_ships/code/npc_ship_controller.dm @@ -26,6 +26,12 @@ /// Delayed boarding actions belonging to the current encounter. var/list/boarding_timers = list() + /// Captured once per target engagement, retained through combat escalation. + var/datum/npc_spawn_context/boarding_context + var/boarding_budget = 0 + var/boarding_committed = 0 + var/boarding_pending = 0 + var/boarding_boss_sent = FALSE /datum/ai_controller/npc_ship/New(atom/new_pawn) // Initialize combat blackboard @@ -432,6 +438,12 @@ // Crew-wipe findings are about one hull. Don't carry "I've seen them alive" or a // half-elapsed wipe timer over onto whoever we point at next. if(old_target != target) + cleanup_boarding_signals() + boarding_context = null + boarding_budget = 0 + boarding_committed = 0 + boarding_pending = 0 + boarding_boss_sent = FALSE clear_blackboard_key(BB_NPC_TARGET_CREW_SEEN) clear_blackboard_key(BB_NPC_CREW_WIPE_SINCE) @@ -443,6 +455,7 @@ if(target) set_blackboard_key(BB_NPC_TARGET, target) + capture_boarding_encounter(target) // Mark this target as engaged by us (only one pirate can engage at a time) // Don't overwrite if another active pirate already has this target claimed if(our_ship) @@ -619,11 +632,10 @@ /** * TRUE if the target we are raiding is in the lawless (red) band. - * Red runs the full wave gauntlet plus a boss; everywhere else gets the - * lighter single-wave raid. + * Red adds one boss to the single ordinary boarding budget. */ /datum/ai_controller/npc_ship/proc/is_red_zone_raid() - return get_raid_zone()?.zone_type == ZONE_RED + return (boarding_context ? boarding_context.zone_type : get_raid_zone()?.zone_type) == ZONE_RED /** * TRUE if the thing waiting at the end of this hail is the data siphon rather @@ -661,7 +673,7 @@ * fighting in. */ /datum/ai_controller/npc_ship/proc/get_boarding_wave_count() - return is_red_zone_raid() ? NPC_BOARDING_WAVE_COUNT : NPC_BOARDING_WAVE_COUNT_YELLOW + return NPC_BOARDING_WAVE_COUNT /** * End a yellow-zone raid. The single wave has been repelled, so the pirate @@ -677,7 +689,7 @@ var/obj/structure/overmap/ship/target = get_target() if(target && !QDELETED(target)) - target.ship_notify("Boarding party eliminated! [ship?.name || "The attacker"] is breaking off.", "COMBAT", SHIP_NOTIFY_NOTICE, 'voidcrew/sound/notify.ogg', 50) + target.ship_notify("[ship?.name || "The attacker"] is breaking off.", "COMBAT", SHIP_NOTIFY_NOTICE, 'voidcrew/sound/notify.ogg', 50) ship?.ship_notify("Boarding party lost. Disengaging.", "COMMS", SHIP_NOTIFY_WARNING, 'voidcrew/sound/notify2.ogg', 50) clear_target() @@ -697,8 +709,8 @@ return FALSE // Count and store player crew count for wave scaling - var/crew_count = count_player_crew(target) - set_blackboard_key(BB_NPC_BOARDING_INITIAL_CREW_COUNT, crew_count) + capture_boarding_encounter(target) + set_blackboard_key(BB_NPC_BOARDING_INITIAL_CREW_COUNT, boarding_budget) // Start tracking player crew deaths start_tracking_player_crew(target) @@ -774,24 +786,15 @@ return // Announce boarding phase start - ship.ship_notify("Boarding operation initiated. Wave 1 deploying.", "COMBAT", SHIP_NOTIFY_WARNING, 'voidcrew/sound/alert2.ogg', 25) + ship.ship_notify("Boarding operation initiated.", "COMBAT", SHIP_NOTIFY_WARNING, 'voidcrew/sound/alert2.ogg', 25) target.ship_notify("[ship.name] is deploying boarding parties! Prepare to repel boarders!", "COMBAT", SHIP_NOTIFY_DANGER) - target.ship_notify("First wave incoming in 30 seconds!", "COMBAT", SHIP_NOTIFY_WARNING, 'voidcrew/sound/notify.ogg', 50) + target.ship_notify("Boarding pods inbound!", "COMBAT", SHIP_NOTIFY_WARNING, 'voidcrew/sound/notify.ogg', 50) /** - * Count living humanoid crew on the target ship. - * Used for wave scaling. + * Count living connected carbon and silicon crew on the target ship. */ /datum/ai_controller/npc_ship/proc/count_player_crew(obj/structure/overmap/ship/target) - if(!target?.shuttle?.shuttle_areas) - return 0 - - var/count = 0 - for(var/area/shuttle_area as anything in target.shuttle.shuttle_areas) - for(var/mob/living/carbon/human/H in shuttle_area) - if(H.stat != DEAD) - count++ - return count + return max(0, count_living_crew(target)) /** * Launch a boarding wave of the specified number. @@ -811,27 +814,9 @@ if(!ship || !target || QDELETED(target)) return FALSE - // Get wave size range from ship config - var/list/wave_sizes = ship.boarding_wave_sizes - if(!wave_sizes || wave_number > length(wave_sizes)) + if(wave_number != 1) return FALSE - - var/list/wave_range = wave_sizes[wave_number] - var/base_min = wave_range[1] - var/base_max = wave_range[2] - - // Scale wave size based on initial crew count - var/initial_crew = blackboard[BB_NPC_BOARDING_INITIAL_CREW_COUNT] || 1 - var/scale_factor = get_crew_scale_factor(initial_crew) - - var/scaled_min = round(base_min * scale_factor) - var/scaled_max = round(base_max * scale_factor) - - // Ensure at least 1 boarder - scaled_min = max(1, scaled_min) - scaled_max = max(scaled_min, scaled_max) - - var/boarder_count = rand(scaled_min, scaled_max) + var/boarder_count = max(0, boarding_budget - boarding_committed) // Get mob types to spawn (use boarding pod types or crew types) var/list/mob_types = ship.boarding_pod_mob_types @@ -877,26 +862,11 @@ blackboard[BB_NPC_BOARDING_TARGET_POS] = list(target.x, target.y) // Notify target ship - target.ship_notify("Wave [wave_number]: [length(wave_boarders)] hostiles have boarded!", "SECURITY", SHIP_NOTIFY_DANGER, 'voidcrew/sound/warn3.ogg', 25) + target.ship_notify("Hostiles have boarded!", "SECURITY", SHIP_NOTIFY_DANGER, 'voidcrew/sound/warn3.ogg', 25) npc_metric_boarding_wave(src, wave_number, length(wave_boarders)) return TRUE -/** - * Get crew scaling factor based on player crew count. - * Returns multiplier for wave sizes. - */ -/datum/ai_controller/npc_ship/proc/get_crew_scale_factor(crew_count) - switch(crew_count) - if(0 to 2) - return 0.75 // Solo/duo - smaller waves - if(3 to 4) - return 1.0 // Standard crew - normal waves - if(5 to 6) - return 1.25 // Larger crew - bigger waves - else - return 1.5 // Full crew - maximum waves - /** * Find valid turfs on the target ship for spawning boarders. */ @@ -947,7 +917,7 @@ /datum/ai_controller/npc_ship/proc/check_wave_complete() // Guard against multiple calls - only process if we're in BOARDING state var/combat_state = get_combat_state() - if(combat_state != NPC_COMBAT_BOARDING && combat_state != NPC_COMBAT_BOSS_PHASE) + if(combat_state != NPC_COMBAT_BOARDING || !validate_boarding_target()) return var/list/wave_boarders = blackboard[BB_NPC_BOARDING_WAVE_BOARDERS] @@ -1043,7 +1013,7 @@ var/obj/structure/overmap/ship/npc/pirate/ship = get_ship() var/obj/structure/overmap/ship/target = get_target() - if(!ship || !target) + if(!ship || !target || boarding_boss_sent || !is_red_zone_raid()) return // Enter cooldown state (reuse boarding cooldown state) @@ -1062,7 +1032,7 @@ target.ship_notify("[ship.name]: \"[taunt]\"", "COMMS", SHIP_NOTIFY_DANGER, 'voidcrew/sound/alert3.ogg', 25) // Announce boss incoming - target.ship_notify("All waves repelled! Enemy commander boarding in 30 seconds...", "COMBAT", SHIP_NOTIFY_WARNING, 'voidcrew/sound/notify.ogg', 50) + target.ship_notify("Enemy commander inbound!", "COMBAT", SHIP_NOTIFY_WARNING, 'voidcrew/sound/notify.ogg', 50) // Schedule boss spawn boarding_timers += addtimer(CALLBACK(src, PROC_REF(spawn_boarding_boss)), NPC_BOARDING_WAVE_COOLDOWN, TIMER_STOPPABLE) @@ -1224,7 +1194,7 @@ // walking every turf of every shuttle area - this runs on a 5 second poll per pirate. var/count = 0 for(var/mob/living/crew in GLOB.player_list) - if(crew.stat == DEAD) + if(crew.stat == DEAD || !crew.client) continue if(!iscarbon(crew) && !issilicon(crew)) continue @@ -1359,6 +1329,8 @@ for(var/timer_id in boarding_timers) deltimer(timer_id) boarding_timers.Cut() + boarding_committed -= boarding_pending + boarding_pending = 0 // Unregister from player crew deaths var/list/tracked_crew = blackboard[BB_NPC_BOARDING_PLAYER_CREW] @@ -1410,10 +1382,11 @@ set_combat_state(NPC_COMBAT_ENGAGING) /** - * Handle wave timeout - advance to next wave instead of escalating to combat. - * Only escalate to ship combat if ALL waves time out (none defeated). + * Finish the ordinary wave on timeout, with the same band transition as clearance. */ /datum/ai_controller/npc_ship/proc/handle_wave_timeout() + if(get_combat_state() != NPC_COMBAT_BOARDING || !validate_boarding_target()) + return var/obj/structure/overmap/ship/npc/pirate/ship = get_ship() var/obj/structure/overmap/ship/target = get_target() var/current_wave = blackboard[BB_NPC_BOARDING_WAVE] || 1 @@ -1430,27 +1403,10 @@ UnregisterSignal(boarder, COMSIG_LIVING_DEATH) clear_blackboard_key(BB_NPC_BOARDING_WAVE_BOARDERS) - // Check if this was the final wave - if(current_wave >= NPC_BOARDING_WAVE_COUNT) - // All waves timed out - escalate to boss phase - ship.ship_notify("Time's up! Sending in the heavy hitter!", "COMBAT", SHIP_NOTIFY_WARNING, 'voidcrew/sound/alert2.ogg', 25) - target.ship_notify("[ship.name]: \"You've stalled long enough. Meet our enforcer.\"", "COMMS", SHIP_NOTIFY_DANGER, 'voidcrew/sound/alert3.ogg', 25) + if(is_red_zone_raid()) start_boss_cooldown() - return - - // Advance to next wave - var/next_wave = current_wave + 1 - ship.ship_notify("Wave [current_wave] timed out. Sending wave [next_wave]!", "COMBAT", SHIP_NOTIFY_WARNING) - target.ship_notify("[ship.name]: \"Your stalling won't save you. More incoming!\"", "COMMS", SHIP_NOTIFY_WARNING) - - // Start cooldown for next wave - set_combat_state(NPC_COMBAT_BOARDING_COOLDOWN) - var/cooldown_end = world.time + NPC_BOARDING_WAVE_COOLDOWN - set_blackboard_key(BB_NPC_BOARDING_COOLDOWN_END, cooldown_end) - set_blackboard_key(BB_NPC_BOARDING_WAVE_START_TIME, null) - - // Schedule next wave - boarding_timers += addtimer(CALLBACK(src, PROC_REF(end_wave_cooldown), next_wave), NPC_BOARDING_WAVE_COOLDOWN, TIMER_STOPPABLE) + else + end_yellow_raid() /** * Check if any boarders have fallen into space and clean them up. @@ -1478,3 +1434,38 @@ spaced.death() wave_boarders -= spaced UnregisterSignal(spaced, COMSIG_LIVING_DEATH) + +/// Snapshot the target band and connected crew exactly once, including combat-only raids. +/datum/ai_controller/npc_ship/proc/capture_boarding_encounter(obj/structure/overmap/ship/target) + if(boarding_context || QDELETED(target)) + return + boarding_context = new(target, get_raid_zone(target)?.zone_type || ZONE_GREEN, "ordinary") + boarding_budget = max(1, count_player_crew(target)) + +/datum/ai_controller/npc_ship/proc/reserve_boarders(obj/structure/overmap/ship/target, requested) + capture_boarding_encounter(target) + var/reserved = min(max(0, requested), max(0, boarding_budget - boarding_committed)) + boarding_committed += reserved + return reserved + +/// Timer callbacks must still belong to this encounter after docking or target changes. +/datum/ai_controller/npc_ship/proc/deploy_combat_boarder(turf/spot, obj/structure/overmap/ship/target, mob_type, datum/npc_spawn_context/encounter) + if(get_target() != target || boarding_context != encounter) + return + boarding_pending-- + return create_boarding_pod(spot, target, get_ship(), mob_type, encounter, TRUE) + +/datum/ai_controller/npc_ship/proc/deploy_combat_boss(obj/structure/overmap/ship/target) + if(!is_red_zone_raid() || boarding_boss_sent || boarding_pending || boarding_committed < boarding_budget) + return FALSE + var/obj/structure/overmap/ship/npc/pirate/ship = get_ship() + var/list/spots = get_target_spawn_turfs(target) + if(!istype(ship) || !ship.boss_type || !length(spots)) + return FALSE + var/mob/living/boss = create_boss_boarding_pod(pick(spots), target, ship, ship.boss_type) + if(!boss) + return FALSE + set_blackboard_key(BB_NPC_BOARDING_BOSS, boss) + RegisterSignal(boss, COMSIG_LIVING_DEATH, PROC_REF(on_boss_death)) + npc_metric_boss_deployed(src, boss) + return TRUE diff --git a/voidcrew/modules/unit_tests/voidcrew_bounty_lair_mafia.dm b/voidcrew/modules/unit_tests/voidcrew_bounty_lair_mafia.dm index eb6f6ae32f7..44a82a0d616 100644 --- a/voidcrew/modules/unit_tests/voidcrew_bounty_lair_mafia.dm +++ b/voidcrew/modules/unit_tests/voidcrew_bounty_lair_mafia.dm @@ -63,6 +63,7 @@ /datum/unit_test/voidcrew_bounty_lair_mafia/rockets/Run() var/mob/living/basic/bounty_lair_boss/mafia_mech/mech = allocate(/mob/living/basic/bounty_lair_boss/mafia_mech, spot(0, 2)) + mech.finalize_npc_zone(allocate(/datum/npc_spawn_context, src, 3, "boss")) var/mob/living/carbon/human/consistent/hunter = hunter_at(spot(4, 2)) TEST_ASSERT(!ispath(mech.mech_rocket_type, /obj/projectile/bullet/rocket), "The mech fires tg's rocket, which calls explosion()") TEST_ASSERT(ispath(mech.mech_rocket_type, /obj/projectile/bullet/bounty_mafia_rocket), "The mech doesn't fire the club's rocket") @@ -86,13 +87,13 @@ TEST_ASSERT(!istype(rocket, /obj/projectile/bullet/rocket), "The launch fired tg's rocket") TEST_ASSERT_EQUAL(rocket.rocket_target, get_turf(hunter), "The rocket isn't aimed at the marker") - // It lands on the marker: 70 brute and a knockdown (BOUNTY_MECH_ROCKET_DAMAGE), once a volley + // The projectile and its scripted detonation share one red boss factor. var/turf/marker_turf = get_turf(hunter) var/list/volley = rocket.rocket_volley var/list/hit = rocket.rocket_detonate(marker_turf) TEST_ASSERT(hunter in hit, "The rocket missed the hunter standing on the marker") var/first = hunter.getBruteLoss() - TEST_ASSERT_EQUAL(first, 70, "The rocket didn't do 70 brute to an unarmoured hunter") // BOUNTY_MECH_ROCKET_DAMAGE + TEST_ASSERT_EQUAL(first, 84, "The rocket lost or doubled its red boss damage factor") // BOUNTY_MECH_ROCKET_DAMAGE * 1.2 TEST_ASSERT(hunter.IsKnockdown(), "The rocket didn't knock the hunter down") TEST_ASSERT(QDELETED(rocket), "The rocket outlived its burst") var/obj/projectile/bullet/bounty_mafia_rocket/second = new(spot(1, 2)) @@ -285,8 +286,9 @@ /datum/unit_test/voidcrew_bounty_lair_mafia/posse/Run() var/mob/living/basic/bounty_lair_boss/mafia_mech/mech = allocate(/mob/living/basic/bounty_lair_boss/mafia_mech, spot(2, 2)) + mech.finalize_npc_zone(allocate(/datum/npc_spawn_context, src, 3, "boss")) TEST_ASSERT(!ispath(mech.type, /mob/living/basic/boss), "The mech is a megafauna boss") - TEST_ASSERT_EQUAL(mech.maxHealth, 350, "The mech doesn't start at its one-hunter health") // BOUNTY_MECH_HEALTH_1 + TEST_ASSERT_EQUAL(mech.maxHealth, 455, "The mech doesn't start at its one-hunter health") // BOUNTY_MECH_HEALTH_1 TEST_ASSERT_EQUAL(mech.damage_coeff[BRUTE], 0.6, "The mech's brute armour is wrong") // BOUNTY_MECH_BRUTE_MOD TEST_ASSERT_EQUAL(mech.damage_coeff[BURN], 0.8, "The mech's burn armour is wrong") // BOUNTY_MECH_BURN_MOD TEST_ASSERT_EQUAL(mech.damage_coeff[STAMINA], 0, "The mech takes stamina damage") @@ -296,19 +298,19 @@ for(var/i in 1 to 5) hunters += hunter_at(spot(i - 1, 0)) TEST_ASSERT(mech.mech_engage(hunters[1]), "The first hunter didn't join the posse") - TEST_ASSERT_EQUAL(mech.maxHealth, 350, "One hunter changed the mech's health") + TEST_ASSERT_EQUAL(mech.maxHealth, 455, "One hunter changed the mech's health") mech.adjust_health(100) - TEST_ASSERT_EQUAL(mech.health, 250, "The mech didn't take the damage") + TEST_ASSERT_EQUAL(mech.health, 355, "The mech didn't take the damage") TEST_ASSERT(mech.mech_engage(hunters[2]), "The second hunter didn't join the posse") - TEST_ASSERT_EQUAL(mech.maxHealth, 700, "Two hunters didn't raise the mech to 700") // BOUNTY_MECH_HEALTH_2 - TEST_ASSERT_EQUAL(mech.health, 600, "The mech's damage didn't carry over when its health rose") + TEST_ASSERT_EQUAL(mech.maxHealth, 910, "Two hunters lost the selected zone factor") // BOUNTY_MECH_HEALTH_2 + TEST_ASSERT_EQUAL(mech.health, 810, "The mech's damage didn't carry over when its health rose") TEST_ASSERT(!mech.mech_engage(hunters[2]), "The same hunter joined twice") mech.mech_engage(hunters[3]) - TEST_ASSERT_EQUAL(mech.maxHealth, 1050, "Three hunters didn't raise the mech to 1050") // BOUNTY_MECH_HEALTH_3 + TEST_ASSERT_EQUAL(mech.maxHealth, 1365, "Three hunters lost the selected zone factor") // BOUNTY_MECH_HEALTH_3 mech.mech_engage(hunters[4]) - TEST_ASSERT_EQUAL(mech.maxHealth, 1400, "Four hunters didn't raise the mech to 1400") // BOUNTY_MECH_HEALTH_4 + TEST_ASSERT_EQUAL(mech.maxHealth, 1820, "Four hunters lost the selected zone factor") // BOUNTY_MECH_HEALTH_4 mech.mech_engage(hunters[5]) - TEST_ASSERT_EQUAL(mech.maxHealth, 1400, "A fifth hunter raised the mech past its 4+ health") + TEST_ASSERT_EQUAL(mech.maxHealth, 1820, "A fifth hunter raised the mech past its 4+ health") // ===== THE EMP STALL ===== @@ -419,6 +421,7 @@ posting.record = new /datum/bounty_record posting.record.name = "Viktor Sokolov" var/mob/living/basic/bounty_lair_boss/mafia_mech/mech = allocate(/mob/living/basic/bounty_lair_boss/mafia_mech, spot(2, 2)) + mech.finalize_npc_zone(allocate(/datum/npc_spawn_context, src, 3, "boss")) mech.posting_ref = WEAKREF(posting) var/mob/living/carbon/human/consistent/hunter = hunter_at(spot(0, 2)) var/turf/where = get_turf(mech) @@ -437,7 +440,7 @@ TEST_ASSERT(don in ejected, "The mech didn't announce the don") TEST_ASSERT_EQUAL(don.posting_ref?.resolve(), posting, "The don didn't keep the mech's posting") TEST_ASSERT_EQUAL(don.name, "Viktor Sokolov", "The don isn't named for his posting") - TEST_ASSERT_EQUAL(don.maxHealth, 250, "The don's health is wrong") // BOUNTY_DON_HEALTH + TEST_ASSERT_EQUAL(don.maxHealth, 325, "The don lost the mech's selected boss profile") // BOUNTY_DON_HEALTH TEST_ASSERT_EQUAL(don.don_busy, "stagger", "The don isn't dazed as he climbs out") TEST_ASSERT_EQUAL(don.don_wreck_ref?.resolve(), wreck, "The don doesn't know his wreck") @@ -503,7 +506,7 @@ TEST_ASSERT(!ispath(entry, /mob/living/basic/trooper/russian/mafia/lieutenant), "[entry] is a lieutenant, which only the gate has") TEST_ASSERT(!ispath(entry, /mob/living/basic/boss), "[entry] is a megafauna") for(var/list/count_range in list(probe.count_green, probe.count_yellow, probe.count_red)) - TEST_ASSERT(count_range[1] >= 3 && count_range[2] <= 5, "A mafia marker spawns outside 3-5 goons") + TEST_ASSERT(count_range[1] == 1 && count_range[2] == 2, "A mafia marker spawns outside 1-2 goons") // P11's rooms get their own crews var/list/casino = bounty_mafia_room_crew("/area/ruin/space/has_grav/powered/mafia_club/casino") @@ -516,7 +519,7 @@ TEST_ASSERT_NULL(bounty_mafia_room_crew("/area/ruin/space/has_grav/powered/mafia_club/garage"), "The arena gets goons") TEST_ASSERT_NULL(bounty_mafia_room_crew(/area/misc/testroom), "A room outside the club gets a club crew") - // Anywhere else, the zone table: 3-5 goons, all on its own floor + // Anywhere else, the zone table: 1-2 goons, all on its own floor probe.forceMove(spot(2, 2)) probe.do_spawn(2) // ZONE_YELLOW var/count = 0 @@ -526,7 +529,7 @@ count++ TEST_ASSERT(!istype(goon, /mob/living/basic/trooper/russian/mafia/lieutenant), "The marker spawned a lieutenant") TEST_ASSERT_EQUAL(get_area(goon), room, "A goon spawned outside the marker's room") - TEST_ASSERT(count >= 3 && count <= 5, "The marker spawned [count] goons, not 3-5") + TEST_ASSERT(count >= 1 && count <= 2, "The marker spawned [count] goons, not 1-2") qdel(probe) // ===== GOONS: THE SHOUT, THE DOORWAY, THE DOWNED, NO GUNS ===== @@ -674,6 +677,7 @@ posting.board_gps_tag = "WANTED-[posting.record.id]" GLOB.criminal_bounties += posting fake_lair = allocate(/obj/structure/overmap/space_ruin/bounty_lair) + fake_lair.npc_spawn_context = allocate(/datum/npc_spawn_context, src, 2, "boss") fake_lair.lair_bind_posting(posting) var/datum/map_footprint/footprint = allocate(/datum/map_footprint) footprint.z_value = origin.z @@ -682,6 +686,8 @@ fake_lair.loaded = TRUE boss_mark = new(locate(origin.x + 2, origin.y + 2, origin.z)) boss_mark.boss_type = /mob/living/basic/bounty_lair_boss/mafia_mech + var/obj/effect/landmark/bounty_lair_gatekeeper/keeper_mark = allocate(/obj/effect/landmark/bounty_lair_gatekeeper, origin) + keeper_mark.gatekeeper_type = /mob/living/basic/npc_zone_test // The lair spawns the mech and takes it on SEND_SIGNAL(fake_lair, "voidcrew_planet_loaded", TRUE) // COMSIG_VOIDCREW_PLANET_LOADED @@ -692,6 +698,13 @@ var/datum/weakref/mech_ref = fake_lair.lair_bosses[1] var/mob/living/basic/bounty_lair_boss/mafia_mech/mech = mech_ref.resolve() TEST_ASSERT(istype(mech), "The lair's boss isn't the don's mech") + TEST_ASSERT(abs(mech.maxHealth - 350 * 1.15) < 0.001, "The lair route did not finalize its boss") + TEST_ASSERT_EQUAL(length(fake_lair.lair_gatekeepers), 1, "Lair gatekeeper fixture did not spawn") + var/datum/weakref/keeper_ref = fake_lair.lair_gatekeepers[1] + var/mob/living/keeper = keeper_ref.resolve() + allocated += keeper + TEST_ASSERT_EQUAL(keeper.npc_zone_role, "boss", "Lair gatekeeper lost its explicit boss role") + TEST_ASSERT(abs(keeper.maxHealth - 115) < 0.001, "Lair gatekeeper used the ordinary profile") TEST_ASSERT_EQUAL(mech.posting_ref?.resolve(), posting, "The mech isn't wanted on the lair's bounty") // The mech breaks: the lair takes the don on as he climbs out, and the fight goes on past its grace diff --git a/voidcrew/modules/unit_tests/voidcrew_derelict_themes.dm b/voidcrew/modules/unit_tests/voidcrew_derelict_themes.dm index 6e5ee77512b..32be804e6ee 100644 --- a/voidcrew/modules/unit_tests/voidcrew_derelict_themes.dm +++ b/voidcrew/modules/unit_tests/voidcrew_derelict_themes.dm @@ -96,9 +96,10 @@ if(generator) // DERELICT_GENERATOR_CLEAR_RADIUS TEST_ASSERT(get_dist(hostile, generator) > 4, "[theme_id]: [hostile] starts within 4 of the generator") - // DERELICT_BOSS_HEALTH_MULT_* 1.5 / 2, DERELICT_HEALTH_MULT_* 1.5 / 1.8 - var/multiplier = i == 1 ? (red ? 2 : 1.5) : (red ? 1.8 : 1.5) - TEST_ASSERT_EQUAL(hostile.maxHealth, round(initial(hostile.maxHealth) * multiplier), "[theme_id]: [hostile]'s health was not scaled by [multiplier]") + // Named boss types retain their boss role even in the regular roster. + var/is_boss = i == 1 || npc_zone_boss_type(hostile.type) + var/multiplier = is_boss ? (red ? 1.3 : 1.15) : (red ? 1.8 : 1.35) + TEST_ASSERT(abs(hostile.maxHealth - hostile.npc_zone_original_max_health * multiplier) < 0.001, "[theme_id]: [hostile]'s health was not scaled by [multiplier]") /// Dressing stays under DERELICT_MAX_DRESSING (160); lights break at the theme's rate, give or take one fixture /datum/unit_test/voidcrew_derelict_theme/proc/check_dressing(obj/structure/overmap/dynamic/player_outpost/derelict/site, placed, dressing_before, list/lights_before) diff --git a/voidcrew/modules/unit_tests/voidcrew_npc_boarding_docking.dm b/voidcrew/modules/unit_tests/voidcrew_npc_boarding_docking.dm index 3edb5eb579b..5a4c5aeeb76 100644 --- a/voidcrew/modules/unit_tests/voidcrew_npc_boarding_docking.dm +++ b/voidcrew/modules/unit_tests/voidcrew_npc_boarding_docking.dm @@ -3,6 +3,129 @@ /datum/ai_controller/npc_ship/boarding_docking_test ai_movement = /datum/ai_movement/basic_avoidance +/// Deterministic band and connected crew snapshot; the production accounting stays intact. +/datum/ai_controller/npc_ship/boarding_docking_test/profile + var/datum/overmap_zone/test_zone + var/test_crew = 3 + var/turf/test_floor + +/datum/ai_controller/npc_ship/boarding_docking_test/profile/get_raid_zone(obj/structure/overmap/ship/target) + return test_zone + +/datum/ai_controller/npc_ship/boarding_docking_test/profile/count_player_crew(obj/structure/overmap/ship/target) + return test_crew + +/datum/ai_controller/npc_ship/boarding_docking_test/profile/get_target_spawn_turfs(obj/structure/overmap/ship/target) + return test_floor ? list(test_floor) : list() + +/datum/unit_test/voidcrew_npc_boarding_budget/Run() + var/obj/structure/overmap/ship/npc/pirate/pirate = allocate(/obj/structure/overmap/ship/npc/pirate) + var/obj/structure/overmap/ship/target = allocate(/obj/structure/overmap/ship) + var/datum/ai_controller/npc_ship/boarding_docking_test/profile/controller = allocate(/datum/ai_controller/npc_ship/boarding_docking_test/profile, pirate) + for(var/band in list(2, 3)) + for(var/timed_out in list(FALSE, TRUE)) + target.state = "flying" + controller.test_zone = allocate(/datum/overmap_zone, band) + controller.test_crew = 3 + controller.set_target(target) + TEST_ASSERT_EQUAL(controller.boarding_budget, 3, "The raid did not capture one boarder per connected crew member") + TEST_ASSERT_EQUAL(controller.get_boarding_wave_count(), 1, "A raid has more than one ordinary wave") + controller.test_crew = 8 + controller.test_zone = allocate(/datum/overmap_zone, band == 2 ? 3 : 2) + controller.capture_boarding_encounter(target) + TEST_ASSERT_EQUAL(controller.boarding_context.zone_type, band, "Movement changed the captured band") + TEST_ASSERT_EQUAL(controller.boarding_budget, 3, "Late arrivals changed the initial boarding budget") + TEST_ASSERT_EQUAL(controller.reserve_boarders(target, 2), 2, "Combat pods could not reserve part of the wave") + controller.cleanup_boarding_signals() + TEST_ASSERT_EQUAL(controller.reserve_boarders(target, 10), 1, "Escalation replenished the ordinary budget") + TEST_ASSERT_EQUAL(controller.reserve_boarders(target, 1), 0, "A later volley exceeded the engagement budget") + controller.set_combat_state("boarding") + controller.blackboard["npc_boarding_wave_boarders"] = list() + if(timed_out) + controller.handle_wave_timeout() + else + controller.check_wave_complete() + TEST_ASSERT_EQUAL(controller.get_combat_state(), band == 3 ? "boarding_cooldown" : "idle", "Clearance/timeout took the wrong band transition") + TEST_ASSERT_EQUAL(isnull(controller.get_target()), band != 3, "Yellow did not disengage or red lost its target") + controller.clear_target() + controller.test_crew = 0 + controller.set_target(target) + TEST_ASSERT_EQUAL(controller.boarding_budget, 1, "An empty crew snapshot did not retain the minimum boarder") + controller.clear_target() + // A disconnected human with a mind is not connected crew. + var/mob/living/carbon/human/consistent/disconnected = allocate(/mob/living/carbon/human/consistent, run_loc_floor_bottom_left) + disconnected.mind_initialize() + TEST_ASSERT_EQUAL(controller.count_living_crew(target), -1, "An unreadable hull was treated as a crew wipe") + var/obj/docking_port/mobile/voidcrew/port = allocate(/obj/docking_port/mobile/voidcrew, run_loc_floor_bottom_left) + port.shuttle_areas = list((get_area(disconnected)) = TRUE) + target.shuttle = port + var/already_listed = (disconnected in GLOB.player_list) + GLOB.player_list |= disconnected + var/living_count = controller.count_living_crew(target) + if(!already_listed) + GLOB.player_list -= disconnected + target.shuttle = null + port.shuttle_areas = list() + qdel(port, force = TRUE) + TEST_ASSERT_EQUAL(living_count, 0, "A disconnected body inflated the connected crew count") + +/datum/npc_combat_interface/boarding_budget_test + var/turf/test_floor + +/datum/npc_combat_interface/boarding_budget_test/get_random_target_turf(obj/structure/overmap/ship/target_ship) + return test_floor + +/datum/unit_test/voidcrew_npc_boarding_volley_budget/Run() + var/obj/structure/overmap/ship/npc/pirate/pirate = allocate(/obj/structure/overmap/ship/npc/pirate) + pirate.boss_type = /mob/living/basic/trooper/pirate/faction/boss/silverscale + pirate.boarding_pod_mob_types = list(/mob/living/basic/npc_zone_test) + var/obj/structure/overmap/ship/target = allocate(/obj/structure/overmap/ship) + var/datum/ai_controller/npc_ship/boarding_docking_test/profile/controller = allocate(/datum/ai_controller/npc_ship/boarding_docking_test/profile, pirate) + var/datum/npc_combat_interface/boarding_budget_test/combat = allocate(/datum/npc_combat_interface/boarding_budget_test) + combat.owner_ship = pirate + combat.test_floor = run_loc_floor_bottom_left + controller.test_floor = combat.test_floor + for(var/band in list(2, 3)) + target.state = "flying" + pirate.state = "flying" + controller.test_zone = allocate(/datum/overmap_zone, band) + controller.set_target(target) + TEST_ASSERT(combat.fire_boarding_pods(target, 5, list(/mob/living/basic/npc_zone_test)), "Combat volley fixture did not launch") + TEST_ASSERT_EQUAL(controller.boarding_pending, 3, "Combat volley exceeded the captured crew size") + TEST_ASSERT(!combat.fire_boarding_pods(target, 5), "An overlapping volley exceeded the reserved budget") + controller.escalate_to_full_combat(target) + TEST_ASSERT_EQUAL(controller.boarding_pending, 0, "Escalation retained cancelled reservations") + TEST_ASSERT_EQUAL(controller.boarding_committed, 0, "Escalation spent pods it cancelled") + TEST_ASSERT(combat.fire_boarding_pods(target, 5, list(/mob/living/basic/npc_zone_test)), "Cancelled pods did not return to the same engagement budget") + // Execute the actual callbacks directly, after cancelling their timers. + for(var/timer_id in controller.boarding_timers) + deltimer(timer_id) + controller.boarding_timers.Cut() + for(var/i in 1 to 3) + var/mob/living/boarder = controller.deploy_combat_boarder(combat.test_floor, target, /mob/living/basic/npc_zone_test, controller.boarding_context) + TEST_ASSERT_NOTNULL(boarder, "A reserved combat pod lost its encounter") + TEST_ASSERT_EQUAL(boarder.npc_spawn_context.zone_type, band, "Combat pod used a different band") + TEST_ASSERT_EQUAL(controller.boarding_pending, 0, "Deployed pods retained reservations") + TEST_ASSERT_EQUAL(combat.fire_boarding_pods(target, 5), band == 3, "Exhausting the ordinary budget took the wrong boss transition") + TEST_ASSERT(!combat.fire_boarding_pods(target, 5), "A later combat volley replenished the budget or boss") + target.state = "idle" + for(var/obj/effect/pod_landingzone/boarding/landing in combat.test_floor) + landing.cancel_if_target_docked() + controller.clear_target() + // The scripted route spends the same budget and cannot launch another wave. + target.state = "flying" + controller.set_target(target) + controller.set_combat_state("boarding") + TEST_ASSERT(controller.launch_boarding_wave(1), "The scripted boarding fixture did not launch") + TEST_ASSERT_EQUAL(length(controller.blackboard["npc_boarding_wave_boarders"]), 3, "Scripted raid did not launch exactly one boarder per initial crew") + TEST_ASSERT_EQUAL(controller.boarding_committed, 3, "Scripted raid escaped shared engagement accounting") + TEST_ASSERT(!controller.launch_boarding_wave(2), "A second ordinary wave was allowed") + TEST_ASSERT(!combat.fire_boarding_pods(target, 5, list(/mob/living/basic/npc_zone_test)) || band == 3, "Combat replenished a scripted raid's ordinary budget") + target.state = "idle" + for(var/obj/effect/pod_landingzone/boarding/landing in combat.test_floor) + landing.cancel_if_target_docked() + controller.clear_target() + /datum/unit_test/voidcrew_npc_boarding_docking /datum/unit_test/voidcrew_npc_boarding_docking/Run() diff --git a/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm index 49214d61cfd..1fcbdab9446 100644 --- a/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm +++ b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm @@ -365,3 +365,159 @@ body.finalize_npc_zone() TEST_ASSERT_EQUAL(body.npc_spawn_context.zone_type, band, "Moving a mapped hostile retiered it") qdel(body) + +/// Hull crews finalize after their key/setup, and nullspace pods use the captured raid band. +/datum/unit_test/voidcrew_npc_zone_ship_routes/Run() + var/turf/location = run_loc_floor_bottom_left + var/obj/structure/overmap/ship/npc/pirate/ship = allocate(/obj/structure/overmap/ship/npc/pirate) + var/obj/structure/overmap/ship/target = allocate(/obj/structure/overmap/ship) + var/obj/docking_port/mobile/voidcrew/port = allocate(/obj/docking_port/mobile/voidcrew, location) + port.shuttle_areas = list((get_area(location)) = TRUE) + ship.shuttle = port + ship.pool_zone_type = 2 + ship.crew_min = 2 + ship.crew_max = 2 + ship.crew_types = list(/mob/living/basic/npc_zone_test) + ship.captain_type = /mob/living/basic/npc_zone_test + ship.spawn_crew() + TEST_ASSERT_EQUAL(length(ship.tracked_crew), 2, "Hull crew fixture did not spawn its roster") + for(var/mob/living/crew as anything in ship.tracked_crew) + var/is_captain = locate(/obj/item/ship_key) in crew + TEST_ASSERT_EQUAL(crew.npc_zone_role, is_captain ? "boss" : "ordinary", "Hull captain/crew role was lost") + TEST_ASSERT(abs(crew.maxHealth - (is_captain ? 115 : 135)) < 0.001, "Hull crew retained the flat pirate multiplier") + qdel(crew) + ship.tracked_crew.Cut() + ship.shuttle = null + port.shuttle_areas = list() + qdel(port, force = TRUE) + var/datum/ai_controller/npc_ship/boarding_docking_test/profile/controller = allocate(/datum/ai_controller/npc_ship/boarding_docking_test/profile, ship) + controller.test_floor = location + ship.boss_type = /mob/living/basic/trooper/pirate/faction/boss/silverscale + for(var/band in list(2, 3)) + ship.state = "flying" + target.state = "flying" + controller.test_zone = allocate(/datum/overmap_zone, band) + controller.set_target(target) + var/mob/living/boarder = create_boarding_pod(location, target, ship, /mob/living/basic/npc_zone_test) + TEST_ASSERT_NOTNULL(boarder, "Ordinary pod route did not create a boarder") + TEST_ASSERT_EQUAL(boarder.npc_spawn_context.zone_type, band, "A nullspace pod lost the target band") + TEST_ASSERT(abs(boarder.maxHealth - (band == 2 ? 135 : 180)) < 0.001, "Ordinary pod used the old flat multiplier") + var/mob/living/boss = create_boss_boarding_pod(location, target, ship, ship.boss_type) + if(band == 3) + TEST_ASSERT_NOTNULL(boss, "Red pod route omitted its boss") + TEST_ASSERT_EQUAL(boss.npc_zone_role, "boss", "Boss pod lost its explicit role") + TEST_ASSERT(abs(boss.maxHealth - boss.npc_zone_original_max_health * 1.3) < 0.001, "Boss initialization health was scaled incorrectly") + TEST_ASSERT_NULL(create_boss_boarding_pod(location, target, ship, ship.boss_type), "A second boss escaped the engagement budget") + else + TEST_ASSERT_NULL(boss, "Yellow deployed a boss") + target.state = "idle" + for(var/obj/effect/pod_landingzone/boarding/landing in location) + landing.cancel_if_target_docked() + controller.clear_target() + +/datum/unit_test/voidcrew_npc_zone_bounty_routes/Run() + var/turf/location = run_loc_floor_bottom_left + var/datum/bounty_record/record = allocate(/datum/bounty_record) + record.tier = 2 // BOUNTY_TIER_WANTED + record.style = "brawler" + var/mob/living/basic/bounty_criminal/criminal = spawn_bounty_criminal(record, location, null) + allocated += criminal + var/raw_health = criminal.body_tier_health() + criminal.npc_spawn_context.on_zone_resolved(3) + TEST_ASSERT(abs(criminal.maxHealth - raw_health * 1.8) < 0.001, "Criminal route finalized before body_setup") + criminal.setBruteLoss(criminal.maxHealth / 2) + var/mob/living/basic/bounty_criminal/decoy/decoy = allocate(/mob/living/basic/bounty_criminal/decoy, location) + decoy.body_match(criminal) + decoy.body_match(criminal) + TEST_ASSERT_EQUAL(decoy.npc_spawn_context.source_id, criminal.npc_spawn_context.source_id, "Decoy lost the fugitive source") + TEST_ASSERT_EQUAL(decoy.maxHealth, criminal.maxHealth, "Repeated body_match multiplied copied health") + TEST_ASSERT(abs(decoy.health / decoy.maxHealth - criminal.health / criminal.maxHealth) < 0.001, "Decoy copy changed health fraction") + var/mob/living/carbon/human/consistent/admin = allocate(/mob/living/carbon/human/consistent, run_loc_floor_top_right) + var/datum/bounty_admin_panel/unit_test/panel = allocate(/datum/bounty_admin_panel/unit_test, admin) + var/mob/living/basic/bounty_criminal/decoy/admin_decoy = panel.admin_spawn_decoy(admin, criminal) + TEST_ASSERT_NOTNULL(admin_decoy, "Admin decoy fixture failed") + allocated += admin_decoy + TEST_ASSERT_EQUAL(admin_decoy.maxHealth, criminal.maxHealth, "Admin decoy route stacked the copied pool") + var/datum/bounty_real_weapon/knife = bounty_real_weapon(/obj/item/knife/combat) + knife.apply_melee(criminal) + knife.apply_melee(criminal) + TEST_ASSERT(abs(criminal.melee_damage_upper - knife.force_high * 1.35) < 0.001, "Bounty weapon replacement stacked or lost the profile") + var/mob/living/basic/bounty_criminal/kingpin/kingpin = bounty_kingpin_setup(location, list(), null) + allocated += kingpin + kingpin.npc_spawn_context.on_zone_resolved(2) + TEST_ASSERT_EQUAL(kingpin.npc_zone_role, "boss", "The neutral lounge kingpin missed its explicit boss profile") + var/mob/living/basic/bounty_kingpin_goon/goon = kingpin.kingpin_crew.spawn_goon(run_loc_floor_top_right) + allocated += goon + TEST_ASSERT_EQUAL(goon.npc_spawn_context.zone_type, 2, "Replacement goon lost its kingpin's site band") + TEST_ASSERT_EQUAL(goon.npc_zone_role, "ordinary", "Goon inherited the kingpin's boss role") + TEST_ASSERT(abs(goon.maxHealth - goon.npc_zone_original_max_health * 1.35) < 0.001, "Replacement goon did not finalize") + kingpin.exempt_npc_zone() + var/mob/living/basic/bounty_kingpin_goon/owned_goon = kingpin.kingpin_crew.spawn_goon(location) + allocated += owned_goon + TEST_ASSERT(!owned_goon.npc_zone_applied && owned_goon.npc_zone_exempt, "Player ownership did not propagate to goons") + +/datum/unit_test/voidcrew_npc_zone_bounty_damage/Run() + var/turf/location = run_loc_floor_bottom_left + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, 3, "boss") + var/mob/living/basic/bounty_criminal/boss/boss = spawn_npc_in_zone(/mob/living/basic/bounty_criminal/boss/juggernaut, location, context) + allocated += boss + var/mob/living/basic/npc_zone_test/victim = allocate(/mob/living/basic/npc_zone_test, run_loc_floor_top_right) + boss.boss_hit(victim, 10) + TEST_ASSERT_EQUAL(victim.getBruteLoss(), 12, "Raw boss ability escaped scaling") + boss.boss_hit(victim, 12, already_scaled = TRUE) + TEST_ASSERT_EQUAL(victim.getBruteLoss(), 24, "Scaled melee input multiplied twice") + var/list/table = boss.boss_health_table() + boss.boss_engaged = list("first" = TRUE, "second" = TRUE) + boss.boss_apply_posse_health(FALSE) + TEST_ASSERT(abs(boss.maxHealth - table[2] * 1.3) < 0.001, "Posse health lost the boss factor") + var/obj/effect/bounty_boss_explosive/explosive = allocate(/obj/effect/bounty_boss_explosive, location, boss) + var/obj/effect/bounty_boss_fire_pool/pool = allocate(/obj/effect/bounty_boss_fire_pool, location, list(location), 5 SECONDS, boss) + var/factor = boss.get_npc_zone_damage_factor() + qdel(boss) + TEST_ASSERT_EQUAL(explosive.damage_factor, factor, "Delayed explosive lost its creator's factor") + TEST_ASSERT_EQUAL(pool.damage_factor, factor, "Delayed fire lost its creator's factor") + victim.setMaxHealth(1000) + victim.updatehealth() + victim.mind_initialize() + victim.forceMove(location) + var/before_blast = victim.getBruteLoss() + var/raw_blast = explosive.damage + explosive.detonate() + TEST_ASSERT(abs(victim.getBruteLoss() - before_blast - raw_blast * factor) < 0.001, "Orphaned explosive fallback lost or doubled its captured factor") + var/before_fire = victim.getBruteLoss() + pool.scorch(10) + TEST_ASSERT(abs(victim.getBruteLoss() - before_fire - 10 * factor) < 0.001, "Orphaned fire pool lost its captured factor") + var/datum/status_effect/bounty_boss_burning/burning = victim.apply_status_effect(/datum/status_effect/bounty_boss_burning, factor) + // scorch already applied the refreshable effect. + burning = victim.has_status_effect(/datum/status_effect/bounty_boss_burning) + var/before = victim.getBruteLoss() + burning.tick(1) + TEST_ASSERT(abs(victim.getBruteLoss() - before - 3 * factor) < 0.001, "Lingering fire did not retain its numeric factor") // BOUNTY_BOSS_BURNING_DAMAGE + +/// Exercise the mafia override in a real club room, which bypasses base marker spawning. +/datum/unit_test/voidcrew_npc_zone_mafia_room + var/turf/room_floor + var/area/original_area + +/datum/unit_test/voidcrew_npc_zone_mafia_room/Destroy() + if(room_floor && original_area) + room_floor.change_area(get_area(room_floor), original_area) + return ..() + +/datum/unit_test/voidcrew_npc_zone_mafia_room/Run() + room_floor = run_loc_floor_bottom_left + original_area = get_area(room_floor) + var/area/ruin/space/has_grav/powered/mafia_club/casino/room = allocate(/area/ruin/space/has_grav/powered/mafia_club/casino) + room_floor.change_area(original_area, room) + var/obj/effect/zone_mobs/mafia/marker = allocate(/obj/effect/zone_mobs/mafia) + marker.forceMove(room_floor) + marker.do_spawn(3) + var/count = 0 + var/list/roster = bounty_mafia_room_crew(room.type) + for(var/mob/living/basic/trooper/russian/mafia/goon in room_floor) + allocated += goon + count++ + TEST_ASSERT(roster[goon.type], "Custom mafia marker escaped its existing room roster") + TEST_ASSERT_EQUAL(goon.npc_zone_role, "ordinary", "Custom mafia room output missed finalization") + TEST_ASSERT(abs(goon.maxHealth - goon.npc_zone_original_max_health * 1.8) < 0.001, "Custom mafia room output missed the selected factor") + TEST_ASSERT(count >= 1 && count <= 2, "Custom mafia marker escaped the 1-2 output budget") From c517b50da39d6b0e7ccf4c9f93bc158a6102d66a Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:59:58 -0700 Subject: [PATCH 034/105] NPC zone profile: missions, ambient NPCs, events and fauna replacements --- .../modules/ambient_npcs/planet_peddler.dm | 32 +- voidcrew/modules/ambient_npcs/recruit.dm | 1 + .../modules/cargo/shipping/_shuttle_loan.dm | 36 ++- .../dynamic_events/events/portal_storm.dm | 10 +- .../dynamic_events/events/vent_clog.dm | 8 +- .../missions/missions/big_game_hunt.dm | 6 +- .../modules/missions/missions/live_capture.dm | 5 +- .../modules/missions/missions/poacher_bust.dm | 6 +- .../modules/missions/objectives/combat.dm | 11 +- .../simple_animal/friendly/sea_crystal.dm | 49 +-- .../hostile/mining_mobs/polarbear.dm | 2 +- .../simple_animal/hostile/mining_mobs/wolf.dm | 4 +- .../hostile/wasteland/hermits.dm | 4 +- .../unit_tests/voidcrew_derelict_layout.dm | 32 ++ .../unit_tests/voidcrew_npc_zone_profiles.dm | 289 ++++++++++++++++++ 15 files changed, 432 insertions(+), 63 deletions(-) diff --git a/voidcrew/modules/ambient_npcs/planet_peddler.dm b/voidcrew/modules/ambient_npcs/planet_peddler.dm index 1411c751398..aa3db24c542 100644 --- a/voidcrew/modules/ambient_npcs/planet_peddler.dm +++ b/voidcrew/modules/ambient_npcs/planet_peddler.dm @@ -816,18 +816,7 @@ for(var/i in 1 to count) var/turf/where = ambient_free_turf_near(landing, 2) || landing var/raider_type = i == 3 ? /mob/living/basic/trooper/pirate/faction/grey/ranged : pick_weight(raiders - /mob/living/basic/trooper/pirate/faction/grey/ranged) - var/mob/living/raider = new raider_type(where) - // Not the planet's own: it comes for the caravan, and is kept near it - var/list/kept = list() - for(var/faction_token in raider.faction) - if(!findtext("[faction_token]", "planetary_")) - kept += faction_token - raider.faction = kept - raider.AddComponent(/datum/component/leash, doer, AMBIENT_AMBUSH_LEASH) - raider.AddElement(/datum/element/relay_attackers) - RegisterSignal(raider, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_pack_attacked)) - if(bait) - raider.ai_controller?.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, bait) + var/mob/living/raider = spawn_raider(raider_type, where, bait) var/datum/weakref/ref = WEAKREF(raider) pack += ref pack_refs += ref @@ -837,6 +826,25 @@ SSplanet_mobs.total_managed_mobs += count return count +/// Ready each ambusher against the caravan site before applying its profile. +/datum/ambient_activity/caravan_ambush/proc/spawn_raider(raider_type, turf/where, mob/living/bait) + var/datum/ambient_place/site/site = doer.place + var/datum/npc_spawn_context/context = new(site, site.band, source_turf = get_turf(doer)) + var/mob/living/raider = spawn_npc_in_zone(raider_type, where, context, FALSE) + // Not the planet's own: it comes for the caravan, and is kept near it. + var/list/kept = list() + for(var/faction_token in raider.faction) + if(!findtext("[faction_token]", "planetary_")) + kept += faction_token + raider.faction = kept + raider.AddComponent(/datum/component/leash, doer, AMBIENT_AMBUSH_LEASH) + raider.AddElement(/datum/element/relay_attackers) + RegisterSignal(raider, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_pack_attacked)) + if(bait) + raider.ai_controller?.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, bait) + context.finalize() + return raider + /// Someone hit the pack: their crew gets the helpers' price /datum/ambient_activity/caravan_ambush/proc/on_pack_attacked(datum/source, atom/attacker, attack_flags) SIGNAL_HANDLER diff --git a/voidcrew/modules/ambient_npcs/recruit.dm b/voidcrew/modules/ambient_npcs/recruit.dm index 89ce467fd36..e4b9a61554d 100644 --- a/voidcrew/modules/ambient_npcs/recruit.dm +++ b/voidcrew/modules/ambient_npcs/recruit.dm @@ -420,6 +420,7 @@ GLOBAL_LIST_EMPTY(ambient_ship_places) stray_state = STRAY_WILD REMOVE_TRAIT(src, TRAIT_SPACEWALK, STRAY_TRAIT) return FALSE + exempt_npc_zone() on_joined(ship) speak_context("accepted", leader, force = TRUE) log_game("AMBIENT: [src] agreed to join the [ship.name], asked by [key_name(leader)] at [AREACOORD(src)]") diff --git a/voidcrew/modules/cargo/shipping/_shuttle_loan.dm b/voidcrew/modules/cargo/shipping/_shuttle_loan.dm index 408ab0144ae..601a6fa0d20 100644 --- a/voidcrew/modules/cargo/shipping/_shuttle_loan.dm +++ b/voidcrew/modules/cargo/shipping/_shuttle_loan.dm @@ -194,12 +194,22 @@ GLOBAL_LIST_INIT(voidcrew_shuttle_loans, list( var/thanks_msg = "Your shuttle will return with our cargo. Payment has been transferred." /// Description for logging var/logging_desc = "generic loan" + /// One captured host band for all hostile cargo in this delivery. + var/datum/npc_spawn_context/npc_source /// Spawns items on the shuttle when it arrives /datum/voidcrew_shuttle_loan/proc/spawn_items(datum/voidcrew_cargo_shuttle/shuttle) SHOULD_CALL_PARENT(FALSE) CRASH("Unimplemented spawn_items() on [src.type].") +/// The cargo bay can be off-map; its host ship supplies the encounter band. +/datum/voidcrew_shuttle_loan/proc/spawn_hostile(mob_type, turf/location, datum/voidcrew_cargo_shuttle/shuttle) + if(!npc_source) + var/turf/source_turf = get_turf(shuttle.target_ship) + npc_source = new(shuttle, SSovermap_zones.get_zone_type_anywhere(source_turf) || ZONE_GREEN, source_turf = source_turf) + var/datum/npc_spawn_context/context = new(shuttle, npc_source.zone_type, "ordinary", source_turf = npc_source.source_turf) + return spawn_npc_in_zone(mob_type, location, context) + /// Department resupply - free supplies, no bonus /datum/voidcrew_shuttle_loan/department_resupply sender = "Nanotrasen Supply Division" @@ -431,13 +441,13 @@ GLOBAL_LIST_INIT(voidcrew_shuttle_loans, list( for(var/i in 1 to 2) if(!length(cargo_turfs)) break - new /mob/living/basic/trooper/syndicate/ranged/infiltrator(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/trooper/syndicate/ranged/infiltrator, pick_n_take(cargo_turfs), shuttle) // Chance for more if(prob(75) && length(cargo_turfs)) - new /mob/living/basic/trooper/syndicate/ranged/infiltrator(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/trooper/syndicate/ranged/infiltrator, pick_n_take(cargo_turfs), shuttle) if(prob(50) && length(cargo_turfs)) - new /mob/living/basic/trooper/syndicate/ranged/infiltrator(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/trooper/syndicate/ranged/infiltrator, pick_n_take(cargo_turfs), shuttle) /// Lots of bees - Toxic bees and beekeeping equipment /datum/voidcrew_shuttle_loan/lots_of_bees @@ -492,7 +502,7 @@ GLOBAL_LIST_INIT(voidcrew_shuttle_loans, list( for(var/i in 1 to 8) if(!length(cargo_turfs)) break - new /mob/living/basic/bee/toxin(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/bee/toxin, pick_n_take(cargo_turfs), shuttle) // Blood and bug guts for(var/i in 1 to 5) @@ -568,17 +578,17 @@ GLOBAL_LIST_INIT(voidcrew_shuttle_loans, list( // The Russians if(length(cargo_turfs)) - new /mob/living/basic/trooper/russian(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/trooper/russian, pick_n_take(cargo_turfs), shuttle) if(length(cargo_turfs)) - new /mob/living/basic/trooper/russian/ranged(pick_n_take(cargo_turfs)) // This one drops a mateba + spawn_hostile(/mob/living/basic/trooper/russian/ranged, pick_n_take(cargo_turfs), shuttle) // This one drops a mateba if(length(cargo_turfs)) - new /mob/living/basic/bear/russian(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/bear/russian, pick_n_take(cargo_turfs), shuttle) // Chance for more if(prob(75) && length(cargo_turfs)) - new /mob/living/basic/trooper/russian(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/trooper/russian, pick_n_take(cargo_turfs), shuttle) if(prob(50) && length(cargo_turfs)) - new /mob/living/basic/bear/russian(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/bear/russian, pick_n_take(cargo_turfs), shuttle) /// Spider gift - Giant spiders from the Spider Clan /datum/voidcrew_shuttle_loan/spider_gift @@ -601,13 +611,13 @@ GLOBAL_LIST_INIT(voidcrew_shuttle_loans, list( // THE SPIDERS if(length(cargo_turfs)) - new /mob/living/basic/spider/giant(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/spider/giant, pick_n_take(cargo_turfs), shuttle) if(length(cargo_turfs)) - new /mob/living/basic/spider/giant(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/spider/giant, pick_n_take(cargo_turfs), shuttle) if(length(cargo_turfs)) - new /mob/living/basic/spider/giant/nurse(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/spider/giant/nurse, pick_n_take(cargo_turfs), shuttle) if(prob(50) && length(cargo_turfs)) - new /mob/living/basic/spider/giant/hunter(pick_n_take(cargo_turfs)) + spawn_hostile(/mob/living/basic/spider/giant/hunter, pick_n_take(cargo_turfs), shuttle) // Victim remains if(length(cargo_turfs)) diff --git a/voidcrew/modules/dynamic_events/events/portal_storm.dm b/voidcrew/modules/dynamic_events/events/portal_storm.dm index 65a1ce934b2..98b221070a6 100644 --- a/voidcrew/modules/dynamic_events/events/portal_storm.dm +++ b/voidcrew/modules/dynamic_events/events/portal_storm.dm @@ -81,6 +81,9 @@ var/next_pulse = 0 /// Whether the final pulse may spend one spawn slot on a boss. var/boss_pending = FALSE + /// Pinned when the event is set up, before later pulses or ship movement. + var/npc_spawn_zone + var/turf/npc_source_turf /// Builds plane-correct portal appearances without resolving or retaining turfs. /datum/round_event/voidcrew/portal_storm/setup() @@ -88,6 +91,8 @@ kill() return + npc_source_turf = get_turf(target_ship) + npc_spawn_zone = SSovermap_zones.get_zone_type_anywhere(npc_source_turf) || ZONE_GREEN storm_appearances = list() for(var/offset in 0 to SSmapping.max_plane_offset) var/mutable_appearance/storm = mutable_appearance('icons/obj/machines/engine/energy_ball.dmi', "energy_ball_fast", FLY_LAYER) @@ -159,10 +164,12 @@ spawn_slots_remaining-- var/mob_type + var/role = "ordinary" if(boss_pending && pulses_remaining == 1) boss_pending = FALSE if(length(target_ship.get_event_crew()) >= 5) mob_type = pick_weight(boss_types) + role = "boss" else mob_type = pick_weight(hostile_types) if(!mob_type) @@ -171,7 +178,8 @@ var/turf/open/floor/spawn_turf = target_ship.get_random_open_ship_turf() if(!spawn_turf || !target_ship.is_aboard(spawn_turf)) continue - var/mob/living/new_hostile = new mob_type(spawn_turf) + var/datum/npc_spawn_context/context = new(target_ship, npc_spawn_zone, role, source_turf = npc_source_turf) + var/mob/living/new_hostile = spawn_npc_in_zone(mob_type, spawn_turf, context) if(QDELETED(new_hostile)) continue spawned_mobs++ diff --git a/voidcrew/modules/dynamic_events/events/vent_clog.dm b/voidcrew/modules/dynamic_events/events/vent_clog.dm index ec5cdb534c8..45d864416c4 100644 --- a/voidcrew/modules/dynamic_events/events/vent_clog.dm +++ b/voidcrew/modules/dynamic_events/events/vent_clog.dm @@ -74,12 +74,15 @@ var/list/filth_spawn_types = list() /// Whether this datum currently has signals registered on vent. var/signals_registered = FALSE + /// Capture the owning ship's band, including while docked or in transit. + var/datum/npc_spawn_context/npc_source /datum/round_event/voidcrew/vent_clog/setup() if(!target_valid()) finish_event() return + npc_source = new(target_ship, SSovermap_zones.get_zone_type_anywhere(get_turf(target_ship)) || ZONE_GREEN) vent = get_vent() if(QDELETED(vent) || !target_ship.is_aboard(vent)) finish_event() @@ -205,7 +208,10 @@ if(length(living_mobs) >= min(maximum_spawns, crew_scaled_cap)) return - var/mob/living/new_mob = new spawned_mob(vent_loc) + var/datum/npc_spawn_context/context = new(target_ship, npc_source.zone_type, source_turf = npc_source.source_turf) + var/mob/living/new_mob = spawn_npc_in_zone(spawned_mob, vent_loc, context) + if(QDELETED(new_mob)) + return living_mobs += WEAKREF(new_mob) vent.visible_message(span_warning("[new_mob] crawls out of [vent]!")) diff --git a/voidcrew/modules/missions/missions/big_game_hunt.dm b/voidcrew/modules/missions/missions/big_game_hunt.dm index 7420129e29c..a70c7292dc9 100644 --- a/voidcrew/modules/missions/missions/big_game_hunt.dm +++ b/voidcrew/modules/missions/missions/big_game_hunt.dm @@ -304,12 +304,13 @@ spawn_field_objects(get_nearby_open_turf(lure_turf, 4)) /datum/mission_objective/field/kill_named/big_game/spawn_field_objects(turf/spawn_turf) - var/mob/living/beast = new target_mob_type(spawn_turf) + var/mob/living/beast = spawn_field_npc(target_mob_type, spawn_turf, finalize = FALSE) beast.name = mission.objective_name beast.desc += " This one is old, scarred, and much too big. The guild wants it as a wall piece." if(health_override > beast.maxHealth) beast.maxHealth = health_override beast.health = health_override + beast.npc_spawn_context.finalize() target_mob = beast protect_field_mob(beast) RegisterSignal(beast, COMSIG_LIVING_DEATH, PROC_REF(on_target_death)) @@ -317,8 +318,9 @@ // The entourage: lesser fauna drawn in by the blood on the wind. Killing // them pays nothing - the contract is the name on the trophy. for(var/guard_type in guard_types) - var/mob/living/guard = new guard_type(get_nearby_open_turf(spawn_turf)) + var/mob/living/guard = spawn_field_npc(guard_type, get_nearby_open_turf(spawn_turf), finalize = FALSE) guard.desc += " It followed something much bigger here." + guard.npc_spawn_context.finalize() beast.visible_message(span_boldwarning("[beast] comes crashing in and goes straight for the lure!")) notify_crew("The lure's been taken. [mission.objective_name] is out in the open - good hunting.", type = SHIP_NOTIFY_WARNING, sound = 'voidcrew/sound/notify2.ogg') diff --git a/voidcrew/modules/missions/missions/live_capture.dm b/voidcrew/modules/missions/missions/live_capture.dm index 141767fa3cb..bf2505fc5a5 100644 --- a/voidcrew/modules/missions/missions/live_capture.dm +++ b/voidcrew/modules/missions/missions/live_capture.dm @@ -253,11 +253,12 @@ return TRUE /datum/mission_objective/field/capture_beast/spawn_field_objects(turf/spawn_turf) - var/mob/living/beast = new target_mob_type(spawn_turf) + var/mob/living/beast = spawn_field_npc(target_mob_type, spawn_turf, finalize = FALSE) beast.name = "marked [beast.name]" - beast.desc += " It's wearing a guild survey tag. This is the contracted specimen, and it's worth nothing dead." + beast.desc += " It's wearing a guild survey tag." target_mob = beast protect_field_mob(beast) + beast.npc_spawn_context.finalize() RegisterSignal(beast, COMSIG_LIVING_DEATH, PROC_REF(on_target_death)) mission.register_quest_atom(beast) notify_crew("Survey tag live - the marked specimen is on the surface ([mission.gps_tag]). Wear it down and crate it breathing.", type = SHIP_NOTIFY_WARNING, sound = 'voidcrew/sound/notify2.ogg') diff --git a/voidcrew/modules/missions/missions/poacher_bust.dm b/voidcrew/modules/missions/missions/poacher_bust.dm index d54cd04d0db..fa9552c3dff 100644 --- a/voidcrew/modules/missions/missions/poacher_bust.dm +++ b/voidcrew/modules/missions/missions/poacher_bust.dm @@ -323,13 +323,14 @@ // The squad, scattered around the campsite for(var/i in 1 to length(squad_types)) var/poacher_type = squad_types[i] - var/mob/living/simple_animal/poacher = new poacher_type(get_nearby_open_turf(camp_turf, 3)) + var/mob/living/simple_animal/poacher = spawn_field_npc(poacher_type, get_nearby_open_turf(camp_turf, 3), finalize = FALSE) if(i <= length(squad_names)) poacher.name = squad_names[i] poacher.desc += " The kit is professional: snare wire, skinning knives, and the brand of [mission.objective_name] burned into the stock." // Outfitted expedition: cold-weather gear keeps an ice-planet camp // from freezing to death before the crew arrives poacher.minbodytemp = 0 + poacher.npc_spawn_context.finalize() protect_field_mob(poacher) RegisterSignal(poacher, COMSIG_LIVING_DEATH, PROC_REF(on_poacher_death)) RegisterSignal(poacher, COMSIG_QDELETING, PROC_REF(on_poacher_removed)) @@ -353,7 +354,8 @@ var/obj/item/pet_carrier/cage = new(get_nearby_open_turf(camp_turf, 2)) cage.name = "live-catch cage" cage.desc = "A warden-banned live trap, still occupied. The lock is a simple latch." - var/mob/living/critter = new critter_type(cage) + var/datum/npc_spawn_context/context = new(mission?.target || src, mission?.target?.get_zone_type(), "exempt", source_turf = camp_turf) + var/mob/living/critter = spawn_npc_in_zone(critter_type, cage, context) cage.add_occupant(critter) cage.open = FALSE cage.locked = TRUE diff --git a/voidcrew/modules/missions/objectives/combat.dm b/voidcrew/modules/missions/objectives/combat.dm index dc9bded3307..377c9d2c0c3 100644 --- a/voidcrew/modules/missions/objectives/combat.dm +++ b/voidcrew/modules/missions/objectives/combat.dm @@ -100,6 +100,11 @@ /datum/mission_objective/field/proc/spawn_field_objects(turf/spawn_turf) return +/// Construct against the mission site before replacement rolls or caller setup. +/datum/mission_objective/field/proc/spawn_field_npc(mob_type, turf/spawn_turf, role = "auto", finalize = TRUE) + var/datum/npc_spawn_context/context = new(mission?.target || src, mission?.target?.get_zone_type(), role, source_turf = spawn_turf) + return spawn_npc_in_zone(mob_type, spawn_turf, context, finalize) + /** * Marks a mob the contract can't finish without, so the planet's fauna sweep * leaves it alone (SSplanet_mobs clears every unclaimed living mob off an empty @@ -166,18 +171,20 @@ target_mob = null /datum/mission_objective/field/kill_named/spawn_field_objects(turf/spawn_turf) - var/mob/living/target = new target_mob_type(spawn_turf) + var/mob/living/target = spawn_field_npc(target_mob_type, spawn_turf, finalize = FALSE) target.name = mission.objective_name target.desc += " They look like they're worth something dead." target_mob = target protect_field_mob(target) + target.npc_spawn_context.finalize() RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(on_target_death)) mission.register_quest_atom(target) // The entourage: untracked muscle around the target. Killing them pays // nothing - the contract is the name on the tag. for(var/guard_type in guard_types) - var/mob/living/guard = new guard_type(get_nearby_open_turf(spawn_turf)) + var/mob/living/guard = spawn_field_npc(guard_type, get_nearby_open_turf(spawn_turf), finalize = FALSE) guard.desc += " They're on somebody's payroll." + guard.npc_spawn_context.finalize() /** * The target died: drop the proof item, track it instead, and advance. diff --git a/voidcrew/modules/mob/living/simple_animal/friendly/sea_crystal.dm b/voidcrew/modules/mob/living/simple_animal/friendly/sea_crystal.dm index 3e14c208c7d..7d39700d394 100644 --- a/voidcrew/modules/mob/living/simple_animal/friendly/sea_crystal.dm +++ b/voidcrew/modules/mob/living/simple_animal/friendly/sea_crystal.dm @@ -61,6 +61,7 @@ /obj/structure/spawner/sea_crystal/Initialize(mapload) . = ..() + get_npc_spawn_context() for(var/turf/adjacent in RANGE_TURFS(1, src)) if(ismineralturf(adjacent)) var/turf/closed/mineral/mineral = adjacent @@ -135,28 +136,25 @@ return FALSE COOLDOWN_START(src, summon_cooldown, cooldown_time) + // Retain a separate construction context per landing before the source can die. + var/datum/npc_spawn_context/source_context = get_npc_spawn_context() + var/list/summon_contexts = list() + for(var/turf/summon_turf as anything in summon_turfs) + summon_contexts[summon_turf] = new /datum/npc_spawn_context(src, source_context.zone_type) crystal_power() - // Both legs are scheduled HERE, while the crystal is certainly alive, rather - // than the telegraph chaining the landing. addtimer() stack_traces when the - // callback's object is already qdeleting, and the whole point of the change - // below is that the landing has to survive the crystal dying mid-windup. - addtimer(CALLBACK(src, PROC_REF(summon_telegraph), summon_turfs, center), 2.5 SECONDS) - addtimer(CALLBACK(src, PROC_REF(summon_hivelords), summon_turfs), 3.5 SECONDS) + // Datum destruction cancels its own timers. Independent callbacks retain the + // committed landing contexts, with only a weak reference back to the crystal. + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(sea_crystal_summon_telegraph), summon_turfs, center), 2.5 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(sea_crystal_summon_hivelords), summon_turfs, summon_contexts, WEAKREF(src)), 3.5 SECONDS) return TRUE /** * Sparks and camera shake, one second before the hivelords actually land. * - * Deliberately NOT guarded on QDELETED(src), and neither is summon_hivelords(): - * a committed wave lands even if the crystal is broken during its own three and - * a half second windup. Both used to bail there, which meant the harder a crew - * hit the crystal the less it answered with, and a fast kill produced no - * hivelords whatsoever - the one case the answer exists for. The landing spots - * were picked when the wave was committed, so nothing here needs the crystal to - * still be standing; `origin` is carried through because a broken spawner has - * been moved to nullspace and its own loc is no longer a turf. + * The independent timer survives the crystal's destruction. Landing spots, + * origin and spawn contexts were all pinned when the wave was committed. */ -/obj/structure/spawner/sea_crystal/proc/summon_telegraph(list/summon_turfs, turf/origin) +/proc/sea_crystal_summon_telegraph(list/summon_turfs, turf/origin) if(!length(summon_turfs) || isnull(origin)) return for(var/mob/mob in range(10, origin)) @@ -167,19 +165,24 @@ new /obj/effect/temp_visual/seacrystal/sparks(summon_turf) new /obj/effect/temp_visual/seacrystal/arrival(summon_turf) -/obj/structure/spawner/sea_crystal/proc/summon_hivelords(list/summon_turfs) - var/still_standing = !QDELETED(src) +/proc/sea_crystal_summon_hivelords(list/summon_turfs, list/summon_contexts, datum/weakref/crystal_ref) + var/obj/structure/spawner/sea_crystal/crystal = crystal_ref.resolve() for(var/turf/summon_turf as anything in summon_turfs) - var/mob/living/basic/mining/hivelord/beach/hivelord = new(summon_turf) + var/datum/npc_spawn_context/context = summon_contexts[summon_turf] + var/mob/living/basic/mining/hivelord/beach/hivelord = spawn_npc_in_zone(/mob/living/basic/mining/hivelord/beach, summon_turf, context) // A broken crystal keeps no ledger: it will never summon again, and // registering on the hivelord would hold the dead spawner alive through // the signal until the mob died. - if(!still_standing) + if(QDELETED(crystal)) continue - live_hivelords += hivelord - RegisterSignals(hivelord, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING), PROC_REF(on_hivelord_gone)) - if(still_standing) - crystal_depower() + crystal.track_hivelord(hivelord) + if(!QDELETED(crystal)) + crystal.crystal_depower() + +/// A surviving crystal tracks its own wave until the hivelords die or disappear. +/obj/structure/spawner/sea_crystal/proc/track_hivelord(mob/living/hivelord) + live_hivelords += hivelord + RegisterSignals(hivelord, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING), PROC_REF(on_hivelord_gone)) /// Free the slot on death rather than on deletion - a corpse is not a threat. /obj/structure/spawner/sea_crystal/proc/on_hivelord_gone(datum/source) diff --git a/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm b/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm index 63f4b66c4d3..8963ec41abd 100644 --- a/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm +++ b/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm @@ -39,5 +39,5 @@ /mob/living/simple_animal/hostile/asteroid/polarbear/random/Initialize() . = ..() if(prob(15)) - new /mob/living/simple_animal/hostile/asteroid/polarbear/warrior(loc) + spawn_npc_in_zone(/mob/living/simple_animal/hostile/asteroid/polarbear/warrior, loc, get_npc_spawn_context(), FALSE) return INITIALIZE_HINT_QDEL diff --git a/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm b/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm index da80bd6cb72..3244e474397 100644 --- a/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm +++ b/voidcrew/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm @@ -69,7 +69,7 @@ /mob/living/basic/mining/wolf/random/Initialize() . = ..() if(prob(15)) - new /mob/living/basic/mining/wolf/alpha(loc) + spawn_npc_in_zone(/mob/living/basic/mining/wolf/alpha, loc, get_npc_spawn_context(), FALSE) return INITIALIZE_HINT_QDEL /mob/living/basic/mining/wolf/wasteland @@ -81,5 +81,5 @@ /mob/living/basic/mining/wolf/wasteland/random/Initialize() . = ..() if(prob(15)) - new /mob/living/basic/mining/wolf/alpha/wasteland(loc) + spawn_npc_in_zone(/mob/living/basic/mining/wolf/alpha/wasteland, loc, get_npc_spawn_context(), FALSE) return INITIALIZE_HINT_QDEL diff --git a/voidcrew/modules/mob/living/simple_animal/hostile/wasteland/hermits.dm b/voidcrew/modules/mob/living/simple_animal/hostile/wasteland/hermits.dm index ddbadbbbbe0..e59848796f3 100644 --- a/voidcrew/modules/mob/living/simple_animal/hostile/wasteland/hermits.dm +++ b/voidcrew/modules/mob/living/simple_animal/hostile/wasteland/hermits.dm @@ -54,10 +54,10 @@ /mob/living/simple_animal/hostile/asteroid/hermit/survivor/random/Initialize() . = ..() if(prob(10)) - new /mob/living/simple_animal/hostile/asteroid/hermit/ranged/gunslinger(loc) + spawn_npc_in_zone(/mob/living/simple_animal/hostile/asteroid/hermit/ranged/gunslinger, loc, get_npc_spawn_context(), FALSE) return INITIALIZE_HINT_QDEL if(prob(35)) - new /mob/living/simple_animal/hostile/asteroid/hermit/ranged/hunter(loc) + spawn_npc_in_zone(/mob/living/simple_animal/hostile/asteroid/hermit/ranged/hunter, loc, get_npc_spawn_context(), FALSE) return INITIALIZE_HINT_QDEL /mob/living/simple_animal/hostile/asteroid/hermit/ranged diff --git a/voidcrew/modules/unit_tests/voidcrew_derelict_layout.dm b/voidcrew/modules/unit_tests/voidcrew_derelict_layout.dm index daefc48d266..aa49e8e1668 100644 --- a/voidcrew/modules/unit_tests/voidcrew_derelict_layout.dm +++ b/voidcrew/modules/unit_tests/voidcrew_derelict_layout.dm @@ -122,3 +122,35 @@ TEST_ASSERT(fixture.on, "A light stayed off in a relit berth (status [fixture.status])") qdel(berth) + +/// Shared mob types must use the designated boss role after theme-specific setup. +/datum/derelict_theme/npc_zone_test + id = "npc_zone_test" + +/datum/derelict_theme/npc_zone_test/prepare_hostile(mob/living/hostile) + hostile.setMaxHealth(200) + hostile.setBruteLoss(50) + hostile.melee_damage_lower = 30 + hostile.melee_damage_upper = 40 + +/datum/unit_test/voidcrew_derelict_zone_profiles/Run() + var/obj/structure/overmap/dynamic/player_outpost/derelict/site = allocate(/obj/structure/overmap/dynamic/player_outpost/derelict) + var/datum/derelict_scene/scene = allocate(/datum/derelict_scene, site) + var/datum/derelict_theme/theme = allocate(/datum/derelict_theme/npc_zone_test) + for(var/band in 1 to 3) + site.derelict_band = band + for(var/role in list("ordinary", "boss")) + var/list/mob/living/spawned = list() + var/mob/living/body = scene.add_hostile(theme, /mob/living/basic/npc_zone_test/replacement, run_loc_floor_bottom_left, role, spawned) + TEST_ASSERT_NOTNULL(body, "Derelict route lost its replacement") + TEST_ASSERT_EQUAL(length(spawned), 1, "Derelict registered a discarded precursor") + TEST_ASSERT_EQUAL(body.npc_spawn_context.source_id, REF(site), "Derelict hostile lost site identity") + TEST_ASSERT_EQUAL(body.npc_zone_role, role, "Designated derelict boss was treated as its ordinary shared type") + var/health_factor = band == 1 ? 1 : (role == "boss" ? (band == 2 ? 1.15 : 1.3) : (band == 2 ? 1.35 : 1.8)) + var/damage_factor = band == 1 ? 1 : (role == "boss" ? (band == 2 ? 1.1 : 1.2) : (band == 2 ? 1.15 : 1.35)) + TEST_ASSERT(abs(body.maxHealth - 200 * health_factor) < 0.001, "Derelict finalized before theme health setup") + TEST_ASSERT(abs(body.health / body.maxHealth - 0.75) < 0.001, "Derelict profile healed theme damage") + TEST_ASSERT(abs(body.melee_damage_upper - 40 * damage_factor) < 0.001, "Derelict theme melee missed the selected factor") + body.npc_spawn_context.finalize() + TEST_ASSERT(abs(body.maxHealth - 200 * health_factor) < 0.001, "Derelict retained a stacking multiplier") + qdel(body) diff --git a/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm index 1fcbdab9446..23faaa5a02c 100644 --- a/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm +++ b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm @@ -521,3 +521,292 @@ TEST_ASSERT_EQUAL(goon.npc_zone_role, "ordinary", "Custom mafia room output missed finalization") TEST_ASSERT(abs(goon.maxHealth - goon.npc_zone_original_max_health * 1.8) < 0.001, "Custom mafia room output missed the selected factor") TEST_ASSERT(count >= 1 && count <= 2, "Custom mafia marker escaped the 1-2 output budget") + +/// Field-route fixtures suppress offer generation, retaining the real spawn/tracking paths. +/datum/mission/npc_zone_test/generate_mission_details() + return + +/datum/mission_target/npc_zone_test + var/band = 3 + +/datum/mission_target/npc_zone_test/get_zone_type() + return band + +/datum/unit_test/voidcrew_npc_zone_mission_routes/Run() + var/turf/location = run_loc_floor_bottom_left + var/datum/mission/mission = allocate(/datum/mission/npc_zone_test) + mission.objective_name = "Test quarry" + var/datum/mission_target/npc_zone_test/site = allocate(/datum/mission_target/npc_zone_test, mission) + mission.target = site + for(var/objective_type in list(/datum/mission_objective/field/kill_named, /datum/mission_objective/field/kill_named/big_game)) + var/datum/mission_objective/field/kill_named/objective = allocate(objective_type) + objective.mission = mission + objective.target_mob_type = /mob/living/basic/npc_zone_test/replacement + objective.guard_types = list(/mob/living/basic/npc_zone_test/replacement) + var/is_hunt = istype(objective, /datum/mission_objective/field/kill_named/big_game) + if(is_hunt) + var/datum/mission_objective/field/kill_named/big_game/hunt = objective + hunt.health_override = 450 + objective.spawn_field_objects(location) + var/mob/living/body = objective.target_mob + TEST_ASSERT_NOTNULL(body, "[objective_type] lost its replacement target") + TEST_ASSERT_EQUAL(body.npc_spawn_context.source_id, REF(site), "Mission target lost site identity") + TEST_ASSERT_EQUAL(body.npc_spawn_context.zone_type, 3, "Mission used its spawn turf instead of its site's band") + TEST_ASSERT(abs(body.maxHealth - (is_hunt ? 810 : 180)) < 0.001, "Mission finalized before hunt health setup") + var/guards = 0 + for(var/mob/living/basic/npc_zone_test/guard in range(3, location)) + if(guard == body) + continue + guards++ + TEST_ASSERT_EQUAL(guard.maxHealth, 180, "Mission guard replacement missed finalization") + qdel(guard) + TEST_ASSERT_EQUAL(guards, 1, "Mission lost an entourage output") + mission.forget_quest_atom(body) + objective.deactivate() + qdel(body) + qdel(objective) + // Auto role profiles hostile specimens while passive captures remain baseline. + for(var/specimen_type in list(/mob/living/basic/npc_zone_test/replacement, /mob/living/basic/butterfly)) + var/datum/mission_objective/field/capture_beast/capture = allocate(/datum/mission_objective/field/capture_beast) + capture.mission = mission + capture.target_mob_type = specimen_type + capture.spawn_field_objects(location) + var/mob/living/body = capture.target_mob + var/hostile = specimen_type == /mob/living/basic/npc_zone_test/replacement + TEST_ASSERT_EQUAL(body.npc_zone_applied, hostile, "Capture route ignored the environmental hostile gate") + if(hostile) + TEST_ASSERT_EQUAL(body.maxHealth, 180, "Hostile capture lost the site band") + else + TEST_ASSERT_EQUAL(body.maxHealth, initial(body.maxHealth), "Passive specimen was scaled") + mission.forget_quest_atom(body) + capture.deactivate() + qdel(body) + qdel(capture) + var/datum/mission_objective/field/wipe_camp/camp = allocate(/datum/mission_objective/field/wipe_camp) + camp.mission = mission + camp.squad_types = list(/mob/living/simple_animal/hostile/npc_zone_test) + camp.squad_names = list("Test poacher") + // A hostile type makes a missing rescue exemption visible. + camp.critter_type = /mob/living/basic/npc_zone_test/replacement + camp.spawn_field_objects(location) + TEST_ASSERT_EQUAL(length(camp.squad), 1, "Camp did not retain its squad") + var/mob/living/poacher = camp.squad[1] + TEST_ASSERT_EQUAL(poacher.maxHealth, 180, "Poacher missed camp-band finalization") + var/cages = 0 + for(var/obj/item/pet_carrier/cage in range(3, location)) + for(var/mob/living/rescued in cage) + cages++ + TEST_ASSERT(rescued.npc_zone_exempt && !rescued.npc_zone_applied, "Rescued cage replacement received a hostile profile") + TEST_ASSERT_EQUAL(rescued.maxHealth, 100, "Rescued animal health was scaled") + TEST_ASSERT(cages >= 1, "Camp fixture did not produce a rescued animal") + mission.forget_quest_atom(mission.quest_atom) + camp.deactivate() + qdel(poacher) + +/// Actual fauna replacement rolls must defer finalization until the caller finishes setup. +/datum/unit_test/voidcrew_npc_zone_fauna_routes/Run() + var/list/replacement_types = list( + /mob/living/basic/mining/wolf/random = /mob/living/basic/mining/wolf/alpha, + /mob/living/basic/mining/wolf/wasteland/random = /mob/living/basic/mining/wolf/alpha/wasteland, + /mob/living/simple_animal/hostile/asteroid/polarbear/random = /mob/living/simple_animal/hostile/asteroid/polarbear/warrior, + /mob/living/simple_animal/hostile/asteroid/hermit/survivor/random = /mob/living/simple_animal/hostile/asteroid/hermit/ranged, + ) + for(var/spawn_type in replacement_types) + var/found_replacement = FALSE + // Stop at the first replacement. Even the 15% rolls miss all 256 with probability < 1e-18. + for(var/attempt in 1 to 256) + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, 2) + var/mob/living/body = spawn_npc_in_zone(spawn_type, run_loc_floor_bottom_left, context, FALSE) + TEST_ASSERT(!body.npc_zone_applied, "[spawn_type] finalized during its replacement roll") + found_replacement = istype(body, replacement_types[spawn_type]) + body.setMaxHealth(200) + body.setBruteLoss(50) + context.finalize() + var/is_boss = npc_zone_boss_type(body.type) + TEST_ASSERT(abs(body.maxHealth - (is_boss ? 230 : 270)) < 0.001, "[spawn_type] lost replacement role or caller setup") + TEST_ASSERT(abs(body.health / body.maxHealth - 0.75) < 0.001, "[spawn_type] healed during finalization") + TEST_ASSERT_EQUAL(body.npc_spawn_context, context, "Replacement acquired a second context") + qdel(body) + if(found_replacement) + break + TEST_ASSERT(found_replacement, "[spawn_type] never exercised its replacement route") + +/datum/unit_test/voidcrew_npc_zone_crystal_route/Run() + var/turf/location = run_loc_floor_bottom_left + var/obj/structure/spawner/sea_crystal/crystal = allocate(/obj/structure/spawner/sea_crystal, location) + crystal.npc_spawn_context.on_zone_resolved(3) + var/source_id = crystal.npc_spawn_context.source_id + crystal.summon_count = 1 + TEST_ASSERT(crystal.summon_minions(), "Crystal could not commit a retaliation wave") + qdel(crystal) + sleep(4 SECONDS) + var/mob/living/basic/mining/hivelord/beach/hivelord = locate() in range(1, location) + TEST_ASSERT_NOTNULL(hivelord, "Committed crystal retaliation vanished with its source") + TEST_ASSERT_EQUAL(hivelord.npc_spawn_context.source_id, source_id, "Delayed retaliation lost crystal identity") + TEST_ASSERT_EQUAL(hivelord.npc_spawn_context.zone_type, 3, "Delayed retaliation resolved against its landing turf") + TEST_ASSERT(abs(hivelord.maxHealth - hivelord.npc_zone_original_max_health * 1.8) < 0.001, "Delayed retaliation did not finalize") + allocated += hivelord + +/datum/unit_test/voidcrew_npc_zone_ambush_route/Run() + var/turf/location = run_loc_floor_bottom_left + var/datum/ambient_place/site/site = allocate(/datum/ambient_place/site, null, location) + site.band = 2 + var/mob/living/basic/ambient_npc/planet/peddler/peddler = allocate(/mob/living/basic/ambient_npc/planet/peddler, location) + peddler.set_place(site) + var/mob/living/basic/bait = allocate(/mob/living/basic, run_loc_floor_top_right) + var/datum/ambient_activity/caravan_ambush/ambush = allocate(/datum/ambient_activity/caravan_ambush, peddler) + var/mob/living/raider = ambush.spawn_raider(/mob/living/basic/npc_zone_test/replacement, run_loc_floor_top_right, bait) + allocated += raider + // spawn_pack owns this ledger and Destroy unregisters the pack's attack signal. + ambush.pack += WEAKREF(raider) + TEST_ASSERT_EQUAL(raider.npc_spawn_context.source_id, REF(site), "Caravan ambusher lost site identity") + TEST_ASSERT_EQUAL(raider.maxHealth, 135, "Caravan ambusher ignored the site band") + TEST_ASSERT(raider.GetComponent(/datum/component/leash), "Caravan ambusher missed its setup") + TEST_ASSERT_EQUAL(raider.ai_controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET], bait, "Caravan target setup was lost") + for(var/faction_token in raider.faction) + TEST_ASSERT(!findtext("[faction_token]", "planetary_"), "Caravan ambusher kept the planet's faction") + +/// A hull fixture provides floor and crew, with real overmap resolution for its token. +/obj/structure/overmap/ship/npc_zone_test + var/turf/test_floor + +/obj/structure/overmap/ship/npc_zone_test/get_random_open_ship_turf(max_tries = 20) + return test_floor + +/obj/structure/overmap/ship/npc_zone_test/is_aboard(atom/thing) + return get_turf(thing) == test_floor + +/obj/structure/overmap/ship/npc_zone_test/get_event_crew() + return list(1, 2, 3, 4, 5) + +/datum/round_event/voidcrew/vent_clog/npc_zone_test + var/obj/machinery/atmospherics/components/unary/vent_pump/test_vent + +/datum/round_event/voidcrew/vent_clog/npc_zone_test/get_vent() + return test_vent + +/datum/voidcrew_cargo_shuttle/npc_zone_test + var/list/test_turfs + +/datum/voidcrew_cargo_shuttle/npc_zone_test/get_cargo_bay_turfs() + return test_turfs.Copy() + +/datum/unit_test/voidcrew_npc_zone_event_routes + parent_type = /datum/unit_test/voidcrew_npc_zone_packed + +/datum/unit_test/voidcrew_npc_zone_event_routes/Run() + zones_were_active = SSovermap_zones.zones_active + SSovermap_zones.zones_active = TRUE + var/turf/base = run_loc_floor_bottom_left + var/original_type = base.type + var/turf/open/overmap/token = base.ChangeTurf(/turf/open/overmap) + overmap_turfs[token] = original_type + var/datum/overmap_zone/red = allocate(/datum/overmap_zone, 3) + var/datum/overmap_zone/green = allocate(/datum/overmap_zone, 1) + token.current_zone = red + var/turf/location = run_loc_floor_top_right + var/obj/structure/overmap/ship/npc_zone_test/ship = allocate(/obj/structure/overmap/ship/npc_zone_test, token) + ship.test_floor = location + var/obj/docking_port/mobile/voidcrew/port = allocate(/obj/docking_port/mobile/voidcrew, location) + ship.shuttle = port + var/datum/round_event/voidcrew/portal_storm/storm = allocate(/datum/round_event/voidcrew/portal_storm, FALSE) + storm.target_ship = ship + storm.setup() + storm.hostile_types = list(/mob/living/basic/npc_zone_test/replacement = 1) + storm.boss_types = list(/mob/living/basic/npc_zone_test/replacement = 1) + storm.mob_cap = 2 + storm.spawn_slots_remaining = 2 + storm.pulses_remaining = 1 + storm.boss_pending = TRUE + token.current_zone = green + storm.spawn_pulse() + var/list/roles = list() + for(var/mob/living/basic/npc_zone_test/body in location) + roles += body.npc_zone_role + TEST_ASSERT_EQUAL(body.npc_spawn_context.zone_type, 3, "Portal pulse retiered after the ship moved bands") + TEST_ASSERT(abs(body.maxHealth - (body.npc_zone_role == "boss" ? 130 : 180)) < 0.001, "Portal slot lost its explicit role") + qdel(body) + TEST_ASSERT_EQUAL(length(roles), 2, "Portal fixture lost an output") + TEST_ASSERT(("ordinary" in roles) && ("boss" in roles), "Portal boss and ordinary slots used the same role") + storm.kill() + qdel(storm) + // Docked tokens are nested in their destination; the hull floor need not resolve at all. + token.current_zone = red + var/obj/structure/overmap/planet/site = allocate(/obj/structure/overmap/planet, token) + ship.forceMove(site) + ship.docked = site + var/obj/machinery/atmospherics/components/unary/vent_pump/vent = allocate(/obj/machinery/atmospherics/components/unary/vent_pump, location) + var/datum/round_event/voidcrew/vent_clog/npc_zone_test/clog = allocate(/datum/round_event/voidcrew/vent_clog/npc_zone_test, FALSE) + clog.target_ship = ship + clog.test_vent = vent + clog.setup() + ship.forceMove(token) + ship.docked = null + ship.state = "transit" + token.current_zone = green + clog.spawned_mob = /mob/living/basic/npc_zone_test/replacement + clog.produce_mob() + TEST_ASSERT_EQUAL(length(clog.living_mobs), 1, "Vent fixture did not emit a hostile") + for(var/datum/weakref/body_ref as anything in clog.living_mobs) + var/mob/living/body = body_ref.resolve() + TEST_ASSERT_EQUAL(body.npc_spawn_context.zone_type, 3, "Vent used transit floor or the new ship band") + TEST_ASSERT_EQUAL(body.maxHealth, 180, "Vent replacement missed finalization") + qdel(body) + clog.life_check() + clog.spawned_mob = /mob/living/basic/butterfly + clog.produce_mob() + for(var/datum/weakref/body_ref as anything in clog.living_mobs) + var/mob/living/body = body_ref.resolve() + TEST_ASSERT(!body.npc_zone_applied, "Harmless vent fauna was scaled") + qdel(body) + clog.kill() + qdel(clog) + qdel(vent) + // Exercise each complete hostile loan roster, including optional additions. + var/datum/voidcrew_cargo_shuttle/npc_zone_test/cargo = allocate(/datum/voidcrew_cargo_shuttle/npc_zone_test) + cargo.target_ship = ship + cargo.test_turfs = block(get_step(token, NORTH), get_step(location, WEST)) + for(var/loan_type in list(/datum/voidcrew_shuttle_loan/syndiehijacking, /datum/voidcrew_shuttle_loan/lots_of_bees, /datum/voidcrew_shuttle_loan/russian_party, /datum/voidcrew_shuttle_loan/spider_gift)) + token.current_zone = red + var/datum/voidcrew_shuttle_loan/loan = allocate(loan_type) + loan.spawn_items(cargo) + var/hostiles = 0 + for(var/turf/tile as anything in cargo.test_turfs) + for(var/mob/living/body in tile) + if(!isbasicmob(body) && !isanimal(body)) + continue + if(!body.npc_spawn_context || body.npc_zone_exempt) + continue + hostiles++ + TEST_ASSERT_EQUAL(body.npc_spawn_context.zone_type, 3, "[loan_type] resolved against the cargo bay") + TEST_ASSERT_EQUAL(body.npc_spawn_context.source_id, REF(cargo), "[loan_type] lost its delivery identity") + TEST_ASSERT(body.npc_zone_applied, "[loan_type] missed its explicit hostile encounter role") + if(body.npc_zone_applied) + TEST_ASSERT(abs(body.maxHealth - body.npc_zone_original_max_health * 1.8) < 0.001, "[loan_type] missed ordinary scaling") + qdel(body) + TEST_ASSERT(hostiles >= 1, "[loan_type] did not emit profiled cargo") + token.current_zone = green + var/mob/living/late = loan.spawn_hostile(/mob/living/basic/npc_zone_test, location, cargo) + TEST_ASSERT_EQUAL(late.maxHealth, 180, "A later loan output selected a different host band") + qdel(late) + qdel(loan) + ship.shuttle = null + qdel(port, force = TRUE) + +/datum/unit_test/voidcrew_npc_zone_recruit_route/Run() + var/obj/structure/overmap/ship/ship = strays_test_ship(ambient_test_room_bounds()) + var/mob/living/carbon/human/consistent/leader = allocate(/mob/living/carbon/human/consistent, run_loc_floor_top_right) + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, 3, "ordinary") + var/mob/living/basic/ambient_npc/stray/stranded/stray = spawn_npc_in_zone(/mob/living/basic/ambient_npc/stray/stranded, run_loc_floor_bottom_left, context, FALSE) + allocated += stray + stray.faction = list(FACTION_HOSTILE) + context.finalize() + TEST_ASSERT(stray.npc_zone_applied, "Recruit fixture did not begin profiled") + stray.setBruteLoss(stray.maxHealth / 2) + TEST_ASSERT(stray.accept_offer(leader, ship), "Recruit fixture could not join") + TEST_ASSERT(stray.npc_zone_exempt && !stray.npc_zone_applied, "Recruitment retained a hostile profile") + TEST_ASSERT(abs(stray.health / stray.maxHealth - 0.5) < 0.001, "Recruitment healed the recruit") + var/datum/npc_spawn_context/child_context = allocate(/datum/npc_spawn_context, stray, 3) + var/mob/living/child = spawn_npc_in_zone(/mob/living/basic/npc_zone_test/replacement, run_loc_floor_bottom_left, child_context) + allocated += child + TEST_ASSERT(child.npc_zone_exempt && !child.npc_zone_applied, "Recruit descendants lost exemption") From a2ffd6e6c24c14f2840019dd5a7259904b0c4c1c Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:12:56 -0700 Subject: [PATCH 035/105] NPC zone profile: spawned children, lich, vestige waves and exemptions --- .../basic/lavaland/hivelord/hivelord.dm | 10 +- .../lavaland/hivelord/spawn_hivelord_brood.dm | 8 +- .../basic/lavaland/legion/legion_brood.dm | 12 +- .../basic/lavaland/legion/legion_tumour.dm | 36 ++- .../basic/lavaland/legion/spawn_legions.dm | 8 +- .../simple_animal/hostile/megafauna/legion.dm | 17 +- .../spells/spell_types/conjure/_conjure.dm | 9 +- voidcrew/modules/antag_ruins/theme_cult.dm | 4 +- voidcrew/modules/antag_ruins/theme_dragon.dm | 7 +- voidcrew/modules/antag_ruins/theme_spider.dm | 5 +- voidcrew/modules/antag_ruins/theme_xeno.dm | 6 +- .../modules/colosseum/colosseum_modifiers.dm | 4 +- voidcrew/modules/lich/lich_abilities.dm | 15 +- voidcrew/modules/lich/lich_mob.dm | 6 +- voidcrew/modules/lich/lich_site.dm | 5 +- voidcrew/modules/lich/lich_spells.dm | 7 +- voidcrew/modules/npc_scaling/zone_profiles.dm | 6 +- .../player_outposts/outpost_prison_guards.dm | 4 +- voidcrew/modules/unit_tests/voidcrew_loot.dm | 4 + .../unit_tests/voidcrew_npc_zone_profiles.dm | 304 ++++++++++++++++++ 20 files changed, 446 insertions(+), 31 deletions(-) diff --git a/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm b/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm index fbe205ba074..27e5f05e2e2 100644 --- a/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm +++ b/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm @@ -50,6 +50,7 @@ safe_turfs -= check_turf var/turf/our_turf = get_turf(src) + get_npc_spawn_context() // VOIDCREW EDIT - npc_scaling: pin the death burst's source before its delay. for (var/i in 1 to 3) if (!length(safe_turfs)) return @@ -59,10 +60,15 @@ /// Spawns a worm on the specified turf /mob/living/basic/mining/hivelord/proc/complete_spawn(turf/spawn_turf) - var/mob/living/brood = new death_spawn_type(spawn_turf) + // VOIDCREW EDIT ADDITION START - npc_scaling: carry the environmental source into death brood. + get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(src, role = "ordinary") + var/mob/living/brood = spawn_npc_in_zone(death_spawn_type, spawn_turf, context, FALSE) + // VOIDCREW EDIT ADDITION END brood.faction = faction - brood.ai_controller?.set_blackboard_key(ai_controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]) + brood.ai_controller?.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, ai_controller?.blackboard[BB_BASIC_MOB_CURRENT_TARGET]) // VOIDCREW EDIT - npc_scaling: retain the death brood's target during setup. brood.dir = get_dir(src, spawn_turf) + context.finalize() // VOIDCREW EDIT - npc_scaling: finalize after faction setup. /mob/living/basic/mining/hivelord/RangedAttack(atom/atom_target, modifiers) spawn_brood?.Trigger(target = atom_target) diff --git a/code/modules/mob/living/basic/lavaland/hivelord/spawn_hivelord_brood.dm b/code/modules/mob/living/basic/lavaland/hivelord/spawn_hivelord_brood.dm index 6dbbe72a245..be222e5156c 100644 --- a/code/modules/mob/living/basic/lavaland/hivelord/spawn_hivelord_brood.dm +++ b/code/modules/mob/living/basic/lavaland/hivelord/spawn_hivelord_brood.dm @@ -70,6 +70,7 @@ return FALSE var/turf/land_turf = pick(target_turfs) + owner.get_npc_spawn_context() // VOIDCREW EDIT - npc_scaling: pin the parent before the delayed emission. var/obj/effect/temp_visual/hivebrood_spawn/forecast = new(land_turf) forecast.create_from(spawn_type, get_turf(owner), CALLBACK(src, PROC_REF(complete_spawn), land_turf, ai_target)) StartCooldown() @@ -78,10 +79,15 @@ /// Actually create a mob /datum/action/cooldown/mob_cooldown/hivelord_spawn/proc/complete_spawn(turf/spawn_turf, target) - var/mob/living/brood = new spawn_type(spawn_turf) + // VOIDCREW EDIT ADDITION START - npc_scaling: children inherit the source, not the parent's role. + owner.get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(owner, role = "ordinary") + var/mob/living/brood = spawn_npc_in_zone(spawn_type, spawn_turf, context, FALSE) + // VOIDCREW EDIT ADDITION END brood.faction = owner.faction brood.ai_controller?.set_blackboard_key(ai_target_key, target) brood.dir = get_dir(owner, spawn_turf) + context.finalize() // VOIDCREW EDIT - npc_scaling: faction and targeting setup is complete. #define BROOD_ARC_Y_OFFSET 8 #define BROOD_ARC_ROTATION 45 diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm index e09a617f122..c92f839fae9 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm @@ -66,9 +66,19 @@ /mob/living/basic/legion_brood/proc/infest(mob/living/carbon/human/target) visible_message(span_warning("[name] burrows into the flesh of [target]!")) var/spawn_type = get_legion_type(target) - var/mob/living/basic/mining/legion/new_legion = new spawn_type(loc) + // VOIDCREW EDIT ADDITION START - npc_scaling: infestation retains the attacking brood's source. + get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(src, role = "ordinary") + var/mob/living/basic/mining/legion/new_legion = spawn_npc_in_zone(spawn_type, loc, context, FALSE) + // VOIDCREW EDIT ADDITION END new_legion.consume(target) new_legion.faction = faction.Copy() + // VOIDCREW EDIT ADDITION START - npc_scaling: a parasite left in the victim retains the same source. + var/obj/item/organ/legion_tumour/tumour = target.get_organ_slot(ORGAN_SLOT_PARASITE_EGG) + if(istype(tumour)) + tumour.npc_spawn_context = context + context.finalize() + // VOIDCREW EDIT ADDITION END qdel(src) /// Returns the kind of legion we make out of the target diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm index 6be564ab4ab..ab282e805c4 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm @@ -58,6 +58,9 @@ /obj/item/organ/legion_tumour/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags) . = ..() + // VOIDCREW EDIT ADDITION START - npc_scaling: retain infection context, including constructor-created parasites. + npc_spawn_context ||= GLOB.npc_zone_construction_context || new /datum/npc_spawn_context(organ_owner) + // VOIDCREW EDIT ADDITION END owner.log_message("has received [src] which will eventually turn them into a Legion.", LOG_VICTIM) /obj/item/organ/legion_tumour/attack(mob/living/target, mob/living/user, list/modifiers, list/attack_modifiers) @@ -86,7 +89,10 @@ log_combat(user, target, "used a Legion Tumour on", src, "as they are in crit, this will turn them into a Legion.") target.visible_message(span_boldwarning("[user] splatters [target] with [src]... and it springs into horrible life!")) - var/mob/living/basic/legion_brood/skull = new(target.loc) + // VOIDCREW EDIT ADDITION START - npc_scaling: manually applied tumours inherit the user's ownership exemption. + var/datum/npc_spawn_context/context = new(user, role = "ordinary") + var/mob/living/basic/legion_brood/skull = spawn_npc_in_zone(/mob/living/basic/legion_brood, target.loc, context) + // VOIDCREW EDIT ADDITION END skull.melee_attack(target) return TRUE @@ -125,8 +131,7 @@ if (prob(50)) var/turf/check_turf = get_step(owner.loc, owner.dir) var/atom/land_turf = (check_turf.is_blocked_turf()) ? owner.loc : check_turf - var/mob/living/basic/legion_brood/child = new(land_turf) - child.assign_creator(owner, copy_full_faction = FALSE) + spawn_brood(land_turf) // VOIDCREW EDIT - npc_scaling: finalize after creator assignment. if(SPT_PROB(3, seconds_per_tick)) to_chat(owner, span_danger("Your muscles ache.")) @@ -145,14 +150,35 @@ if (stage == 5) to_chat(owner, span_bolddanger("Something is moving under your skin!")) +// VOIDCREW EDIT ADDITION START - npc_scaling: parasite children retain the infection source. +/obj/item/organ/legion_tumour/proc/spawn_brood(atom/location) + get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(src, role = "ordinary") + var/mob/living/basic/legion_brood/child = spawn_npc_in_zone(/mob/living/basic/legion_brood, location, context, FALSE) + child.assign_creator(owner, copy_full_faction = FALSE) + context.finalize() + return child +// VOIDCREW EDIT ADDITION END + /// Consume our host /obj/item/organ/legion_tumour/proc/infest() if (QDELETED(src) || QDELETED(owner)) return owner.log_message("has been turned into a Legion by their tumour.", LOG_VICTIM) owner.visible_message(span_boldwarning("Black tendrils burst from [owner]'s flesh, covering them in amorphous flesh!")) - var/mob/living/basic/mining/legion/new_legion = new spawn_type(owner.loc) - new_legion.consume(owner) + // VOIDCREW EDIT ADDITION START - npc_scaling: finalize the transformed body after consumption. + get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(src, role = "ordinary") + var/mob/living/basic/mining/legion/new_legion = spawn_npc_in_zone(spawn_type, owner.loc, context, FALSE) + // VOIDCREW EDIT ADDITION END + // VOIDCREW EDIT ADDITION START - npc_scaling: consume may replace this tumour; preserve the next infection too. + var/mob/living/carbon/human/host = owner + new_legion.consume(host) + var/obj/item/organ/legion_tumour/tumour = host.get_organ_slot(ORGAN_SLOT_PARASITE_EGG) + if(istype(tumour)) + tumour.npc_spawn_context = context + // VOIDCREW EDIT ADDITION END + context.finalize() // VOIDCREW EDIT - npc_scaling qdel(src) /obj/item/organ/legion_tumour/on_find(mob/living/finder) diff --git a/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm b/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm index b1732eb752f..d3c6282a26f 100644 --- a/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm +++ b/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm @@ -62,6 +62,7 @@ ai_target = owner.ai_controller?.blackboard[ai_target_key] var/target_dir = get_dir(owner, target) + owner.get_npc_spawn_context() // npc_scaling: pin the source before the landing delay. var/obj/effect/temp_visual/legion_skull_depart/launch = new(get_turf(owner)) launch.set_appearance(spawn_type) @@ -74,7 +75,11 @@ /// Actually create a mob /datum/action/cooldown/mob_cooldown/skull_launcher/proc/spawn_skull(turf/spawn_location, target) - var/mob/living/basic/legion_brood/brood = new spawn_type(spawn_location) + // VOIDCREW EDIT ADDITION START - npc_scaling: finalize the surviving child after creator setup. + owner.get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(owner, role = "ordinary") + var/mob/living/basic/legion_brood/brood = spawn_npc_in_zone(spawn_type, spawn_location, context, FALSE) + // VOIDCREW EDIT ADDITION END if (istype(brood)) brood.assign_creator(owner) brood.ai_controller?.set_blackboard_key(ai_target_key, target) @@ -83,6 +88,7 @@ brood.face_atom(target) else brood.dir = get_dir(owner, spawn_location) + context.finalize() // VOIDCREW EDIT - npc_scaling /// Animation for launching a skull diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm index 17171fb9176..8448b92752c 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm @@ -148,7 +148,11 @@ var/mob/living/living_target = target switch(living_target.stat) if(UNCONSCIOUS, HARD_CRIT) - var/mob/living/basic/legion_brood/legion = new(loc) + // VOIDCREW EDIT ADDITION START - npc_scaling: infestation uses the boss's source with the child type's role. + get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(src, role = "ordinary") + var/mob/living/basic/legion_brood/legion = spawn_npc_in_zone(/mob/living/basic/legion_brood, loc, context) + // VOIDCREW EDIT ADDITION END legion.infest(living_target) ///Special snowflake death() here. Can only die if size is 1 or lower and HP is 0 or below. @@ -176,14 +180,17 @@ ///Splits legion into smaller skulls. /mob/living/simple_animal/hostile/megafauna/legion/proc/Split() size-- + get_npc_spawn_context() // VOIDCREW EDIT - npc_scaling: pin the split source before constructing children. switch(size) if (LEGION_SMALL) for (var/i in 0 to 2) - new /mob/living/simple_animal/hostile/megafauna/legion/small(loc) + spawn_npc_in_zone(/mob/living/simple_animal/hostile/megafauna/legion/small, loc, new /datum/npc_spawn_context(src)) // VOIDCREW EDIT - npc_scaling if (LEGION_MEDIUM) - new /mob/living/simple_animal/hostile/megafauna/legion/medium/left(loc) - new /mob/living/simple_animal/hostile/megafauna/legion/medium/right(loc) - new /mob/living/simple_animal/hostile/megafauna/legion/medium/eye(loc) + // VOIDCREW EDIT ADDITION START - npc_scaling: each split is a fresh, once-finalized boss body. + spawn_npc_in_zone(/mob/living/simple_animal/hostile/megafauna/legion/medium/left, loc, new /datum/npc_spawn_context(src)) + spawn_npc_in_zone(/mob/living/simple_animal/hostile/megafauna/legion/medium/right, loc, new /datum/npc_spawn_context(src)) + spawn_npc_in_zone(/mob/living/simple_animal/hostile/megafauna/legion/medium/eye, loc, new /datum/npc_spawn_context(src)) + // VOIDCREW EDIT ADDITION END #undef LEGION_LARGE #undef LEGION_MEDIUM diff --git a/code/modules/spells/spell_types/conjure/_conjure.dm b/code/modules/spells/spell_types/conjure/_conjure.dm index 5501f1055ca..670c42906de 100644 --- a/code/modules/spells/spell_types/conjure/_conjure.dm +++ b/code/modules/spells/spell_types/conjure/_conjure.dm @@ -17,6 +17,8 @@ var/summon_respects_prev_spawn_points = TRUE /// for how long must we stay still when summoning var/create_summon_timer + /// VOIDCREW EDIT - npc_scaling: hostile encounter spells can explicitly designate their outputs. + var/npc_summon_role = "auto" /datum/action/cooldown/spell/conjure/is_valid_target(atom/cast_on) return isturf(cast_on.loc) @@ -55,13 +57,18 @@ open_turf.replace_floor(summoned_object_type, flags = CHANGETURF_INHERIT_AIR) return - var/atom/summoned_object = new summoned_object_type(spawn_place) + // VOIDCREW EDIT ADDITION START - npc_scaling: player-owned casters propagate exemption before construction. + owner.get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(owner, role = npc_summon_role) + var/atom/summoned_object = spawn_npc_in_zone(summoned_object_type, spawn_place, context, FALSE) + // VOIDCREW EDIT ADDITION END summoned_object.flags_1 |= ADMIN_SPAWNED_1 if(summon_lifespan > 0) QDEL_IN(summoned_object, summon_lifespan) post_summon(summoned_object, cast_on) + context.finalize() // VOIDCREW EDIT - npc_scaling: finalize after subtype faction/body setup. /// Called on atoms summoned after they are created, allows extra variable editing and such of created objects /datum/action/cooldown/spell/conjure/proc/post_summon(atom/summoned_object, atom/cast_on) diff --git a/voidcrew/modules/antag_ruins/theme_cult.dm b/voidcrew/modules/antag_ruins/theme_cult.dm index 55ab06aed55..42ff4681059 100644 --- a/voidcrew/modules/antag_ruins/theme_cult.dm +++ b/voidcrew/modules/antag_ruins/theme_cult.dm @@ -238,9 +238,11 @@ paid = TRUE votive.forceMove(get_turf(user)) votive.anchored = TRUE + votive.get_npc_spawn_context() running = TRUE for(var/index in 1 to 3) - var/mob/living/basic/carp/vestige_clot/clot = new(pick_n_take(places)) + var/datum/npc_spawn_context/context = new(votive) + var/mob/living/basic/carp/vestige_clot/clot = spawn_npc_in_zone(/mob/living/basic/carp/vestige_clot, pick_n_take(places), context) clots += clot RegisterSignal(clot, COMSIG_LIVING_DEATH, PROC_REF(clot_died)) refresh_tracker() diff --git a/voidcrew/modules/antag_ruins/theme_dragon.dm b/voidcrew/modules/antag_ruins/theme_dragon.dm index cf5c9ede3b7..5983795e341 100644 --- a/voidcrew/modules/antag_ruins/theme_dragon.dm +++ b/voidcrew/modules/antag_ruins/theme_dragon.dm @@ -423,6 +423,7 @@ /// Wakes the watch: the egg warms, the ground is chosen, and the first tide is heralded /obj/structure/vestige_dragon_egg/proc/begin_assault(mob/living/user) + get_npc_spawn_context() assault_underway = TRUE START_PROCESSING(SSobj, src) color = "#d8905a" // the cold gives way @@ -459,9 +460,12 @@ return wave_lost = FALSE stage++ + get_npc_spawn_context() for(var/i in 1 to 2) - var/mob/living/basic/carp/vestige_brood/hunter = new(wave_perch) + var/datum/npc_spawn_context/context = new(src) + var/mob/living/basic/carp/vestige_brood/hunter = spawn_npc_in_zone(/mob/living/basic/carp/vestige_brood, wave_perch, context, FALSE) enlist(hunter, egg_bound = (i % 2 == 0)) + context.finalize() visible_message(span_boldwarning("The brood pours from the announced approach and turns toward [src]!")) playsound(src, 'sound/effects/magic/wand_teleport.ogg', 70, TRUE) var/datum/vestige_trial/broodwatch/trial = get_bound_trial() @@ -651,6 +655,7 @@ * hunts, and tamed to the keeper by the constructor's tamer argument. */ /mob/living/basic/carp/pet/vestige_hatchling + npc_zone_exempt = TRUE name = "dragonet" desc = "A carp the colour of banked embers, fresh from a shell it had no business fitting inside. It is extremely certain it is a dragon. Nothing so far has dared correct it." gender = NEUTER diff --git a/voidcrew/modules/antag_ruins/theme_spider.dm b/voidcrew/modules/antag_ruins/theme_spider.dm index 6bd2cee52e6..c19801ceb4f 100644 --- a/voidcrew/modules/antag_ruins/theme_spider.dm +++ b/voidcrew/modules/antag_ruins/theme_spider.dm @@ -1125,7 +1125,9 @@ next_send_at = world.time + VESTIGE_TREMOR_RESPITE return next_send_at = world.time + VESTIGE_TREMOR_RESPITE // floor, so an instant kill can't machine-gun the night - var/mob/living/basic/vestige_silk_thief/filcher = new(pick(perches)) + line.get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(line) + var/mob/living/basic/vestige_silk_thief/filcher = spawn_npc_in_zone(/mob/living/basic/vestige_silk_thief, pick(perches), context, FALSE) thieves[filcher] = line line.pinged = FALSE // every new thief must announce its own first bite register_loan(filcher) @@ -1134,6 +1136,7 @@ // The lifespan rides the THIEF, not the trial. Orphans always clean themselves up addtimer(CALLBACK(filcher, TYPE_PROC_REF(/mob/living/basic/vestige_silk_thief, dissolve)), VESTIGE_TREMOR_THIEF_LIFESPAN) filcher.ai_controller?.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, line) + context.finalize() if(isliving(keeper)) to_chat(keeper, span_warning("The web shivers. Something small is moving near your line to the [dir2text(get_dir(keeper, line)) || "very spot you stand on"].")) playsound(keeper, 'sound/effects/snap.ogg', 25, TRUE) diff --git a/voidcrew/modules/antag_ruins/theme_xeno.dm b/voidcrew/modules/antag_ruins/theme_xeno.dm index 8c0e4abef47..b2957c75f53 100644 --- a/voidcrew/modules/antag_ruins/theme_xeno.dm +++ b/voidcrew/modules/antag_ruins/theme_xeno.dm @@ -402,6 +402,7 @@ /// Begins the season: the shell warms and the first work-gang is heralded /obj/structure/vestige_comb_egg/proc/begin_season(mob/living/user) + get_npc_spawn_context() assault_underway = TRUE START_PROCESSING(SSobj, src) color = "#e0c47f" // the warmth takes @@ -436,12 +437,15 @@ visible_message(span_warning("The approach has closed. Clear it and touch the shell to call the gang again.")) return squad_lost = FALSE + get_npc_spawn_context() var/list/gang_sizes = list(1, 2, 2, 3) var/squad_size = gang_sizes[squads_landed + 1] for(var/i in 1 to squad_size) - var/mob/living/basic/hivebot/vestige_comb_chewer/vermin = new(squad_perch) + var/datum/npc_spawn_context/context = new(src) + var/mob/living/basic/hivebot/vestige_comb_chewer/vermin = spawn_npc_in_zone(/mob/living/basic/hivebot/vestige_comb_chewer, squad_perch, context, FALSE) do_sparks(3, TRUE, vermin) enlist(vermin, egg_bound = TRUE) + context.finalize() squads_landed++ visible_message(span_boldwarning("The salvage gang clatters from the announced approach, cutters spinning!")) var/datum/vestige_trial/warm_season/trial = get_bound_trial() diff --git a/voidcrew/modules/colosseum/colosseum_modifiers.dm b/voidcrew/modules/colosseum/colosseum_modifiers.dm index b58a5b36fbb..49cca25abf5 100644 --- a/voidcrew/modules/colosseum/colosseum_modifiers.dm +++ b/voidcrew/modules/colosseum/colosseum_modifiers.dm @@ -108,8 +108,10 @@ if(QDELETED(spot)) continue var/beast_type = pick_weight(beast_weights) - var/mob/living/beast = new beast_type(spot) + var/datum/npc_spawn_context/context = new(controller.site, role = "exempt") + var/mob/living/beast = spawn_npc_in_zone(beast_type, spot, context, FALSE) beast.faction = list("colosseum") // beasts side with beasts, and nobody else + context.finalize() beasts += beast RegisterSignal(beast, COMSIG_LIVING_DEATH, PROC_REF(on_beast_death)) RegisterSignal(beast, COMSIG_QDELETING, PROC_REF(on_beast_gone)) diff --git a/voidcrew/modules/lich/lich_abilities.dm b/voidcrew/modules/lich/lich_abilities.dm index 07c2494cdb2..ba082eb5ac5 100644 --- a/voidcrew/modules/lich/lich_abilities.dm +++ b/voidcrew/modules/lich/lich_abilities.dm @@ -250,6 +250,7 @@ /mob/living/basic/skeleton/templar, ) summon_radius = 2 + npc_summon_role = "ordinary" summon_amount = 2 summon_respects_density = TRUE // Permanent. The cap plus the mob's death cleanup is what keeps this safe, not a @@ -298,7 +299,6 @@ qdel(risen) return - ilthuun.register_summon(risen) // FACTION_LICH is what makes the ward machines read this thing as its layer's // garrison rather than as somebody's pet, so the gates open when the hall is // actually clear. FACTION_SKELETON is kept so the /mob/living/basic/skeleton types @@ -309,6 +309,7 @@ if(risen_turf) new /obj/effect/temp_visual/small_smoke/halfsecond(risen_turf) playsound(risen_turf, 'sound/effects/magic/RATTLEMEBONES.ogg', 45, vary = TRUE) + ilthuun.register_summon(risen) // ===== DESTRUCTION ===== @@ -452,6 +453,8 @@ var/burn_interval = 1 SECONDS /// Burn applied per tick to anyone standing on an affected tile. var/burn_per_tick = 5 + /// Captured at cast time; the patch never depends on a surviving caster for damage. + var/npc_damage_factor = 1 /// The live patch's ground visuals, so his deletion can snuff them early. var/list/obj/effect/temp_visual/lich_grave_dirt/active_dirt = list() /// Stoppable id of the pending ignition, null outside the telegraph window. @@ -481,6 +484,7 @@ var/turf/center = get_turf(cast_on) if(isnull(center)) return + npc_damage_factor = isliving(owner) ? npc_zone_damage(1, owner) : 1 if(owner) owner.visible_message(span_boldwarning("Ilthuun drives a hand downward, and the ground around [cast_on] darkens into turned earth.")) @@ -538,7 +542,7 @@ for(var/mob/living/victim in tile) if(!can_burn(victim)) continue - victim.adjustFireLoss(burn_per_tick) + victim.adjustFireLoss(npc_zone_damage(burn_per_tick, npc_damage_factor)) to_chat(victim, span_danger("The grave-dirt sears you from below!")) // The first application lands at ignition, so reschedule only while the NEXT one // would still fall inside the window: 7 ticks total, not 8. @@ -660,11 +664,14 @@ var/turf/spot = get_step(cast_on, pick_n_take(directions)) if(isnull(spot) || spot.is_blocked_turf(exclude_mobs = TRUE)) continue - var/mob/living/basic/lich/mirror_image/copy = new(spot) + ilthuun.get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(ilthuun, role = "ordinary") + var/mob/living/basic/lich/mirror_image/copy = spawn_npc_in_zone(/mob/living/basic/lich/mirror_image, spot, context, FALSE) ilthuun.register_summon(copy) copies += copy RegisterSignals(copy, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH), PROC_REF(lost_copy)) QDEL_IN(copy, image_lifespan) + context.finalize() placed++ if(!placed) @@ -833,7 +840,7 @@ // mend_the_dead() in lich_spells.dm. victim.heal_overall_damage(brute = 10, burn = 10, forced = TRUE) return - victim.adjustToxLoss(8, forced = TRUE) + victim.adjustToxLoss(npc_zone_damage(8, npc_zone_damage_factor), forced = TRUE) to_chat(victim, span_danger("Something starts rotting where the bolt went in.")) #undef VERDIGRIS_TINT diff --git a/voidcrew/modules/lich/lich_mob.dm b/voidcrew/modules/lich/lich_mob.dm index 028ef65ff41..9940f0a45de 100644 --- a/voidcrew/modules/lich/lich_mob.dm +++ b/voidcrew/modules/lich/lich_mob.dm @@ -406,8 +406,12 @@ /mob/living/basic/lich/proc/register_summon(mob/living/summon) if(QDELETED(summon) || (summon in live_summons)) return + get_npc_spawn_context() + if(!summon.npc_spawn_context) + summon.npc_spawn_context = new /datum/npc_spawn_context(src, role = "ordinary") live_summons += summon RegisterSignals(summon, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH), PROC_REF(on_summon_lost)) + summon.finalize_npc_zone(summon.npc_spawn_context) /mob/living/basic/lich/proc/on_summon_lost(mob/living/source) SIGNAL_HANDLER @@ -620,7 +624,7 @@ SIGNAL_HANDLER if(attack_flags & (ATTACKER_STAMINA_ATTACK|ATTACKER_SHOVING)) return - attacker.adjustFireLoss(15) + attacker.adjustFireLoss(npc_zone_damage(15, src)) to_chat(attacker, span_warning("The image bursts, and something cold pours down your arm!")) /mob/living/basic/lich/mirror_image/examine(mob/user) diff --git a/voidcrew/modules/lich/lich_site.dm b/voidcrew/modules/lich/lich_site.dm index 22503b2c570..2205c7d2ae1 100644 --- a/voidcrew/modules/lich/lich_site.dm +++ b/voidcrew/modules/lich/lich_site.dm @@ -331,7 +331,8 @@ GLOBAL_DATUM(lich_lair, /obj/structure/overmap/space_ruin/lich_lair) if(!found_lich && !spent) var/turf/spawn_turf = boss_spawn_turf || get_random_layer_turf(/area/ruin/space/has_grav/powered/lich_lair/sanctum) if(spawn_turf) - found_lich = new /mob/living/basic/lich(spawn_turf) + var/datum/npc_spawn_context/context = new(src, role = "boss") + found_lich = spawn_npc_in_zone(/mob/living/basic/lich, spawn_turf, context) log_mapping("LICH: template placed no lich. Spawned one at ([spawn_turf.x], [spawn_turf.y]).") else log_mapping("LICH: no lich, no boss_spawn landmark and no sanctum turf. The raid has no boss.") @@ -350,6 +351,8 @@ GLOBAL_DATUM(lich_lair, /obj/structure/overmap/space_ruin/lich_lair) /obj/structure/overmap/space_ruin/lich_lair/proc/bind_lich(mob/living/boss) if(QDELETED(boss)) return + if(!boss.npc_spawn_context) + boss.finalize_npc_zone(new /datum/npc_spawn_context(src, role = "boss")) lich_ref = WEAKREF(boss) RegisterSignal(boss, COMSIG_LIVING_DEATH, PROC_REF(on_boss_death), override = TRUE) diff --git a/voidcrew/modules/lich/lich_spells.dm b/voidcrew/modules/lich/lich_spells.dm index 3ad47797a0a..096c68d95f2 100644 --- a/voidcrew/modules/lich/lich_spells.dm +++ b/voidcrew/modules/lich/lich_spells.dm @@ -439,11 +439,14 @@ var/list/mob/living/basic/verdigris_mirage/fresh_copies = list() while(length(fresh_copies) < VERDIGRIS_MIRAGE_COUNT && length(free_steps) > 1) var/turf/mirage_turf = pick_n_take(free_steps) - var/mob/living/basic/verdigris_mirage/mirage = new(mirage_turf, caster) + caster.get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(caster) + var/mob/living/basic/verdigris_mirage/mirage = spawn_npc_in_zone(/mob/living/basic/verdigris_mirage, mirage_turf, context, FALSE, list(caster)) mirages += mirage fresh_copies += mirage RegisterSignals(mirage, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH), PROC_REF(on_mirage_lost)) QDEL_IN(mirage, VERDIGRIS_MIRAGE_LIFESPAN) + context.finalize() if(!length(fresh_copies)) to_chat(caster, span_warning("The grave-light gathers, but there's no room for it.")) @@ -633,7 +636,7 @@ return stung = TRUE - attacker.adjustBruteLoss(VERDIGRIS_MIRAGE_STING) + attacker.adjustBruteLoss(npc_zone_damage(VERDIGRIS_MIRAGE_STING, src)) to_chat(attacker, span_userdanger("The mirage bursts, spraying green light through your arm!")) new /obj/effect/temp_visual/small_smoke/halfsecond(get_turf(src)) QDEL_IN(src, 0) diff --git a/voidcrew/modules/npc_scaling/zone_profiles.dm b/voidcrew/modules/npc_scaling/zone_profiles.dm index 45d1c73a443..ebd21c16099 100644 --- a/voidcrew/modules/npc_scaling/zone_profiles.dm +++ b/voidcrew/modules/npc_scaling/zone_profiles.dm @@ -83,6 +83,9 @@ /// Approved boss classification, including marker types that grant a boss role /// to otherwise ordinary bodies. Other setpiece producers pass "boss" explicitly. /proc/npc_zone_boss_type(candidate_type) + // A lich's disposable images are registered minions, not additional bosses. + if(ispath(candidate_type, /mob/living/basic/lich/mirror_image)) + return FALSE var/static/list/boss_types = list( /mob/living/simple_animal/hostile/megafauna, /mob/living/simple_animal/hostile/asteroid/elite, @@ -141,7 +144,8 @@ return if(!isbasicmob(src) && !isanimal(src)) return - if(context.role == "auto" && !is_npc_zone_hostile()) + // Named bosses (including the lich) need not start with combat mode enabled. + if(context.role == "auto" && !is_npc_zone_hostile() && !npc_zone_boss_type(type)) return npc_zone_role = (context.role == "boss" || npc_zone_boss_type(type)) ? "boss" : "ordinary" npc_zone_original_max_health = maxHealth diff --git a/voidcrew/modules/player_outposts/outpost_prison_guards.dm b/voidcrew/modules/player_outposts/outpost_prison_guards.dm index ce1e9977f88..17a559bba63 100644 --- a/voidcrew/modules/player_outposts/outpost_prison_guards.dm +++ b/voidcrew/modules/player_outposts/outpost_prison_guards.dm @@ -910,8 +910,10 @@ GLOBAL_LIST_INIT(outpost_guard_placeholders, list("{boss}", "{count}", "{cause}" var/turf/spot = guard_office_spot() if(!spot) return null - var/mob/living/basic/outpost_prison_guard/guard = new record.guard_type(spot) + var/datum/npc_spawn_context/context = new(outpost, role = "exempt") + var/mob/living/basic/outpost_prison_guard/guard = spawn_npc_in_zone(record.guard_type, spot, context, FALSE) guard.join(src, record) + context.finalize() record.away_left = 0 guard.beam_in() if(isnull(guard_rounds_left)) diff --git a/voidcrew/modules/unit_tests/voidcrew_loot.dm b/voidcrew/modules/unit_tests/voidcrew_loot.dm index d1d055355b6..f8069fcf701 100644 --- a/voidcrew/modules/unit_tests/voidcrew_loot.dm +++ b/voidcrew/modules/unit_tests/voidcrew_loot.dm @@ -74,6 +74,10 @@ // callback after we delete it. for(var/marker_path in subtypesof(/obj/effect/zone_mobs)) var/obj/effect/zone_mobs/marker = new marker_path() + for(var/list/count_range in list(marker.count_green, marker.count_yellow, marker.count_red)) + TEST_ASSERT_EQUAL(length(count_range), 2, "[marker_path] has no minimum/maximum guard count") + TEST_ASSERT_EQUAL(count_range[1], 1, "[marker_path] minimum guard count must be one in every band") + TEST_ASSERT_EQUAL(count_range[2], 2, "[marker_path] maximum guard count must be two in every band") for(var/table in list(marker.mobs_green, marker.mobs_yellow, marker.mobs_red)) for(var/entry in table) if(!ispath(entry, /mob/living)) diff --git a/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm index 23faaa5a02c..6a31510e02b 100644 --- a/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm +++ b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm @@ -153,6 +153,7 @@ )) TEST_ASSERT(npc_zone_boss_type(boss_type), "Approved boss type missing: [boss_type]") TEST_ASSERT(!npc_zone_boss_type(/mob/living/basic/npc_zone_test), "An ordinary mob was classified as a boss") + TEST_ASSERT(!npc_zone_boss_type(/mob/living/basic/lich/mirror_image), "Disposable lich images were classified as bosses") // Research's count overrides belong to W1, but its setpiece role is core policy. var/obj/effect/zone_mobs/bug/boss/research_marker = allocate(/obj/effect/zone_mobs/bug/boss) TEST_ASSERT_EQUAL(research_marker.npc_role, "boss", "Research marker did not select the explicit boss role") @@ -810,3 +811,306 @@ var/mob/living/child = spawn_npc_in_zone(/mob/living/basic/npc_zone_test/replacement, run_loc_floor_bottom_left, child_context) allocated += child TEST_ASSERT(child.npc_zone_exempt && !child.npc_zone_applied, "Recruit descendants lost exemption") + +/// Check a real route's output against raw type stats, never against its stored originals. +/datum/unit_test/proc/check_npc_zone_child(mob/living/child, datum/npc_spawn_context/parent_context, exempt = FALSE, boss = FALSE) + TEST_ASSERT_NOTNULL(child, "Child route did not produce a surviving body") + if(!child) + return + TEST_ASSERT_NOTNULL(child.npc_spawn_context, "[child.type] omitted its construction context") + if(!child.npc_spawn_context) + return + TEST_ASSERT_EQUAL(child.npc_spawn_context.source_id, parent_context.source_id, "[child.type] lost its parent's source identity") + TEST_ASSERT_EQUAL(child.npc_spawn_context.zone_type, parent_context.zone_type, "[child.type] resolved against its landing site") + TEST_ASSERT_EQUAL(child.npc_zone_applied, !exempt, "[child.type] ignored its source exemption") + if(exempt) + TEST_ASSERT(child.npc_zone_exempt, "[child.type] did not retain permanent exemption") + TEST_ASSERT_EQUAL(child.maxHealth, initial(child.maxHealth), "Exempt child health was scaled") + return + var/list/health_factors = boss ? list(1, 1.15, 1.3) : list(1, 1.35, 1.8) + var/list/damage_factors = boss ? list(1, 1.1, 1.2) : list(1, 1.15, 1.35) + TEST_ASSERT_EQUAL(child.npc_zone_role, boss ? "boss" : "ordinary", "Child inherited its parent's role instead of its own") + TEST_ASSERT(abs(child.maxHealth - initial(child.maxHealth) * health_factors[parent_context.zone_type]) < 0.001, "[child.type] did not scale its raw health exactly once") + TEST_ASSERT(abs(child.melee_damage_upper - initial(child.melee_damage_upper) * damage_factors[parent_context.zone_type]) < 0.001, "[child.type] did not scale its raw melee exactly once") + var/previous_health = child.maxHealth + child.npc_spawn_context.finalize() + TEST_ASSERT_EQUAL(child.maxHealth, previous_health, "Child finalization stacked its profile") + +/// Force the replacement parasite so its inheritance is deterministic. +/mob/living/basic/mining/legion/npc_zone_test/consume(mob/living/carbon/human/consumed) + . = ..() + var/obj/item/organ/legion_tumour/tumour = new() + tumour.Insert(consumed, special = TRUE, movement_flags = DELETE_IF_REPLACED) + +/datum/unit_test/voidcrew_npc_zone_child_routes/Run() + var/turf/location = run_loc_floor_bottom_left + var/turf/landing = run_loc_floor_top_right + var/mob/living/basic/bait = allocate(/mob/living/basic/npc_zone_test, landing) + for(var/band in 1 to 3) + for(var/exempt in list(FALSE, TRUE)) + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, band, "boss", exempt) + var/mob/living/basic/mining/hivelord/hive = spawn_npc_in_zone(/mob/living/basic/mining/hivelord, location, context) + hive.forceMove(landing) + hive.spawn_brood.complete_spawn(location, bait) + var/mob/living/basic/hivelord_brood/brood = locate() in location + check_npc_zone_child(brood, context, exempt) + TEST_ASSERT_EQUAL(brood.ai_controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET], bait, "Hivelord attack brood lost its target setup") + qdel(brood) + hive.ai_controller.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, bait) + hive.complete_spawn(location) + brood = locate() in location + check_npc_zone_child(brood, context, exempt) + TEST_ASSERT_EQUAL(brood.ai_controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET], bait, "Hivelord death brood lost its target setup") + qdel(brood) + // This callback must also finalize an Initialize replacement after setup. + hive.death_spawn_type = /mob/living/basic/npc_zone_test/replacement + hive.complete_spawn(location) + var/mob/living/basic/npc_zone_test/replacement = locate() in location + check_npc_zone_child(replacement, context, exempt) + qdel(replacement) + var/datum/action/cooldown/mob_cooldown/skull_launcher/launcher = allocate(/datum/action/cooldown/mob_cooldown/skull_launcher) + launcher.Grant(hive) + launcher.spawn_skull(location, bait) + var/mob/living/basic/legion_brood/skull = locate() in location + check_npc_zone_child(skull, context, exempt) + TEST_ASSERT_EQUAL(skull.created_by.resolve(), hive, "Legion skull lost creator assignment") + // The infected human is a victim, not the source or controller of the legion. + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent, location) + skull.infest(victim) + var/mob/living/basic/mining/legion/infested = locate() in location + check_npc_zone_child(infested, context, exempt) + TEST_ASSERT_EQUAL(infested.stored_mob, victim, "Infestation finalized before consuming its victim") + qdel(infested) + var/mob/living/carbon/human/host = allocate(/mob/living/carbon/human/consistent, location) + var/obj/item/organ/legion_tumour/tumour = allocate(/obj/item/organ/legion_tumour) + tumour.npc_spawn_context = context + tumour.spawn_type = /mob/living/basic/mining/legion/npc_zone_test + tumour.Insert(host, special = TRUE) + skull = tumour.spawn_brood(landing) + check_npc_zone_child(skull, context, exempt) + TEST_ASSERT_EQUAL(skull.created_by.resolve(), host, "Tumour brood missed its host assignment") + qdel(skull) + tumour.infest() + infested = locate() in location + check_npc_zone_child(infested, context, exempt) + var/obj/item/organ/legion_tumour/replacement_tumour = host.get_organ_slot(ORGAN_SLOT_PARASITE_EGG) + TEST_ASSERT_EQUAL(replacement_tumour.npc_spawn_context.source_id, context.source_id, "Replacement parasite lost the original infection source") + TEST_ASSERT_EQUAL(replacement_tumour.npc_spawn_context.zone_type, band, "Replacement parasite retiered against its host") + qdel(infested) + qdel(launcher) + qdel(hive) + +/datum/unit_test/voidcrew_npc_zone_legion_split_route/Run() + var/turf/location = run_loc_floor_bottom_left + for(var/exempt in list(FALSE, TRUE)) + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, 3, "boss", exempt) + var/mob/living/simple_animal/hostile/megafauna/legion/parent = spawn_npc_in_zone(/mob/living/simple_animal/hostile/megafauna/legion, location, context) + parent.forceMove(run_loc_floor_top_right) + parent.Split() + var/list/mediums = list() + for(var/mob/living/simple_animal/hostile/megafauna/legion/medium/child in run_loc_floor_top_right) + mediums += child + check_npc_zone_child(child, context, exempt, TRUE) + TEST_ASSERT_EQUAL(length(mediums), 3, "Large Legion did not produce three medium children") + var/mob/living/simple_animal/hostile/megafauna/legion/medium/medium = mediums[1] + medium.forceMove(location) + medium.Split() + var/small_count = 0 + for(var/mob/living/simple_animal/hostile/megafauna/legion/small/child in location) + small_count++ + check_npc_zone_child(child, context, exempt, TRUE) + qdel(child) + TEST_ASSERT_EQUAL(small_count, 3, "Medium Legion did not produce three small children") + QDEL_LIST(mediums) + qdel(parent) + +/// The post hook overrides health and faction and must run before finalization. +/datum/action/cooldown/spell/conjure/npc_zone_test + summon_type = list(/mob/living/basic/npc_zone_test/replacement) + summon_radius = 0 + +/datum/action/cooldown/spell/conjure/npc_zone_test/post_summon(atom/summoned_object, atom/cast_on) + var/mob/living/body = summoned_object + if(body.npc_zone_applied) + CRASH("Conjure finalized before post_summon setup") + body.faction = list(FACTION_HOSTILE) + body.setMaxHealth(200) + body.setBruteLoss(50) + +/datum/unit_test/voidcrew_npc_zone_conjure_route/Run() + var/turf/location = run_loc_floor_bottom_left + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, 3, "boss") + var/mob/living/caster = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, run_loc_floor_top_right, context) + var/datum/action/cooldown/spell/conjure/npc_zone_test/spell = allocate(/datum/action/cooldown/spell/conjure/npc_zone_test) + spell.Grant(caster) + for(var/player_owned in list(FALSE, TRUE)) + if(player_owned) + caster.mind_initialize() + spell.cast(location) + var/mob/living/basic/npc_zone_test/body = locate() in location + TEST_ASSERT_NOTNULL(body, "Conjure lost its Initialize replacement") + TEST_ASSERT_EQUAL(body.maxHealth, player_owned ? 200 : 360, "Conjure lost ownership exemption or post-summon health setup") + TEST_ASSERT(abs(body.health / body.maxHealth - 0.75) < 0.001, "Conjure finalization healed its output") + TEST_ASSERT_EQUAL(body.npc_spawn_context.source_id, context.source_id, "Conjure lost caster source identity") + TEST_ASSERT_EQUAL(body.npc_zone_exempt, player_owned, "Player summons did not retain exemption") + var/datum/npc_spawn_context/child_context = allocate(/datum/npc_spawn_context, body) + var/mob/living/child = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, location, child_context) + check_npc_zone_child(child, context, player_owned) + qdel(child) + qdel(body) + qdel(caster) + +/datum/unit_test/voidcrew_npc_zone_lich_routes/Run() + var/turf/location = run_loc_floor_bottom_left + var/obj/structure/overmap/space_ruin/lich_lair/site = allocate(/obj/structure/overmap/space_ruin/lich_lair) + site.npc_spawn_context = allocate(/datum/npc_spawn_context, site, 3) + site.ruin_bottom_left = location + var/datum/map_template/ruin/template = allocate(/datum/map_template/ruin) + template.width = 1 + template.height = 1 + site.ruin_template = template + allocate(/obj/effect/landmark/lich/boss_spawn, location) + site.link_interior() + var/mob/living/basic/lich/lich = site.lich_ref?.resolve() + TEST_ASSERT_NOTNULL(lich, "Lich site's fallback spawn did not bind a boss") + allocated += lich + check_npc_zone_child(lich, site.npc_spawn_context, FALSE, TRUE) + // A mapped lich uses the auto role and starts with combat mode off. + var/datum/npc_spawn_context/auto_context = allocate(/datum/npc_spawn_context, site, 3) + var/mob/living/basic/lich/mapped = spawn_npc_in_zone(/mob/living/basic/lich, run_loc_floor_top_right, auto_context) + check_npc_zone_child(mapped, site.npc_spawn_context, FALSE, TRUE) + qdel(mapped) + var/datum/action/cooldown/spell/conjure/lich_raise_dead/raise = allocate(/datum/action/cooldown/spell/conjure/lich_raise_dead) + raise.Grant(lich) + raise.cast(lich) + TEST_ASSERT_EQUAL(length(lich.live_summons), 2, "Lich did not register its conjured minions") + for(var/mob/living/minion as anything in lich.live_summons) + check_npc_zone_child(minion, site.npc_spawn_context) + TEST_ASSERT("verdigris" in minion.faction, "Lich summon missed its faction setup") // FACTION_LICH + var/mob/living/basic/victim = allocate(/mob/living/basic/npc_zone_test, run_loc_floor_top_right) + var/datum/action/cooldown/spell/pointed/lich_mirror_images/images = allocate(/datum/action/cooldown/spell/pointed/lich_mirror_images) + images.Grant(lich) + images.cast(victim) + TEST_ASSERT(length(images.copies) >= 1, "Lich mirror route produced no registered copies") + for(var/mob/living/basic/lich/mirror_image/image as anything in images.copies) + check_npc_zone_child(image, site.npc_spawn_context) + TEST_ASSERT(image in lich.live_summons, "Mirror image bypassed the lich's cleanup registry") + image.on_attacked(image, victim, ATTACKER_DAMAGING_ATTACK) + TEST_ASSERT(abs(victim.getBruteLoss() - 20.25) < 0.001, "Mirror retaliation did not use its ordinary damage factor") + victim.fully_heal() + var/datum/action/cooldown/spell/pointed/lich_grave_dirt/dirt = allocate(/datum/action/cooldown/spell/pointed/lich_grave_dirt) + dirt.Grant(lich) + dirt.cast(victim) + TEST_ASSERT_EQUAL(dirt.npc_damage_factor, 1.2, "Grave dirt did not capture the boss's damage factor") + dirt.Remove(lich) + qdel(lich) + dirt.burn_tick(list(get_turf(victim)), world.time) + TEST_ASSERT_EQUAL(victim.getBruteLoss(), 6, "Delayed grave dirt lost damage scaling after creator deletion") + qdel(dirt) + +/// Use the actual guard creation path and its record, without a second prison map load. +/datum/unit_test/voidcrew_npc_zone_guard_route + parent_type = /datum/unit_test/voidcrew_outpost_management + +/datum/unit_test/voidcrew_npc_zone_guard_route/Run() + var/obj/structure/overmap/dynamic/player_outpost/home = prison_test_claim("npczoneguard") + TEST_ASSERT_NOTNULL(home, "Guard profile fixture could not load its prison") + home.npc_spawn_context = allocate(/datum/npc_spawn_context, home, 3) + var/datum/outpost_prison/prison = test_prison(home) + var/datum/outpost_guard_record/record = prison.add_guard_record(TRUE) + var/mob/living/basic/outpost_prison_guard/guard = record.guard + check_npc_zone_child(guard, home.npc_spawn_context, TRUE) + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, guard) + var/mob/living/child = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, get_turf(guard), context) + check_npc_zone_child(child, home.npc_spawn_context, TRUE) + qdel(child) + +/// Arena geometry is irrelevant to spawn_wave's provided turf list. +/datum/colosseum_controller/npc_zone_test/snapshot_arena() + return + +/datum/unit_test/voidcrew_npc_zone_arena_route/Run() + var/datum/colosseum_controller/controller = allocate(/datum/colosseum_controller/npc_zone_test) + controller.state = "live" // COLOSSEUM_STATE_LIVE + var/datum/colosseum_modifier/beast_interlude/modifier = allocate(/datum/colosseum_modifier/beast_interlude) + modifier.controller = controller + modifier.spawn_wave(list(run_loc_floor_bottom_left), list(/mob/living/basic/mining/legion = 1)) + TEST_ASSERT_EQUAL(length(modifier.beasts), 1, "Arena wave lost its output") + var/mob/living/basic/mining/legion/beast = modifier.beasts[1] + TEST_ASSERT(beast.npc_zone_exempt && !beast.npc_zone_applied, "Colosseum beast received an environmental profile") + var/datum/action/cooldown/mob_cooldown/skull_launcher/launcher = beast.ai_controller.blackboard[BB_TARGETED_ACTION] + launcher.spawn_skull(run_loc_floor_top_right, null) + var/mob/living/basic/legion_brood/skull = locate() in run_loc_floor_top_right + TEST_ASSERT(skull.npc_zone_exempt && !skull.npc_zone_applied, "Arena beast descendants escaped exemption") + qdel(skull) + +/// Real wave methods use their deployed objective's source, not the player's mind. +/datum/unit_test/voidcrew_npc_zone_vestige_routes/Run() + var/turf/center = get_step(get_step(run_loc_floor_bottom_left, NORTH), EAST) + var/mob/living/carbon/human/keeper = allocate(/mob/living/carbon/human/consistent, center) + keeper.mind_initialize() + var/obj/item/vestige_blood_votive/votive = allocate(/obj/item/vestige_blood_votive, center) + votive.npc_spawn_context = allocate(/datum/npc_spawn_context, votive, 2) + var/datum/vestige_trial/vigil/vigil = allocate(/datum/vestige_trial/vigil, keeper.mind) + vigil.votive = votive + vigil.unfold(keeper) + TEST_ASSERT_EQUAL(length(vigil.clots), 3, "Cult fixture did not unfold its hostile pack") + for(var/mob/living/clot as anything in vigil.clots) + check_npc_zone_child(clot, votive.npc_spawn_context) + vigil.reset_rite() + var/obj/structure/vestige_dragon_egg/dragon = allocate(/obj/structure/vestige_dragon_egg, center) + dragon.npc_spawn_context = allocate(/datum/npc_spawn_context, dragon, 3) + dragon.assault_underway = TRUE + dragon.wave_pending = TRUE + dragon.wave_perch = pick(vestige_hunt_approaches(dragon, 4)) + dragon.unleash_wave() + TEST_ASSERT_EQUAL(length(dragon.brood), 2, "Dragon trial did not emit its wave") + for(var/mob/living/hunter as anything in dragon.brood.Copy()) + check_npc_zone_child(hunter, dragon.npc_spawn_context) + qdel(hunter) + var/obj/structure/vestige_comb_egg/comb = allocate(/obj/structure/vestige_comb_egg, center) + comb.npc_spawn_context = allocate(/datum/npc_spawn_context, comb, 2) + comb.assault_underway = TRUE + comb.squad_pending = TRUE + comb.squad_perch = pick(vestige_hunt_approaches(comb, 4, chew_resin = TRUE)) + comb.land_squad() + TEST_ASSERT_EQUAL(length(comb.chewers), 1, "Comb trial did not emit its first squad") + for(var/mob/living/chewer as anything in comb.chewers.Copy()) + check_npc_zone_child(chewer, comb.npc_spawn_context) + qdel(chewer) + var/obj/structure/vestige_tremor_line/line = allocate(/obj/structure/vestige_tremor_line, center) + line.npc_spawn_context = allocate(/datum/npc_spawn_context, line, 3) + var/datum/vestige_trial/loom_tremor/loom = allocate(/datum/vestige_trial/loom_tremor, keeper.mind) + loom.send_thief(line, keeper) + TEST_ASSERT_EQUAL(length(loom.thieves), 1, "Spider trial did not emit a thief") + for(var/mob/living/thief as anything in loom.thieves.Copy()) + check_npc_zone_child(thief, line.npc_spawn_context) + TEST_ASSERT_EQUAL(thief.ai_controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET], line, "Spider thief missed its target setup") + qdel(thief) + // Reward pets retain baseline stats even under an explicit hostile role. + var/datum/npc_spawn_context/pet_context = allocate(/datum/npc_spawn_context, src, 3, "boss") + var/mob/living/pet = spawn_npc_in_zone(/mob/living/basic/carp/pet/vestige_hatchling, center, pet_context) + allocated += pet + TEST_ASSERT(pet.npc_zone_exempt && !pet.npc_zone_applied, "Reward dragonet received a hostile profile") + +/datum/unit_test/voidcrew_npc_zone_player_spell_route/Run() + var/turf/center = get_step(get_step(run_loc_floor_bottom_left, NORTH), EAST) + var/mob/living/carbon/human/caster = allocate(/mob/living/carbon/human/consistent, center) + caster.mind_initialize() + var/datum/action/cooldown/spell/grave_mirage/spell = allocate(/datum/action/cooldown/spell/grave_mirage) + spell.Grant(caster) + spell.cast(caster) + TEST_ASSERT(length(spell.mirages) >= 1, "Player mirage spell produced no copies") + for(var/mob/living/mirage as anything in spell.mirages) + TEST_ASSERT(mirage.npc_zone_exempt && !mirage.npc_zone_applied, "Player mirage received an environmental profile") + TEST_ASSERT_EQUAL(mirage.maxHealth, initial(mirage.maxHealth), "Player mirage health was scaled") + TEST_ASSERT_EQUAL(mirage.npc_spawn_context.source_id, REF(caster), "Player mirage lost caster identity") + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent, get_step(caster, EAST)) + victim.stat = HARD_CRIT + var/obj/item/organ/legion_tumour/tumour = allocate(/obj/item/organ/legion_tumour) + TEST_ASSERT(tumour.try_apply(victim, caster), "Manual tumour fixture could not reach the infestation route") + // The victim starts beside the caster, and the infestation stays on the victim's tile. + var/mob/living/basic/mining/legion/infested = locate() in get_turf(victim) + TEST_ASSERT_NOTNULL(infested, "Manual tumour did not produce a legion") + TEST_ASSERT(infested.npc_zone_exempt && !infested.npc_zone_applied, "Player-applied infestation lost the player's exemption") + qdel(infested) From 6dd008f8a13a24b1b931274b4d83f09c7c4c6292 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:24:45 -0700 Subject: [PATCH 036/105] Mission rewards on the outpost contract board --- tgstation.dme | 3 + voidcrew/_DEFINES/trade.dm | 43 +-- voidcrew/modules/trade/outpost.dm | 10 +- voidcrew/modules/trade/outpost_missions.dm | 169 ++++++++-- voidcrew/modules/trade/outpost_quests.dm | 47 ++- voidcrew/modules/trade/shop.dm | 177 ++++------- .../trade/shop_catalog_black_market.dm | 12 - .../modules/trade/shop_catalog_general.dm | 6 - .../modules/trade/shop_catalog_outfitter.dm | 8 - .../modules/trade/shop_catalog_suit_vendor.dm | 23 +- voidcrew/modules/trade/trader_favor.dm | 12 +- voidcrew/modules/trade/trader_npc.dm | 28 +- voidcrew/modules/unit_tests/_unit_tests.dm | 1 + .../unit_tests/voidcrew_anomaly_rewards.dm | 12 +- .../unit_tests/voidcrew_launch_progression.dm | 22 +- .../voidcrew_mission_board_rewards.dm | 299 ++++++++++++++++++ .../unit_tests/voidcrew_shop_catalog.dm | 13 +- 17 files changed, 646 insertions(+), 239 deletions(-) create mode 100644 voidcrew/modules/unit_tests/voidcrew_mission_board_rewards.dm diff --git a/tgstation.dme b/tgstation.dme index 6329ed844de..5ddbace4c9c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7681,6 +7681,9 @@ #include "voidcrew\modules\transporter\transporter_designs.dm" #include "voidcrew\modules\transporter\transporter_pad.dm" #include "voidcrew\modules\transporter\transporter_transponder.dm" +#if defined(UNIT_TESTS) || defined(SPACEMAN_DMM) +#include "voidcrew\modules\unit_tests\voidcrew_mission_board_rewards.dm" +#endif #include "voidcrew\modules\vehicles\atv.dm" #include "voidcrew\modules\vending\_vending.dm" #include "voidcrew\modules\vending\security.dm" diff --git a/voidcrew/_DEFINES/trade.dm b/voidcrew/_DEFINES/trade.dm index 63779ab4e1b..db65d96346d 100644 --- a/voidcrew/_DEFINES/trade.dm +++ b/voidcrew/_DEFINES/trade.dm @@ -79,7 +79,7 @@ // Favor paid per completed board contract, by difficulty band #define FAVOR_GAIN_EASY 1 #define FAVOR_GAIN_MEDIUM 2 -#define FAVOR_GAIN_HARD 4 +#define FAVOR_GAIN_HARD 3 /// How many of each favor-shelf unique one crew may buy per round #define FAVOR_UNIQUE_CREW_LIMIT 3 @@ -88,23 +88,30 @@ #define OUTPOST_RESTOCK_INTERVAL (22 MINUTES) // ===== CONTRACT PAY BANDS ===== -// Outpost contracts settle in goods, not credits, so the bundle a contract pays -// has to be assembled to hit a credit-equivalent target. These are that target, -// in shop credits, per difficulty band. Anything below the EASY floor reads as -// an insult on the board, a 600cr box of shells for a 2000cr haul of cores was -// the bug these bands exist to prevent. -// These bands include travel and delivery work. Routine supplies can form a -// bundle, medium contracts fund a ship component, and hard ones add an exclusive. -#define CONTRACT_PAY_EASY_MIN 1400 -#define CONTRACT_PAY_EASY_MAX 2000 -#define CONTRACT_PAY_MEDIUM_MIN 2600 -#define CONTRACT_PAY_MEDIUM_MAX 3800 -#define CONTRACT_PAY_HARD_MIN 5500 -#define CONTRACT_PAY_HARD_MAX 8000 +// Total quote, before archetype multipliers and supply service ceilings. +#define CONTRACT_PAY_EASY_MIN 600 +#define CONTRACT_PAY_EASY_MAX 900 +#define CONTRACT_PAY_MEDIUM_MIN 1300 +#define CONTRACT_PAY_MEDIUM_MAX 1800 +#define CONTRACT_PAY_HARD_MIN 2400 +#define CONTRACT_PAY_HARD_MAX 3200 /// A contract must beat selling the same goods over the counter by this much, /// or accepting it is strictly worse than walking to the buyback window. -#define CONTRACT_ASK_PREMIUM 1.6 +#define CONTRACT_ASK_PREMIUM 1.15 + +#define CONTRACT_SERVICE_EASY 200 +#define CONTRACT_SERVICE_MEDIUM 350 +#define CONTRACT_SERVICE_HARD 500 +#define CONTRACT_EXCEPTION_MULT 0.4 +#define CONTRACT_EXCEPTION_PREMIUM 1.10 +#define CONTRACT_SHELF_SHARE 0.6 +#define CONTRACT_COURIER_DISTANCE_PAY 10 + +/// Shared board vacancies wait for the next scheduled refill. +#define OUTPOST_SHOP_OFFER_COUNT 4 +#define OUTPOST_CONTRACT_REFILL_INTERVAL (11 MINUTES) +#define OUTPOST_CONTRACT_EXPIRY (22 MINUTES) /// Imputed credit worth of one trade voucher, for valuing voucher-priced stock /// and for paying out a bundle's shortfall in scrip instead of money. @@ -113,11 +120,11 @@ /// Credit worth assumed for a back-room exclusive, which no shelf prices #define CONTRACT_EXCLUSIVE_VALUE 3600 -/// Shortfall below this is just rounding; above it, top the contract up in vouchers -#define CONTRACT_SHORTFALL_TOLERANCE 600 +/// Every quoted credit must be settled. +#define CONTRACT_SHORTFALL_TOLERANCE 0 /// Never hand over more than this many separate items for one contract -#define CONTRACT_MAX_REWARD_ITEMS 3 +#define CONTRACT_MAX_REWARD_ITEMS 2 /// Trait source for TRAIT_FOOD_CHEF_MADE on dishes sold over an outpost /// kitchen's counter (the Chowder Pot's plated shelves). Kept distinct from diff --git a/voidcrew/modules/trade/outpost.dm b/voidcrew/modules/trade/outpost.dm index 8b5c0b460d5..b6363c4be9a 100644 --- a/voidcrew/modules/trade/outpost.dm +++ b/voidcrew/modules/trade/outpost.dm @@ -89,6 +89,9 @@ GLOBAL_LIST_EMPTY(trader_outposts) var/list/obj/machinery/porta_turret/outpost/turrets = list() /// Looping timer id for the supply convoy restock var/restock_timer + /// Board clock is independent of visits, acceptance and the supply convoy. + var/next_contract_refill = 0 + var/contract_refill_timer /// A market, as against a crew's own colony. Both are "Outposts" on the readout. /obj/structure/overmap/trader_outpost/get_contact_variant() @@ -102,7 +105,9 @@ GLOBAL_LIST_EMPTY(trader_outposts) GLOB.trader_outposts += src berths = new /list(OUTPOST_MAX_BERTHS) ensure_main_shop() - restock_timer = addtimer(CALLBACK(src, PROC_REF(convoy_restock)), OUTPOST_RESTOCK_INTERVAL, TIMER_STOPPABLE | TIMER_LOOP) + ensure_shop_offers() + contract_refill_timer = addtimer(CALLBACK(src, PROC_REF(ensure_shop_offers)), OUTPOST_CONTRACT_REFILL_INTERVAL, TIMER_STOPPABLE | TIMER_LOOP | TIMER_DELETE_ME) + restock_timer = addtimer(CALLBACK(src, PROC_REF(convoy_restock)), OUTPOST_RESTOCK_INTERVAL, TIMER_STOPPABLE | TIMER_LOOP | TIMER_DELETE_ME) /** * Creates the main shop on first need. SSovermap spawns outposts and pre-loads @@ -119,6 +124,9 @@ GLOBAL_LIST_EMPTY(trader_outposts) return shop /obj/structure/overmap/trader_outpost/Destroy() + if(contract_refill_timer) + deltimer(contract_refill_timer) + contract_refill_timer = null if(restock_timer) deltimer(restock_timer) restock_timer = null diff --git a/voidcrew/modules/trade/outpost_missions.dm b/voidcrew/modules/trade/outpost_missions.dm index e9ee22306ac..936fea9b612 100644 --- a/voidcrew/modules/trade/outpost_missions.dm +++ b/voidcrew/modules/trade/outpost_missions.dm @@ -2,9 +2,7 @@ * # Outpost Supply Contracts * * The shop-specific mission loop: each trader outpost posts a couple of - * supply requests ("bring me X"), and the pay is a FREE ITEM off the shop's - * own shelves rather than credits. Gives a ship a reason to detour to an - * outpost even with empty pockets. + * supply requests with fixed packages and currency settlements. * * The player-facing side is the trader NPC's Contracts radial (see * trader_npc.dm). Wiring rides the existing mission pipeline end to end: @@ -13,9 +11,6 @@ * pad, where the reward item spawns exactly like voucher/item rewards do. */ -/// How many contracts an outpost keeps posted at once -#define OUTPOST_SHOP_OFFER_COUNT 4 - /// Exact request types; fish and bear hides are deliberate owner exceptions. /proc/is_outpost_procurement_type(item_type) var/static/list/eligible_types = list( @@ -28,7 +23,7 @@ /obj/item/stack/telecrystal_raw, /obj/item/organ/monster_core/regenerative_core/legion, /obj/item/stack/glacial_core, - // Eligibility only: suit-vendor rows still need reward-design inputs. + // Salvaged suit goods; module matching stays exact at handover. /obj/item/mod/construction/broken_core, /obj/item/mod/control/pre_equipped, /obj/item/mod/module/springlock, @@ -87,8 +82,7 @@ * # Outpost Supply Mission * * Delivery-style: haul the asked goods to your ship's mission pad or any - * trader. Pays no credits. The reward is one free item rolled off the - * posting shop's SKU list at creation time. + * trader. The package and currency quote are fixed at posting. */ /datum/mission/outpost_supply name = "Supply Request" @@ -101,6 +95,9 @@ var/required_type var/required_name var/required_amount = 1 + /// Optional fixed target band for recovered suit goods. + var/request_pay_min + var/request_pay_max /datum/mission/outpost_supply/get_archetype() return "procurement" @@ -115,12 +112,11 @@ if(generation_failed) return - // The pay: kit off the shelf, assembled to the difficulty band and floored - // by what the ask itself fetches at this trader's own buyback window. A - // contract for five glacial cores has to beat carrying those same cores - // twenty steps to the counter, or there is no reason to take it. - voucher_count = 0 - if(!shop.roll_contract_reward(src, shop.get_counter_value(required_type, required_amount))) + var/datum/outpost_shop/reward_shop = contract_reward_shop || shop + var/ask_value = reward_shop.get_counter_value(required_type, required_amount) + if(ispath(required_type, /obj/item/mod/module)) + ask_value = 250 * required_amount // Reference only; never a buyback. + if(!reward_shop.roll_contract_reward(src, ask_value)) generation_failed = TRUE /// Rolls the ask off the shop's request table. Override for themed asks. @@ -134,6 +130,12 @@ required_name = request["name"] required_amount = request["amount"] difficulty = request["difficulty"] + request_pay_min = request["pay_min"] + request_pay_max = request["pay_max"] + if(request["reward_shop"]) + contract_reward_shop = shop.type == request["reward_shop"] ? shop : shop.outpost?.get_shop(request["reward_shop"]) + if(!contract_reward_shop) + generation_failed = TRUE /datum/mission/outpost_supply/build_objectives() var/datum/mission_objective/deliver/procurement/ask = new @@ -154,8 +156,7 @@ * Bring a rod." * * A fish-shaped supply request posted only by outposts that actually run a - * fishing stall (see the shop's extra_offer_mix). Same goods-for-goods deal; - * trophy asks reach the exclusive shelf like any hard contract. + * fishing stall (see the shop's extra_offer_mix). */ /datum/mission/outpost_supply/angler /// Trophy gate in grams (0 = any fish) @@ -254,8 +255,13 @@ * folded in. Discards failed rolls (e.g. courier with no second outpost). */ /obj/structure/overmap/trader_outpost/proc/ensure_shop_offers() - if(!shop) + if(!shop || world.time < next_contract_refill) return + // Keep the original cadence if a visit beats a delayed timer callback. + if(!next_contract_refill) + next_contract_refill = world.time + OUTPOST_CONTRACT_REFILL_INTERVAL + else + next_contract_refill += (floor((world.time - next_contract_refill) / OUTPOST_CONTRACT_REFILL_INTERVAL) + 1) * OUTPOST_CONTRACT_REFILL_INTERVAL var/static/list/offer_mix = list( /datum/mission/outpost_supply = 40, /datum/mission/recovery/kill/outpost = 25, @@ -274,6 +280,10 @@ for(var/datum/mission/posted as anything in shop_offers.Copy()) if(QDELETED(posted)) shop_offers -= posted + else if(posted.failed || posted.completed || world.time - posted.posted_at >= OUTPOST_CONTRACT_EXPIRY) + shop_offers -= posted + tally_mission_offer(posted, null, "contract_offer_expired") + qdel(posted) var/safety = 12 while(length(shop_offers) < OUTPOST_SHOP_OFFER_COUNT && safety-- > 0) // Keep a plain supply request on the board only when its pool is eligible. @@ -321,4 +331,125 @@ count++ return count < limit -#undef OUTPOST_SHOP_OFFER_COUNT + +// ===== BOARD QUOTES AND SETTLEMENT ===== +// Shared shell hooks live here so both trader and ship-pad handovers use them. +/datum/mission + /// Total value, fixed at posting; null on work outside this reward channel. + var/contract_quote + var/contract_no_vouchers = FALSE + /// May be the fitter while shop remains the outfitter that receives favor. + var/datum/outpost_shop/contract_reward_shop + /// Quoted item path -> live core SKU and its fixed value. + var/list/contract_stock + var/list/contract_item_values + var/contract_stock_reserved = FALSE + var/contract_settled = FALSE + var/contract_turning_in = FALSE + +/datum/mission/proc/is_routine_contract() + if(!istype(src, /datum/mission/outpost_supply)) + return FALSE + var/datum/mission/outpost_supply/supply = src + return istype(src, /datum/mission/outpost_supply/cook) || istype(src, /datum/mission/outpost_supply/angler) \ + || supply.required_type == /obj/item/fish || supply.required_type == /obj/item/stack/sheet/animalhide/bear + +/// Set both bounds: the shell rolls value after generate_details(). +/datum/mission/proc/set_contract_currency(remainder) + voucher_count = contract_no_vouchers ? 0 : floor(remainder / VOUCHER_CREDIT_VALUE) + value = remainder - voucher_count * VOUCHER_CREDIT_VALUE + value_min = value + value_max = value + +/// No yields between checking and claiming stock. Lost shelf objects become currency. +/datum/mission/proc/reserve_contract_stock() + if(isnull(contract_quote) || contract_stock_reserved || contract_settled) + return + contract_stock_reserved = TRUE + var/package_value = 0 + for(var/item_path in contract_stock.Copy()) + var/datum/shop_sku/sku = contract_stock[item_path] + if(QDELETED(sku) || sku.stock <= 0) + contract_stock -= item_path + mission_rewards -= item_path + reward_amounts -= item_path + continue + sku.stock-- + sku.reserved_stock++ + package_value += contract_item_values[item_path] + metric_item_value = package_value + set_contract_currency(contract_quote - package_value) + +/// Completion consumes the hold; every other deletion releases it, once. +/datum/mission/proc/release_contract_stock(consumed = FALSE) + if(!contract_stock_reserved) + return + contract_stock_reserved = FALSE + for(var/item_path in contract_stock) + var/datum/shop_sku/sku = contract_stock[item_path] + if(QDELETED(sku)) + continue + sku.reserved_stock-- + if(!consumed) + sku.stock++ + +/datum/mission/start_mission(obj/structure/overmap/ship/ship) + if(shop || !isnull(contract_quote)) + if(QDELETED(src) || active || failed || completed || QDELETED(ship) || QDELETED(ship.ship_account)) + return FALSE + reserve_contract_stock() + . = ..() + if(!. && !QDELETED(src)) + release_contract_stock() + +/datum/mission/turn_in(atom/reward_anchor, obj/item/turned_in_item, force = FALSE) + if(shop || !isnull(contract_quote)) + if(QDELETED(src) || !active || failed || completed || contract_turning_in || QDELETED(servant) || QDELETED(servant.ship_account)) + return FALSE + if(!get_turf(reward_anchor) || !can_turn_in_at(reward_anchor)) + return FALSE + contract_turning_in = TRUE + . = ..() + contract_turning_in = FALSE + +/datum/mission/distribute_rewards(atom/reward_anchor) + if(!isnull(contract_quote)) + if(contract_settled) + return + contract_settled = TRUE + release_contract_stock(consumed = TRUE) + return ..() + +/datum/mission/Destroy() + shop?.outpost?.shop_offers -= src + release_contract_stock() + contract_reward_shop = null + contract_stock = null + contract_item_values = null + return ..() + +/datum/mission/get_contract_pay_summary() + var/list/parts = list() + if(length(get_reward_types())) + parts += get_reward_summary() + if(voucher_count > 0) + parts += "[voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]" + if(value > 0) + parts += "[value] cr" + return parts.Join(" + ") + +/// The fixed package may come from the fitter rather than the posting counter. +/datum/mission/note_metric_item_value() + if(!isnull(contract_quote)) + return // roll_contract_reward and acceptance track the actual reserved package. + return ..() + +/datum/mission/finish_mission(atom/reward_anchor) + if((shop || !isnull(contract_quote)) && (QDELETED(src) || !active || failed || completed || QDELETED(servant) || QDELETED(servant.ship_account) || !get_turf(reward_anchor))) + return + return ..() + +/datum/mission/get_reward_summary() + if(shop && !length(get_reward_types())) + return "" + return ..() diff --git a/voidcrew/modules/trade/outpost_quests.dm b/voidcrew/modules/trade/outpost_quests.dm index e4c6a94708f..cdce3076b67 100644 --- a/voidcrew/modules/trade/outpost_quests.dm +++ b/voidcrew/modules/trade/outpost_quests.dm @@ -11,7 +11,7 @@ * - Courier Run: haul a sealed freight pod to ANOTHER outpost; the pod * only unloads at its destination trader (piracy bait by design) * - * Hard contracts can roll the shop's exclusive_rewards. Items no shelf sells. + * Packages and currency are quoted when posted. */ // ===== SALVAGE ORDER (outpost-authored recovery) ===== @@ -19,7 +19,7 @@ /datum/mission/recovery/outpost weight = 0 // board-posted only mission_limit = 0 - contract_pay_mult = 1.25 // a run out to a ruin and back + contract_pay_mult = 1.15 /datum/mission/recovery/outpost/generate_details() if(!shop) @@ -27,7 +27,7 @@ return author = shop.trader_name ..() - // Board contracts pay in goods, not money. The open market covers credits/vouchers + // Replace the console reward with the fixed board quote. value = 0 value_min = 0 value_max = 0 @@ -36,12 +36,8 @@ generation_failed = TRUE /datum/mission/recovery/outpost/update_text() - var/reward_name = get_contract_pay_summary() name = "Salvage Order: [objective_name]" - desc = "[author] of [shop?.outpost_name || "the outpost"] is paying for the [objective_name] out at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - Deliver it to any outpost trader or your own mission pad. \ - Pays in kit, [reward_name], no credits changing hands. \ - Tap a GPS unit on a mission board to receive the objective's beacon ([gps_tag])." + desc = "[author] wants [objective_name] from ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/recovery/outpost/get_archetype() return "salvage" @@ -51,7 +47,7 @@ /datum/mission/recovery/kill/outpost weight = 0 mission_limit = 0 - contract_pay_mult = 1.5 // find a named boss at a hostile site and put it down + contract_pay_mult = 1.10 /datum/mission/recovery/kill/outpost/generate_details() if(!shop) @@ -59,21 +55,24 @@ return author = shop.trader_name ..() - // Board contracts pay in goods, not money. The open market covers credits/vouchers + // Replace the console reward with the fixed board quote. value = 0 value_min = 0 value_max = 0 voucher_count = 0 + switch(difficulty) + if(MISSION_DIFFICULTY_HARD) + contract_pay_mult = 0.55 + if(MISSION_DIFFICULTY_MEDIUM) + contract_pay_mult = 0.95 + else + contract_pay_mult = 1.10 if(!shop.roll_contract_reward(src)) generation_failed = TRUE /datum/mission/recovery/kill/outpost/update_text() - var/reward_name = get_contract_pay_summary() name = "Kill Contract: [objective_name]" - desc = "[author] of [shop?.outpost_name || "the outpost"] wants [objective_name] gone, holed up at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - Bring the identification tag to any outpost trader or your own mission pad. \ - Pays in goods, [reward_name], settled on delivery. \ - Tap a GPS unit on a mission board for the target's transponder ([gps_tag])." + desc = "[author] wants [objective_name] dead. Last seen at ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/recovery/kill/outpost/get_archetype() return "bounty" @@ -86,7 +85,7 @@ duration = 35 MINUTES value_min = 0 value_max = 0 - contract_pay_mult = 1.3 // a long haul across the lanes, and pirates know the pod + contract_pay_mult = 1.10 quest_lost_policy = MISSION_QUEST_LOST_FAIL // pod destroyed = contract void /// The pod-delivery objective (holds the live pod) @@ -112,7 +111,7 @@ /datum/mission/outpost_courier/generate_details() author = shop.trader_name - // Board contracts pay in goods, not money + // Quote the fixed board package and currency. voucher_count = 0 if(!shop.roll_contract_reward(src)) generation_failed = TRUE @@ -127,13 +126,9 @@ return istype(destination) ? destination.outpost : null /datum/mission/outpost_courier/update_text() - var/reward_name = get_contract_pay_summary() var/obj/structure/overmap/trader_outpost/destination = get_destination() name = "Courier Run: [destination?.name || "lost destination"]" - desc = "[author] needs a sealed freight pod hauled to [destination?.name || "its destination"] at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - Collect the pod beside [author] when you accept. \ - The pod's seals only release at the destination's trader, and every pirate on the lane knows what a courier pod looks like. \ - Pays in kit on delivery: [reward_name]." + desc = "Freight for [destination?.name || "its destination"] at ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/outpost_courier/waypoint_label() var/obj/structure/overmap/trader_outpost/destination = get_destination() @@ -164,11 +159,11 @@ if(!istype(reward_anchor, /mob/living/basic/outpost_trader)) return FALSE var/mob/living/basic/outpost_trader/npc = reward_anchor - return npc.outpost == get_destination() + return npc.outpost == get_destination() && npc.outpost?.contains_site_turf(get_turf(npc)) /datum/mission/outpost_courier/get_wrong_location_reason(atom/reward_anchor) var/obj/structure/overmap/trader_outpost/destination = get_destination() - return "The pod's seals only release at [destination?.name || "its destination"]'s trader." + return "Shipment for [destination?.name || "its destination"]." /** * # Courier Pod Objective @@ -224,7 +219,7 @@ */ /obj/item/freight_pod name = "sealed freight pod" - desc = "A tamper-sealed courier pod, bonded and manifest-locked. The seals only release at its destination outpost's contract board." + desc = "A tamper-sealed courier pod with a bonded manifest." icon = 'voidcrew/modules/trade/icons/trade.dmi' icon_state = "freight_pod" inhand_icon_state = "freight_pod" @@ -242,6 +237,6 @@ var/datum/mission/outpost_courier/mission = mission_ref?.resolve() if(istype(mission) && !mission.failed && !mission.completed) var/obj/structure/overmap/trader_outpost/destination = mission.get_destination() - . += span_notice("The manifest reads: deliver to [destination?.name || "unknown"]. Whoever hands it over gets paid.") + . += span_notice("The manifest reads: deliver to [destination?.name || "unknown"].") else . += span_warning("Its contract has lapsed; the seals will never release.") diff --git a/voidcrew/modules/trade/shop.dm b/voidcrew/modules/trade/shop.dm index 5daacd89121..73f0aa9c589 100644 --- a/voidcrew/modules/trade/shop.dm +++ b/voidcrew/modules/trade/shop.dm @@ -90,9 +90,7 @@ /// Supply request table for the outpost mission board: list of /// list("type" = path, "name" = text, "amount" = num, "difficulty" = MISSION_DIFFICULTY_*) var/list/mission_requests = list() - /// Items only ever awarded by this shop's hard contracts, never sold on - /// any shelf. The depth hook: chasing the trader's board is the sole road - /// to these. + /// Legacy catalog field; automatic board draws are disabled. var/list/exclusive_rewards = list() /// Extra contract types this shop's board can post beyond the standard /// mix, as typepath -> weight (the general outpost's angling requests) @@ -239,8 +237,8 @@ /datum/outpost_shop/proc/convoy_restock() // Core shelves creep back toward full for(var/datum/shop_sku/sku as anything in skus) - if(sku.shelf == SHELF_CORE && sku.stock < sku.stock_max) - sku.stock = min(sku.stock_max, sku.stock + max(1, round(sku.stock_max / 2))) + if(sku.shelf == SHELF_CORE && sku.stock < sku.stock_max - sku.reserved_stock) + sku.stock = min(sku.stock_max - sku.reserved_stock, sku.stock + max(1, round(sku.stock_max / 2))) // A new paid chart creates a fresh ruin, so named tips can be sold again. else if(istype(sku, /datum/shop_sku/ruin_chart) && sku.stock < sku.stock_max) sku.stock = sku.stock_max @@ -304,125 +302,88 @@ return round(per_sale * amount / max(1, buyback.amount)) return 0 -/** - * Assigns the item bundle an outpost-board contract pays out, drawn from this - * shop's own stock. These contracts settle in goods rather than money, so the - * bundle IS the pay and has to be assembled to hit a credit-equivalent target - * instead of picked at random. A flat draw over the shelves hands out a 30cr - * can of beans and a 4800cr engine board with exactly equal probability. - * - * The target comes from the difficulty band, floored by what the contracted - * goods are worth over this shop's own counter, so accepting a job is never - * worse than selling the haul at the buyback window. - * - * Hard contracts lead with a back-room exclusive no shelf sells. Whatever the - * shelves can't cover is settled in trade vouchers, which keeps the "paid in - * kit, not cash" premise intact while still landing the pay in band when the - * shop has been picked over. - * - * Returns FALSE only if the shop has no priced stock at all, so the caller can - * discard an unfundable contract. - * * ask_value - credits the contracted goods fetch over the counter, if known - */ +/// Build a fixed quote. Only available, credit-priced core stock can form its package. /datum/outpost_shop/proc/roll_contract_reward(datum/mission/mission, ask_value = 0) - // The shelves, valued. Assoc so the bundle builder can price a candidate - // without walking the SKU list again for every draw. - var/list/valued = list() - // Bundled stack sizes, so a contract paying "plasteel (10 sheets)" hands - // over ten sheets rather than the one a bare stack spawn would give - var/list/bundle_sizes = list() - for(var/datum/shop_sku/sku as anything in skus) - if(!sku.item_path) - continue - // Favor uniques are earned standing at the counter, never rolled into a - // contract's pay bundle, that would leak the back room past its gate - if(sku.shelf == SHELF_FAVOR) - continue - // Scarce stock (anomaly cores) is sold over the counter only - if(!sku.contract_reward) - continue - var/worth = get_sku_value(sku) - if(worth <= 0) - continue - valued[sku.item_path] = worth - if(sku.dispense_amount > 1) - bundle_sizes[sku.item_path] = sku.dispense_amount - if(!length(valued)) + if(QDELETED(mission)) return FALSE - - var/target + if(!isnull(mission.contract_quote)) + return TRUE // Reopening or retargeting cannot reroll an existing quote. + var/band + var/service switch(mission.difficulty) if(MISSION_DIFFICULTY_HARD) - target = rand(CONTRACT_PAY_HARD_MIN, CONTRACT_PAY_HARD_MAX) + band = rand(CONTRACT_PAY_HARD_MIN, CONTRACT_PAY_HARD_MAX) + service = CONTRACT_SERVICE_HARD if(MISSION_DIFFICULTY_MEDIUM) - target = rand(CONTRACT_PAY_MEDIUM_MIN, CONTRACT_PAY_MEDIUM_MAX) + band = rand(CONTRACT_PAY_MEDIUM_MIN, CONTRACT_PAY_MEDIUM_MAX) + service = CONTRACT_SERVICE_MEDIUM else - target = rand(CONTRACT_PAY_EASY_MIN, CONTRACT_PAY_EASY_MAX) - target = round(target * mission.contract_pay_mult) - target = max(target, round(ask_value * CONTRACT_ASK_PREMIUM)) - - var/list/rewards = list() - var/list/rare_rewards = list() - var/remaining = target - - // Hard contracts open the back room, and that prize covers most of the target - if(mission.difficulty == MISSION_DIFFICULTY_HARD && length(exclusive_rewards)) - var/prize = pick(exclusive_rewards) - rewards += prize - rare_rewards += prize - remaining -= CONTRACT_EXCLUSIVE_VALUE - - // Spend the rest down in as few items as possible, so the pay reads as one - // good piece of kit instead of a heap of consumables - while(remaining > CONTRACT_SHORTFALL_TOLERANCE && length(rewards) < CONTRACT_MAX_REWARD_ITEMS) - var/picked = pick_valued_reward(valued, remaining) - if(!picked) + band = rand(CONTRACT_PAY_EASY_MIN, CONTRACT_PAY_EASY_MAX) + service = CONTRACT_SERVICE_EASY + var/target = floor(band * mission.contract_pay_mult) + mission.contract_no_vouchers = mission.is_routine_contract() + if(istype(mission, /datum/mission/outpost_supply)) + var/datum/mission/outpost_supply/supply = mission + if(supply.request_pay_min) + target = rand(supply.request_pay_min, supply.request_pay_max) + if(mission.contract_no_vouchers) + target = max(CEILING(ask_value * CONTRACT_EXCEPTION_PREMIUM, 1), min(floor(band * CONTRACT_EXCEPTION_MULT), service)) + else + target = max(CEILING(ask_value * CONTRACT_ASK_PREMIUM, 1), min(target, ask_value + service)) + else if(istype(mission, /datum/mission/outpost_courier)) + var/datum/mission/outpost_courier/courier = mission + var/obj/structure/overmap/trader_outpost/destination = courier.get_destination() + if(!outpost || !destination) + return FALSE + target = min(target, CONTRACT_COURIER_DISTANCE_PAY * max(abs(outpost.x - destination.x), abs(outpost.y - destination.y))) + + mission.contract_quote = target + mission.contract_reward_shop = src + mission.mission_reward = null + mission.mission_rewards = list() + mission.rare_reward_types = null + mission.reward_amounts = list() + mission.contract_stock = list() + mission.contract_item_values = list() + var/list/valued = list() + var/list/stock_by_path = list() + for(var/datum/shop_sku/sku as anything in skus) + if(!sku.item_path || sku.shelf != SHELF_CORE || !sku.contract_reward || sku.stock <= 0) + continue + if(sku.price_credits <= 0 || sku.price_vouchers > 0 || istype(sku, /datum/shop_sku/barter)) + continue + valued[sku.item_path] = sku.price_credits + stock_by_path[sku.item_path] = sku + var/package_value = 0 + var/budget = floor(target * CONTRACT_SHELF_SHARE) + while(length(mission.mission_rewards) < CONTRACT_MAX_REWARD_ITEMS) + var/item_path = pick_valued_reward(valued, budget - package_value) + if(!item_path) break - rewards += picked - remaining -= valued[picked] - if(bundle_sizes[picked]) - LAZYSET(mission.reward_amounts, picked, bundle_sizes[picked]) - valued -= picked // one of each; a bundle of three identical items reads as filler - - if(!length(rewards)) - return FALSE - - mission.mission_rewards = rewards - mission.rare_reward_types = rare_rewards - // Settle the gap in scrip rather than posting a contract that misses its band - if(remaining > CONTRACT_SHORTFALL_TOLERANCE) - mission.voucher_count += CEILING((remaining - CONTRACT_SHORTFALL_TOLERANCE) / VOUCHER_CREDIT_VALUE, 1) + var/datum/shop_sku/sku = stock_by_path[item_path] + mission.mission_rewards += item_path + mission.contract_stock[item_path] = sku + mission.contract_item_values[item_path] = valued[item_path] + mission.reward_amounts[item_path] = sku.dispense_amount + package_value += valued[item_path] + valued -= item_path + mission.metric_item_value = package_value + mission.set_contract_currency(target - package_value) return TRUE -/** - * Draws one item from a valued pool, preferring the dearest thing that still - * fits the budget so a bundle spends itself down in few, good items. Randomises - * across the top of the affordable range so boards don't repeat the same item - * every round, and falls back to the cheapest thing in stock when the budget - * won't cover anything, so a thin shop still pays something. - */ +/// Prefer the upper end of the affordable range, with no overshoot or fallback. /datum/outpost_shop/proc/pick_valued_reward(list/valued, budget) - if(!length(valued)) - return null - // A little overshoot allowance, so a 2000cr budget lands the 2400cr item - // rather than falling all the way back to a 600cr one - var/ceiling = round(budget * 1.25) var/best = 0 for(var/item_path in valued) - if(valued[item_path] <= ceiling) + if(valued[item_path] <= budget) best = max(best, valued[item_path]) if(!best) - // Everything is over budget; take the cheapest thing on the shelf - var/cheapest - for(var/item_path in valued) - if(!cheapest || valued[item_path] < valued[cheapest]) - cheapest = item_path - return cheapest + return null var/list/contenders = list() for(var/item_path in valued) - if(valued[item_path] <= ceiling && valued[item_path] >= best * 0.6) + if(valued[item_path] <= budget && valued[item_path] >= best * 0.6) contenders += item_path - return length(contenders) ? pick(contenders) : null + return pick(contenders) /** * Returns a random personality line for the given TRADER_LINE_* category. @@ -474,6 +435,8 @@ var/stock_max = 4 /// Remaining stock this round var/stock = 0 + /// Units held for accepted board contracts, excluded from the sellable stock. + var/reserved_stock = 0 /// Author override when the item's initial icon renders wrong in the UI (GAGS etc.) var/icon_override var/icon_state_override diff --git a/voidcrew/modules/trade/shop_catalog_black_market.dm b/voidcrew/modules/trade/shop_catalog_black_market.dm index 9bc21c2ad36..1d4c73bee23 100644 --- a/voidcrew/modules/trade/shop_catalog_black_market.dm +++ b/voidcrew/modules/trade/shop_catalog_black_market.dm @@ -172,18 +172,6 @@ list("type" = /obj/item/stack/telecrystal_raw, "name" = "raw telecrystal", "amount" = 10, "difficulty" = MISSION_DIFFICULTY_HARD), list("type" = /obj/item/organ/monster_core/regenerative_core/legion, "name" = "legion core", "amount" = 1, "difficulty" = MISSION_DIFFICULTY_HARD), ) - // The back shelf: hard contracts only, never sold. Each of these is the top - // of a ladder Vex otherwise stops short of, the elite suit above the - // syndicate one, the Spider Clan chassis above that, and the one combat - // board that is on no shelf anywhere. - exclusive_rewards = list( - /obj/item/mod/control/pre_equipped/traitor_elite, - /obj/item/mod/control/pre_equipped/empty/ninja, - /obj/item/circuitboard/machine/ship_combat/cloak_device, - // The one piece of chrome Splice can't get: a prototype drop-leg frame - // that never reached his supplier. Hard contracts only. - /obj/item/organ/cyberimp/cyberware/piledriver, - ) trader_lines = list( TRADER_LINE_GREETING = list( "Welcome to the Undertow. Touch nothing you can't pay for.", diff --git a/voidcrew/modules/trade/shop_catalog_general.dm b/voidcrew/modules/trade/shop_catalog_general.dm index 44923bb2990..c795c0b01b7 100644 --- a/voidcrew/modules/trade/shop_catalog_general.dm +++ b/voidcrew/modules/trade/shop_catalog_general.dm @@ -168,12 +168,6 @@ list("type" = /obj/item/stack/spice_pods, "name" = "wild spice pods", "amount" = 6, "difficulty" = MISSION_DIFFICULTY_MEDIUM), list("type" = /obj/item/sea_crystal, "name" = "sea crystal", "amount" = 1, "difficulty" = MISSION_DIFFICULTY_HARD), ) - // Under the counter: hard contracts only, never sold - exclusive_rewards = list( - /obj/item/storage/bag/ore/holding, - /obj/item/fishing_rod/telescopic/master, - /obj/item/pickaxe/drill/jackhammer, - ) trader_lines = list( TRADER_LINE_GREETING = list( "Welcome to Halcyon! Mind the gift shop on your way out. We are the gift shop.", diff --git a/voidcrew/modules/trade/shop_catalog_outfitter.dm b/voidcrew/modules/trade/shop_catalog_outfitter.dm index a09f1db34f8..d0b546e0860 100644 --- a/voidcrew/modules/trade/shop_catalog_outfitter.dm +++ b/voidcrew/modules/trade/shop_catalog_outfitter.dm @@ -167,14 +167,6 @@ list("type" = /obj/item/stack/sheet/sinew, "name" = "beast sinew", "amount" = 4, "difficulty" = MISSION_DIFFICULTY_MEDIUM), list("type" = /obj/item/stack/glacial_core, "name" = "glacial cores", "amount" = 5, "difficulty" = MISSION_DIFFICULTY_MEDIUM), ) - // The armory back room: hard contracts only, never sold. Everything here has - // to be unobtainable elsewhere, so no item that drops in a zone loot theme - // and nothing that appears on the Ship Systems shelf. - exclusive_rewards = list( - /obj/item/circuitboard/machine/ship_combat/missile_launcher, - /obj/item/circuitboard/machine/engine/void, - /obj/item/gun/energy/laser/captain, - ) trader_lines = list( TRADER_LINE_GREETING = list( "Quartermain Depot. State your needs, keep your sidearm holstered.", diff --git a/voidcrew/modules/trade/shop_catalog_suit_vendor.dm b/voidcrew/modules/trade/shop_catalog_suit_vendor.dm index 8f46a1e5647..1c9215ac77a 100644 --- a/voidcrew/modules/trade/shop_catalog_suit_vendor.dm +++ b/voidcrew/modules/trade/shop_catalog_suit_vendor.dm @@ -197,15 +197,14 @@ /datum/shop_buyback/fitter/salvage_spacesuit, /datum/shop_buyback/fitter/salvage_space_helmet, ) - // Salvage requests await quantities and difficulties from the reward design. - mission_requests = list() - // Never on a shelf: two chassis Nakamura doesn't retail, and the two - // anomaly modules that come with their core already seated - exclusive_rewards = list( - /obj/item/mod/control/pre_equipped/magnate, - /obj/item/mod/control/pre_equipped/safeguard, - /obj/item/mod/module/anomaly_locked/kinesis/prebuilt/locked, - /obj/item/mod/module/anomaly_locked/teleporter/prebuilt/locked, + // These requests share Sarge's board; Wick supplies the quoted package. + mission_requests = list( + list("type" = /obj/item/mod/construction/broken_core, "name" = "Recovered MOD cores", "amount" = 2, "difficulty" = MISSION_DIFFICULTY_EASY, "pay_min" = 600, "pay_max" = 700, "reward_shop" = /datum/outpost_shop/vendor/suit_fitter), + list("type" = /obj/item/mod/control/pre_equipped, "name" = "Salvaged MOD control unit", "amount" = 1, "difficulty" = MISSION_DIFFICULTY_MEDIUM, "pay_min" = 850, "pay_max" = 850, "reward_shop" = /datum/outpost_shop/vendor/suit_fitter), + list("type" = /obj/item/mod/module/springlock, "name" = "Recovered springlock module", "amount" = 1, "difficulty" = MISSION_DIFFICULTY_MEDIUM, "pay_min" = 600, "pay_max" = 600, "reward_shop" = /datum/outpost_shop/vendor/suit_fitter), + list("type" = /obj/item/mod/module/visor/rave, "name" = "Recovered rave visor", "amount" = 1, "difficulty" = MISSION_DIFFICULTY_MEDIUM, "pay_min" = 600, "pay_max" = 600, "reward_shop" = /datum/outpost_shop/vendor/suit_fitter), + list("type" = /obj/item/mod/module/balloon, "name" = "Recovered balloon module", "amount" = 1, "difficulty" = MISSION_DIFFICULTY_MEDIUM, "pay_min" = 600, "pay_max" = 600, "reward_shop" = /datum/outpost_shop/vendor/suit_fitter), + list("type" = /obj/item/mod/module/stamp, "name" = "Recovered stamp module", "amount" = 1, "difficulty" = MISSION_DIFFICULTY_MEDIUM, "pay_min" = 600, "pay_max" = 600, "reward_shop" = /datum/outpost_shop/vendor/suit_fitter), ) trader_lines = list( TRADER_LINE_SALE = list( @@ -947,3 +946,9 @@ pay_credits = 20 demand_min = 3 demand_max = 5 + +/// One ordinary request pool gives all nine asks equal weight in the existing slots. +/datum/outpost_shop/outfitter/New(obj/structure/overmap/trader_outpost/outpost) + . = ..() + var/datum/outpost_shop/vendor/suit_fitter/fitter_type = /datum/outpost_shop/vendor/suit_fitter + mission_requests = mission_requests + initial(fitter_type.mission_requests) diff --git a/voidcrew/modules/trade/trader_favor.dm b/voidcrew/modules/trade/trader_favor.dm index 9a6a7860412..c93f78d3ddc 100644 --- a/voidcrew/modules/trade/trader_favor.dm +++ b/voidcrew/modules/trade/trader_favor.dm @@ -98,15 +98,7 @@ var/new_tier = get_favor_tier(crew_ship) if(new_tier <= old_tier) return - var/perk_text - switch(new_tier) - if(3) - perk_text = "[FAVOR_DISCOUNT_TRUSTED]% off credit prices, and the back-room shelf is open to your crew." - if(2) - perk_text = "[FAVOR_DISCOUNT_PARTNER]% off credit prices." - else - perk_text = "[FAVOR_DISCOUNT_REGULAR]% off credit prices." - crew_ship.ship_notify("[favor_trader_name()] now counts your crew as [LOWER_TEXT(get_favor_tier_name(new_tier))]: [perk_text]", \ + crew_ship.ship_notify("[favor_trader_name()] now counts your crew as [LOWER_TEXT(get_favor_tier_name(new_tier))].", \ "TRADER STANDING", SHIP_NOTIFY_NOTICE, 'voidcrew/sound/notify.ogg', 50) /// How many units of `sku_type` this crew has bought off the favor shelf @@ -136,6 +128,8 @@ /datum/mission/proc/get_favor_reward() if(!shop) return 0 + if(is_routine_contract()) + return FAVOR_GAIN_EASY switch(difficulty) if(MISSION_DIFFICULTY_HARD) return FAVOR_GAIN_HARD diff --git a/voidcrew/modules/trade/trader_npc.dm b/voidcrew/modules/trade/trader_npc.dm index 04d13058640..6f6a4369c5c 100644 --- a/voidcrew/modules/trade/trader_npc.dm +++ b/voidcrew/modules/trade/trader_npc.dm @@ -120,7 +120,7 @@ /mob/living/basic/outpost_trader/examine(mob/user) . = ..() if(shop) - . += span_notice("[name] runs the counter at [shop.outpost_name]. Click them from anywhere along the counter to do business.") + . += span_notice("[name] runs the counter at [shop.outpost_name].") if(outpost?.is_user_barred(user)) . += span_warning("[name] is pointedly ignoring you.") @@ -490,7 +490,9 @@ GLOBAL_DATUM_INIT(trader_counter_state, /datum/ui_state/trader_counter, new) var/mob/living/user = ui.user var/datum/outpost_shop/shop = npc.shop - if(!istype(user) || !shop) + if(!istype(user) || !shop || !npc.check_menu(user)) + return + if(npc.outpost && !npc.outpost.contains_site_turf(get_turf(npc))) return switch(action) @@ -604,6 +606,7 @@ GLOBAL_DATUM_INIT(trader_counter_state, /datum/ui_state/trader_counter, new) if(QDELETED(offer)) continue var/list/offer_data = offer.get_ui_data() + offer_data["quote_value"] = offer.contract_quote offer_data["wanted_text"] = offer.get_progress_string() offers += list(offer_data) data["offers"] = offers @@ -617,6 +620,7 @@ GLOBAL_DATUM_INIT(trader_counter_state, /datum/ui_state/trader_counter, new) if(QDELETED(mission)) continue var/list/mission_data = mission.get_ui_data() + mission_data["quote_value"] = mission.contract_quote mission_data["from_this_shop"] = (mission.shop == outpost?.shop) var/location_ok = mission.can_turn_in_at(npc) mission_data["location_ok"] = location_ok @@ -631,7 +635,7 @@ GLOBAL_DATUM_INIT(trader_counter_state, /datum/ui_state/trader_counter, new) else if(!location_ok) turn_in_hint = mission.get_wrong_location_reason(npc) else if(!holding_valid) - turn_in_hint = offered ? mission.get_failure_reason(offered) : "Hold the contract goods in hand." + turn_in_hint = offered ? mission.get_failure_reason(offered) : "Shipment declined." mission_data["turn_in_hint"] = turn_in_hint ship_missions += list(mission_data) data["ship_missions"] = ship_missions @@ -645,7 +649,7 @@ GLOBAL_DATUM_INIT(trader_counter_state, /datum/ui_state/trader_counter, new) var/mob/living/user = ui.user var/obj/structure/overmap/trader_outpost/outpost = npc.outpost - if(!istype(user) || !outpost?.shop) + if(!istype(user) || !outpost?.shop || !npc.can_use_contracts(user)) return switch(action) @@ -659,8 +663,8 @@ GLOBAL_DATUM_INIT(trader_counter_state, /datum/ui_state/trader_counter, new) npc.balloon_alert(user, "you have no ship!") return TRUE var/datum/mission/offer = locate(params["ref"]) in outpost.shop_offers - if(!offer || QDELETED(offer)) - npc.balloon_alert(user, "offer no longer posted!") + if(!offer || QDELETED(offer) || offer.active || offer.failed || offer.completed || world.time - offer.posted_at >= OUTPOST_CONTRACT_EXPIRY) + npc.balloon_alert(user, "offer closed!") return TRUE // Ride the standard accept path so limits/bookkeeping all apply @@ -673,7 +677,6 @@ GLOBAL_DATUM_INIT(trader_counter_state, /datum/ui_state/trader_counter, new) return TRUE outpost.shop_offers -= offer - outpost.ensure_shop_offers() npc.balloon_alert(user, "contract accepted!") playsound(npc, 'sound/machines/ding.ogg', 50, TRUE) npc.speak_line(TRADER_LINE_GREETING) @@ -706,6 +709,17 @@ GLOBAL_DATUM_INIT(trader_counter_state, /datum/ui_state/trader_counter, new) npc.speak_line(TRADER_LINE_SALE) return TRUE +/// Stale UI actions must still originate from a crew member at the actual counter. +/mob/living/basic/outpost_trader/proc/can_use_contracts(mob/living/user) + if(!check_menu(user) || QDELETED(outpost) || outpost.trader != src || shop != outpost.shop) + return FALSE + if(!outpost.contains_site_turf(get_turf(src))) + return FALSE + if(!get_crew_ship(user)) + to_chat(user, span_warning("Crew access only.")) + return FALSE + return TRUE + #undef TRADER_COUNTER_RANGE #undef TRADER_NPC_OPTION_TRADE #undef TRADER_NPC_OPTION_TALK diff --git a/voidcrew/modules/unit_tests/_unit_tests.dm b/voidcrew/modules/unit_tests/_unit_tests.dm index 3df6df06e1a..7cbd5720c90 100644 --- a/voidcrew/modules/unit_tests/_unit_tests.dm +++ b/voidcrew/modules/unit_tests/_unit_tests.dm @@ -98,6 +98,7 @@ #include "voidcrew_megafauna_aggro.dm" #include "voidcrew_mining_input.dm" #include "voidcrew_mining_qol.dm" +#include "voidcrew_mission_board_rewards.dm" #include "voidcrew_mission_gps.dm" #include "voidcrew_mission_metrics.dm" #include "voidcrew_missions.dm" diff --git a/voidcrew/modules/unit_tests/voidcrew_anomaly_rewards.dm b/voidcrew/modules/unit_tests/voidcrew_anomaly_rewards.dm index c12e849133c..29d44de399d 100644 --- a/voidcrew/modules/unit_tests/voidcrew_anomaly_rewards.dm +++ b/voidcrew/modules/unit_tests/voidcrew_anomaly_rewards.dm @@ -191,13 +191,15 @@ /// Catalog entries supply functioning modules whose seated cores resist the real tool path. /datum/unit_test/voidcrew_anomaly_rewards/trader_modules/Run() var/datum/outpost_shop/vendor/suit_fitter/shop = allocate(/datum/outpost_shop/vendor/suit_fitter) - var/list/module_types = list() - for(var/reward in shop.exclusive_rewards) - if(ispath(reward, /obj/item/mod/module/anomaly_locked)) - module_types += reward + // Automatic Hard-board draws are gone; verify the former prize types stay locked. + TEST_ASSERT_EQUAL(length(shop.exclusive_rewards), 0, "The fitter retained an automatic exclusive pool") + var/list/module_types = list( + /obj/item/mod/module/anomaly_locked/kinesis/prebuilt/locked, + /obj/item/mod/module/anomaly_locked/teleporter/prebuilt/locked, + ) var/datum/shop_sku/fitter/rare/mod_antigrav/sku = allocate(/datum/shop_sku/fitter/rare/mod_antigrav) module_types += sku.item_path - TEST_ASSERT_EQUAL(length(module_types), 3, "The fitter no longer offers all three anomaly modules") + TEST_ASSERT_EQUAL(length(module_types), 3, "The locked anomaly module coverage changed") TEST_ASSERT(/obj/item/mod/module/anomaly_locked/kinesis/prebuilt/locked in module_types, "The kinesis reward is not locked") TEST_ASSERT(/obj/item/mod/module/anomaly_locked/teleporter/prebuilt/locked in module_types, "The teleporter reward is not locked") TEST_ASSERT(/obj/item/mod/module/anomaly_locked/antigrav/prebuilt/locked in module_types, "The anti-gravity SKU is not locked") diff --git a/voidcrew/modules/unit_tests/voidcrew_launch_progression.dm b/voidcrew/modules/unit_tests/voidcrew_launch_progression.dm index 8b955637b10..b9953bad6d1 100644 --- a/voidcrew/modules/unit_tests/voidcrew_launch_progression.dm +++ b/voidcrew/modules/unit_tests/voidcrew_launch_progression.dm @@ -185,16 +185,16 @@ TEST_ASSERT_EQUAL(length(first.deal_chart_picks()), 1, "First shop could not deal its chart") TEST_ASSERT_EQUAL(length(second.deal_chart_picks()), 1, "First shop reserved the second shop's chart") -/// A sparse reward pool must meet the actual ask premium within600cr tolerance. +/// A sparse reward pool must settle its fixed quote exactly. /datum/unit_test/voidcrew_launch_thin_contract/Run() var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) shop.add_sku(/datum/shop_sku/general/beans, "core") - var/datum/mission/mission = allocate(/datum/mission) + var/datum/mission/outpost_supply/mission = allocate(/datum/mission/outpost_supply) mission.difficulty = 1 TEST_ASSERT(shop.roll_contract_reward(mission, 12000), "A thin priced catalog must still fund its contract") var/datum/shop_sku/sku = shop.skus[1] - var/value = shop.get_sku_value(sku) + mission.voucher_count * 1200 - TEST_ASSERT(value >= 12000 * 1.6 - 600, "Sparse rewards fell below the actual ask premium after voucher rounding") + var/value = shop.get_sku_value(sku) + mission.voucher_count * 1200 + mission.value + TEST_ASSERT_EQUAL(value, 13800, "Sparse rewards must settle the 1.15 ask premium exactly") TEST_ASSERT_EQUAL(length(mission.mission_rewards), 1, "Thin reward generation duplicated the same item") /// Repeated purchases use real payment, stock and crew lookup, even with a sealed copy. @@ -250,7 +250,8 @@ TEST_FAIL("[shop_type] cannot fund a [difficulty] contract") qdel(mission) continue - var/value = mission.voucher_count * 1200 + var/value = mission.voucher_count * 1200 + mission.value + TEST_ASSERT_EQUAL(length(mission.mission_rewards), 0, "Depleted shelves must pay currency") for(var/item_type in mission.mission_rewards) if(item_type in mission.rare_reward_types) value += 3600 @@ -262,12 +263,13 @@ if(sku.dispense_amount > 1 && mission.reward_amounts?[item_type] != sku.dispense_amount) TEST_FAIL("[shop_type] awards the wrong quantity of [item_type]") break - var/minimum = 1400 + var/minimum = 600 if(difficulty == 2) - minimum = 2600 + minimum = 1300 else if(difficulty == 3) - minimum = 5500 - if(value < minimum - 600) - TEST_FAIL("[shop_type] pays [value] against minimum [minimum] with tolerance [600]") + minimum = 2400 + if(value < minimum) + TEST_FAIL("[shop_type] pays [value] against minimum [minimum]") + TEST_ASSERT_EQUAL(value, mission.contract_quote, "Currency must exactly meet the quote") qdel(mission) qdel(shop) diff --git a/voidcrew/modules/unit_tests/voidcrew_mission_board_rewards.dm b/voidcrew/modules/unit_tests/voidcrew_mission_board_rewards.dm new file mode 100644 index 00000000000..725901fe5f9 --- /dev/null +++ b/voidcrew/modules/unit_tests/voidcrew_mission_board_rewards.dm @@ -0,0 +1,299 @@ +#ifndef VOIDCREW_MISSION_BOARD_REWARDS_TESTS +#define VOIDCREW_MISSION_BOARD_REWARDS_TESTS + +/// Board fixtures avoid random overmap sites; reward and lifecycle code stays real. +/datum/mission/m1_board_test/generate_mission_details() + +/datum/mission/recovery/outpost/m1_board_test/generate_mission_details() + +/datum/mission/recovery/kill/outpost/m1_board_test/generate_mission_details() + +/datum/mission/outpost_courier/m1_board_test/generate_mission_details() + +/obj/structure/overmap/trader_outpost/m1_board_test + var/turf/counter_turf + +/obj/structure/overmap/trader_outpost/m1_board_test/contains_site_turf(turf/location) + return location && location == counter_turf + +/// Verify conservation, shelf restrictions, stack amounts and all difficulty bands. +/datum/unit_test/voidcrew_m1_quotes/Run() + for(var/shop_type in list(/datum/outpost_shop/general, /datum/outpost_shop/outfitter, /datum/outpost_shop/black_market, /datum/outpost_shop/vendor/suit_fitter)) + var/datum/outpost_shop/shop = allocate(shop_type) + for(var/difficulty in list(1, 2, 3)) // MISSION_DIFFICULTY_* compile later. + for(var/attempt in 1 to 15) + var/datum/mission/mission = allocate(/datum/mission/m1_board_test, shop) + mission.difficulty = difficulty + TEST_ASSERT(shop.roll_contract_reward(mission), "A board must fund even an empty package") + var/list/bands = list(list(600, 900), list(1300, 1800), list(2400, 3200)) + TEST_ASSERT(mission.contract_quote >= bands[difficulty][1] && mission.contract_quote <= bands[difficulty][2], "Quote left its difficulty band") + var/package_value = 0 + TEST_ASSERT(length(mission.get_reward_types()) <= 2, "A quote includes too many shelf objects") + TEST_ASSERT_EQUAL(length(mission.rare_reward_types), 0, "Hard board work must never draw an exclusive") + for(var/item_type in mission.contract_stock) + var/datum/shop_sku/sku = mission.contract_stock[item_type] + TEST_ASSERT_EQUAL(sku.shelf, "core", "A package leaked a restricted shelf") + TEST_ASSERT(sku.contract_reward && sku.price_credits > 0 && !sku.price_vouchers && sku.stock > 0, "A package includes ineligible stock") + TEST_ASSERT_EQUAL(mission.reward_amounts[item_type], sku.dispense_amount, "A package changed a stack quantity") + package_value += sku.price_credits + TEST_ASSERT(package_value <= floor(mission.contract_quote * 0.6), "The package exceeds its shelf share") + TEST_ASSERT_EQUAL(package_value + mission.value + mission.voucher_count * 1200, mission.contract_quote, "Settlement lost or created quoted value") + TEST_ASSERT(mission.value >= 0 && mission.value < 1200, "Currency residual is not exact") + qdel(mission) + for(var/datum/shop_sku/sku as anything in shop.skus) + sku.stock = 0 + var/datum/mission/empty = allocate(/datum/mission/m1_board_test, shop) + TEST_ASSERT(shop.roll_contract_reward(empty), "Empty shelves must still offer work") + TEST_ASSERT_EQUAL(length(empty.get_reward_types()), 0, "Depleted stock was quoted as goods") + TEST_ASSERT_EQUAL(empty.value + empty.voucher_count * 1200, empty.contract_quote, "Empty shelves failed to settle in currency") + TEST_ASSERT(!findtext(empty.get_contract_pay_summary(), "goods"), "Currency-only text invented a goods reward") + qdel(shop) + var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) + var/list/expensive = list(/obj/item/gps = 601) + TEST_ASSERT_NULL(shop.pick_valued_reward(expensive, 600), "The cheapest-item fallback or overshoot remains") + +/// Every retained ask and all six fitter rows use the specified supply formula. +/datum/unit_test/voidcrew_m1_supply_rows/Run() + var/obj/structure/overmap/trader_outpost/outpost = allocate(/obj/structure/overmap/trader_outpost/outfitter) + var/datum/outpost_shop/vendor/suit_fitter/fitter = outpost.get_shop(/datum/outpost_shop/vendor/suit_fitter) + TEST_ASSERT_EQUAL(length(outpost.shop.get_procurement_requests()), 9, "The shared outfitter pool must contain nine equal rows") + for(var/shop_type in list(/datum/outpost_shop/general, /datum/outpost_shop/outfitter, /datum/outpost_shop/black_market)) + var/datum/outpost_shop/shop = shop_type == /datum/outpost_shop/outfitter ? outpost.shop : allocate(shop_type) + var/list/requests = shop.mission_requests.Copy() + for(var/list/request as anything in requests) + shop.mission_requests = list(request) + var/datum/mission/outpost_supply/mission = allocate(/datum/mission/outpost_supply, shop) + TEST_ASSERT(!mission.generation_failed, "[request["type"]] failed generation") + TEST_ASSERT_EQUAL(mission.required_amount, request["amount"], "Generation changed an ask quantity") + TEST_ASSERT_EQUAL(mission.difficulty, request["difficulty"], "Generation changed ask difficulty") + var/datum/outpost_shop/reward_shop = request["reward_shop"] ? fitter : shop + TEST_ASSERT_EQUAL(mission.contract_reward_shop, reward_shop, "Fitter reward stock must come from Wick") + TEST_ASSERT_EQUAL(mission.shop, shop, "Fitter favor must remain with Sarge") + var/counter = reward_shop.get_counter_value(request["type"], request["amount"]) + if(ispath(request["type"], /obj/item/mod/module)) + TEST_ASSERT_EQUAL(counter, 0, "Loot-module reference value became a buyback") + counter = 250 + var/list/bands = list(list(600, 900), list(1300, 1800), list(2400, 3200)) + var/list/band = bands[mission.difficulty] + var/list/services = list(200, 350, 500) + var/service = services[mission.difficulty] + var/minimum = max(CEILING(counter * 1.15, 1), min(request["pay_min"] || band[1], counter + service)) + var/maximum = max(CEILING(counter * 1.15, 1), min(request["pay_max"] || band[2], counter + service)) + if(mission.is_routine_contract()) + minimum = max(CEILING(counter * 1.10, 1), min(floor(band[1] * 0.4), service)) + maximum = max(CEILING(counter * 1.10, 1), min(floor(band[2] * 0.4), service)) + TEST_ASSERT_EQUAL(mission.voucher_count, 0, "Routine supplies must not pay vouchers") + TEST_ASSERT_EQUAL(mission.get_favor_reward(), 1, "Routine supplies must pay one favor") + TEST_ASSERT(mission.contract_quote >= minimum && mission.contract_quote <= maximum, "[request["type"]] left its specified pay range") + TEST_ASSERT_EQUAL(mission.value, mission.value_min, "The shell overwrote residual credits") + TEST_ASSERT_EQUAL(mission.value, mission.value_max, "Residual credits must not reroll") + qdel(mission) + shop.mission_requests = requests + for(var/mission_type in list(/datum/mission/outpost_supply/cook, /datum/mission/outpost_supply/angler)) + var/datum/mission/mission = allocate(mission_type, outpost.shop) + TEST_ASSERT_EQUAL(mission.voucher_count, 0, "The food and angler exceptions must never pay vouchers") + TEST_ASSERT_EQUAL(mission.get_favor_reward(), 1, "The food and angler exceptions must pay routine favor") + +/// Target scaling precedes the board quote; only the board multiplier changes fees. +/datum/unit_test/voidcrew_m1_field_fees/Run() + var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) + var/list/bands = list(list(600, 900), list(1300, 1800), list(2400, 3200)) + var/list/zones = list(1, 2, 3) // ZONE_GREEN/YELLOW/RED + for(var/index in 1 to 3) + var/list/band = bands[index] + for(var/mission_type in list(/datum/mission/recovery/outpost/m1_board_test, /datum/mission/recovery/kill/outpost/m1_board_test)) + var/datum/mission/mission = allocate(mission_type, shop) + mission.apply_zone_scaling(zones[index]) + mission.generate_details() + var/multiplier = 1.15 + if(istype(mission, /datum/mission/recovery/kill)) + var/list/kill_multipliers = list(1.10, 0.95, 0.55) + multiplier = kill_multipliers[index] + TEST_ASSERT(mission.contract_quote >= floor(band[1] * multiplier) && mission.contract_quote <= floor(band[2] * multiplier), "Field fee scaled twice or used the old multiplier") + TEST_ASSERT_EQUAL(mission.get_favor_reward(), index == 3 ? 3 : index, "Field favor has the wrong difficulty reward") + var/obj/structure/overmap/trader_outpost/origin = allocate(/obj/structure/overmap/trader_outpost, run_loc_floor_bottom_left) + var/obj/structure/overmap/trader_outpost/destination = allocate(/obj/structure/overmap/trader_outpost, run_loc_floor_top_right) + var/datum/mission/outpost_courier/mission = allocate(/datum/mission/outpost_courier/m1_board_test, origin.shop) + var/datum/mission_target/outpost/target = new(mission) + target.outpost = destination + mission.target = target + mission.generate_details() + TEST_ASSERT_EQUAL(mission.contract_quote, 10 * max(abs(origin.x - destination.x), abs(origin.y - destination.y)), "Courier pay ignored the fixed endpoint distance") + +/// Stock races, convoy caps, failure/delete release and exact once-only payout. +/datum/unit_test/voidcrew_m1_reservations/Run() + var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) + shop.add_sku(/datum/shop_sku/general/beans, "core") + var/datum/shop_sku/sku = shop.skus[1] + sku.stock = 1 + sku.stock_max = 1 + var/obj/structure/overmap/ship/ship = allocate(/obj/structure/overmap/ship) + var/datum/bank_account/account = allocate(/datum/bank_account, "Contract settlement", null, 1, FALSE) + ship.ship_account = account + var/datum/mission/first = allocate(/datum/mission/m1_board_test, shop) + var/datum/mission/second = allocate(/datum/mission/m1_board_test, shop) + shop.roll_contract_reward(first) + shop.roll_contract_reward(second) + var/second_quote = second.contract_quote + TEST_ASSERT(shop.roll_contract_reward(second), "A fixed quote could not be read again") + TEST_ASSERT_EQUAL(second.contract_quote, second_quote, "Reading the quote rerolled its value") + TEST_ASSERT(first.start_mission(ship), "The first crew could not accept its quote") + TEST_ASSERT_EQUAL(sku.stock, 0, "Acceptance did not claim shared stock") + TEST_ASSERT_EQUAL(sku.reserved_stock, 1, "Acceptance did not record its reservation") + TEST_ASSERT(!first.start_mission(ship), "A second acceptance reserved stock again") + TEST_ASSERT(second.start_mission(ship), "The second crew must still receive a currency award") + TEST_ASSERT_EQUAL(length(second.get_reward_types()), 0, "Two crews reserved the same last shelf object") + TEST_ASSERT_EQUAL(second.value + second.voucher_count * 1200, second_quote, "A drained shelf changed total pay") + shop.convoy_restock() + TEST_ASSERT_EQUAL(sku.stock, 0, "The convoy refilled a unit held by a contract") + first.fail("Abandoned.") + TEST_ASSERT_EQUAL(sku.stock, 1, "Abandonment did not release its stock") + qdel(first) + TEST_ASSERT_EQUAL(sku.stock, 1, "Deletion released the same reservation twice") + qdel(second) + var/datum/mission/paid = allocate(/datum/mission/m1_board_test, shop) + shop.roll_contract_reward(paid) + TEST_ASSERT(paid.start_mission(ship), "The completion fixture could not start") + var/cash = paid.value + var/balance = account.account_balance + TEST_ASSERT(paid.turn_in(run_loc_floor_bottom_left, null), "A completed contract could not settle") + TEST_ASSERT_EQUAL(account.account_balance, balance + cash, "Settlement paid the wrong residual credits") + TEST_ASSERT_EQUAL(sku.stock, 0, "Completion returned the paid shelf object to stock") + TEST_ASSERT_EQUAL(sku.reserved_stock, 0, "Completion left a reservation behind") + TEST_ASSERT(!paid.turn_in(run_loc_floor_bottom_left, null), "A stale hand-in completed twice") + paid.finish_mission(run_loc_floor_bottom_left) + TEST_ASSERT_EQUAL(account.account_balance, balance + cash, "A repeated completion paid twice") + +/// Missing receiving accounts refuse both partial and final consumption. +/datum/unit_test/voidcrew_m1_accounts/Run() + var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) + var/obj/structure/overmap/ship/ship = allocate(/obj/structure/overmap/ship) + var/datum/bank_account/account = allocate(/datum/bank_account, "Contract handover", null, 1, FALSE) + var/datum/mission/mission = allocate(/datum/mission/m1_board_test, shop) + shop.roll_contract_reward(mission) + ship.ship_account = null + TEST_ASSERT(!mission.start_mission(ship), "An accountless crew accepted work") + ship.ship_account = account + mission.requires_item = TRUE + var/datum/mission_objective/deliver/procurement/ask = new + ask.required_type = /obj/item/mod/construction/broken_core + ask.required_amount = 2 + mission.add_objective(ask) + TEST_ASSERT(mission.start_mission(ship), "A funded crew could not accept work") + var/obj/item/first = allocate(/obj/item/mod/construction/broken_core) + var/obj/item/second = allocate(/obj/item/mod/construction/broken_core) + ship.ship_account = null + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left, first), "A partial delivery consumed goods without a receiving account") + TEST_ASSERT(!QDELETED(first) && ask.delivered_count == 0, "Refused partial goods were consumed") + ship.ship_account = account + TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left, first), "A valid partial delivery failed") + TEST_ASSERT_EQUAL(ask.delivered_count, 1, "Partial delivery did not advance") + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left, first), "The same partial delivery counted twice") + ship.ship_account = null + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left, second), "A final delivery consumed goods without an account") + TEST_ASSERT(!QDELETED(second), "Refused final goods were consumed") + ship.ship_account = account + TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left, second), "Restoring the account did not allow settlement") + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left, second), "A final delivery settled twice") + +/// Acceptance, reopening, failure and target loss never advance the refill clock. +/datum/unit_test/voidcrew_m1_board_clock/Run() + var/obj/structure/overmap/trader_outpost/outpost = allocate(/obj/structure/overmap/trader_outpost) + for(var/datum/mission/posted as anything in outpost.shop_offers.Copy()) + qdel(posted) + outpost.shop_offers.Cut() + outpost.shop.mission_requests = list() + outpost.shop.extra_offer_mix = list( + /datum/mission/outpost_supply = 0, + /datum/mission/recovery/kill/outpost = 0, + /datum/mission/recovery/outpost = 0, + /datum/mission/outpost_courier = 0, + /datum/mission/outpost_supply/cook = 1, + ) + outpost.next_contract_refill = world.time + outpost.ensure_shop_offers() + TEST_ASSERT_EQUAL(length(outpost.shop_offers), 4, "Scheduled refill did not fill the shared slots") + var/next_refill = outpost.next_contract_refill + var/datum/mission/taken = outpost.shop_offers[1] + outpost.shop_offers -= taken + qdel(taken) + outpost.ensure_shop_offers() + TEST_ASSERT_EQUAL(length(outpost.shop_offers), 3, "Reopening replaced a vacant offer early") + TEST_ASSERT_EQUAL(outpost.next_contract_refill, next_refill, "Reopening moved the refill clock") + var/datum/mission/expired = outpost.shop_offers[1] + expired.posted_at = world.time - (22 MINUTES) + outpost.next_contract_refill = world.time + outpost.ensure_shop_offers() + TEST_ASSERT(QDELETED(expired), "An unaccepted offer survived its expiry") + TEST_ASSERT_EQUAL(length(outpost.shop_offers), 4, "Scheduled refill did not replace expired offers") + outpost.next_contract_refill = world.time - (1 SECONDS) + var/delayed_deadline = outpost.next_contract_refill + outpost.ensure_shop_offers() + TEST_ASSERT_EQUAL(outpost.next_contract_refill, delayed_deadline + (11 MINUTES), "A delayed callback shifted the fixed cadence") + +/// A cached window cannot act for visitors, former members or a displaced trader. +/datum/unit_test/voidcrew_m1_counter_access/Run() + var/obj/structure/overmap/trader_outpost/m1_board_test/outpost = allocate(/obj/structure/overmap/trader_outpost/m1_board_test) + var/mob/living/basic/outpost_trader/npc = allocate(/mob/living/basic/outpost_trader, run_loc_floor_bottom_left) + outpost.counter_turf = get_turf(npc) + outpost.trader = npc + npc.outpost = outpost + npc.shop = outpost.shop + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human/consistent, run_loc_floor_bottom_left) + user.mind_initialize() + allocated += user.mind + TEST_ASSERT(!npc.can_use_contracts(user), "A visitor could act on the board") + var/obj/structure/overmap/ship/ship = allocate(/obj/structure/overmap/ship) + var/datum/team/voidcrew/team = allocate(/datum/team/voidcrew) + team.ship = ship + user.mind.ship_teams = list(team) + TEST_ASSERT(npc.can_use_contracts(user), "A present crew member could not use the board") + user.mind.ship_teams = list() + TEST_ASSERT(!npc.can_use_contracts(user), "A former crew member could send a stale action") + user.mind.ship_teams = list(team) + npc.forceMove(get_step(run_loc_floor_bottom_left, NORTH)) + TEST_ASSERT(!npc.can_use_contracts(user), "A relocated trader could settle outside its site") + user.mind.ship_teams = list() + team.ship = null + +/// Spawned stack quantities, vouchers and cash match the accepted quote exactly. +/datum/unit_test/voidcrew_m1_physical_settlement/Run() + var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) + shop.add_sku(/datum/shop_sku/general/suture, "core") + var/datum/shop_sku/sku = shop.skus[1] + var/datum/mission/mission = allocate(/datum/mission/m1_board_test, shop) + mission.difficulty = 3 + shop.roll_contract_reward(mission) + var/obj/structure/overmap/ship/ship = allocate(/obj/structure/overmap/ship) + var/datum/bank_account/account = allocate(/datum/bank_account, "Physical settlement", null, 1, FALSE) + ship.ship_account = account + TEST_ASSERT(mission.start_mission(ship), "The physical settlement could not start") + var/cash = mission.value + var/vouchers = mission.voucher_count + var/quote = mission.contract_quote + var/balance = account.account_balance + TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left, null), "The physical settlement failed") + var/obj/item/stack/medical/suture/pack = locate() in run_loc_floor_bottom_left + var/obj/item/stack/trade_voucher/scrip = locate() in run_loc_floor_bottom_left + TEST_ASSERT_NOTNULL(pack, "The shelf package was not spawned") + TEST_ASSERT_NOTNULL(scrip, "The currency vouchers were not spawned") + TEST_ASSERT_EQUAL(pack.amount, 10, "The shelf package spawned one unit instead of ten") + TEST_ASSERT_EQUAL(scrip.amount, vouchers, "Settlement spawned the wrong voucher count") + TEST_ASSERT_EQUAL(account.account_balance - balance + scrip.amount * 1200 + sku.price_credits, quote, "Physical and bank rewards do not equal the quote") + TEST_ASSERT_EQUAL(account.account_balance, balance + cash, "The bank did not receive the residual cash") + TEST_ASSERT_EQUAL(shop.get_favor(ship), 3, "Hard completion granted the wrong standing") + +/// Existing food checks still distinguish player cooking from the diner's own plates. +/datum/unit_test/voidcrew_m1_cooked_goods/Run() + var/datum/mission_objective/deliver/cooked/ask = allocate(/datum/mission_objective/deliver/cooked) + var/obj/item/food/dish = allocate(/obj/item/food) + dish.crafting_complexity = ask.min_complexity + TEST_ASSERT(!ask.can_turn_in(dish), "Factory food satisfied a Kitchen Order") + ADD_TRAIT(dish, TRAIT_FOOD_CHEF_MADE, "outpost_kitchen") // TRAIT_SOURCE_OUTPOST_KITCHEN + TEST_ASSERT(!ask.can_turn_in(dish), "A counter plate satisfied a Kitchen Order") + ADD_TRAIT(dish, TRAIT_FOOD_CHEF_MADE, "player_cook") + TEST_ASSERT(ask.can_turn_in(dish), "Player-cooked food failed an otherwise valid order") + dish.crafting_complexity = ask.min_complexity - 1 + TEST_ASSERT(!ask.can_turn_in(dish), "An underspecified meal satisfied a Kitchen Order") + +#endif diff --git a/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm b/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm index 94d01c01965..3d6c9bb621f 100644 --- a/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm +++ b/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm @@ -102,6 +102,12 @@ list(/obj/item/stack/sheet/animalhide/goliath_hide, 4, 3), list(/obj/item/stack/sheet/sinew, 4, 2), list(/obj/item/stack/glacial_core, 5, 2), + list(/obj/item/mod/construction/broken_core, 2, 1), + list(/obj/item/mod/control/pre_equipped, 1, 2), + list(/obj/item/mod/module/springlock, 1, 2), + list(/obj/item/mod/module/visor/rave, 1, 2), + list(/obj/item/mod/module/balloon, 1, 2), + list(/obj/item/mod/module/stamp, 1, 2), ), ) for(var/shop_type in expected_catalogs) @@ -122,7 +128,7 @@ TEST_ASSERT(shop.extra_offer_mix[/datum/mission/outpost_supply/cook] > 0, "The owner's Kitchen Orders must remain available") var/datum/outpost_shop/vendor/suit_fitter/fitter = allocate(/datum/outpost_shop/vendor/suit_fitter) - TEST_ASSERT_EQUAL(length(fitter.mission_requests), 0, "New suit salvage requests need reward-design inputs before activation") + TEST_ASSERT_EQUAL(length(fitter.mission_requests), 6, "The fitter must supply all six salvage requests") var/datum/mission/delivery/delivery = allocate(/datum/mission/delivery) TEST_ASSERT_EQUAL(delivery.weight, 0, "Ore-only ship deliveries must not roll") TEST_ASSERT(delivery.generation_failed, "Explicit generation must also refuse suspended ship deliveries") @@ -174,8 +180,11 @@ list(list("type" = /obj/item/stack/glacial_core, "name" = "glacial cores", "amount" = 5, "difficulty" = 2)), ) for(var/list/pool as anything in pools) - QDEL_LIST(outpost.shop_offers) + for(var/datum/mission/posted as anything in outpost.shop_offers.Copy()) + qdel(posted) + outpost.shop_offers.Cut() outpost.shop.mission_requests = pool + outpost.next_contract_refill = world.time outpost.ensure_shop_offers() // OUTPOST_SHOP_OFFER_COUNT = 4, defined after this test's include. TEST_ASSERT_EQUAL(length(outpost.shop_offers), 4, "Supply eligibility stalled the outpost board") From 1483d2b8e1e756a92743315fee56df7600004f64 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:25:16 -0700 Subject: [PATCH 037/105] NPC zone profile review fixes --- voidcrew/modules/npc_scaling/spawn_hooks.dm | 10 +++ voidcrew/modules/npc_scaling/zone_profiles.dm | 16 ++++- .../unit_tests/voidcrew_npc_zone_profiles.dm | 63 ++++++++++++++++++- 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/voidcrew/modules/npc_scaling/spawn_hooks.dm b/voidcrew/modules/npc_scaling/spawn_hooks.dm index 2b592e1a742..31d975b15f0 100644 --- a/voidcrew/modules/npc_scaling/spawn_hooks.dm +++ b/voidcrew/modules/npc_scaling/spawn_hooks.dm @@ -81,3 +81,13 @@ GLOBAL_VAR(npc_zone_construction_context) SIGNAL_HANDLER if(friend && (friend.client || friend.mind || friend.npc_zone_exempt)) source.exempt_npc_zone() + +// Replace upstream's bare constructor so the regular megafauna attack inherits its source. +// No parent call: it would create an additional, unprofiled skull. +/datum/action/cooldown/mob_cooldown/create_legion_skull/create(atom/target) + owner.get_npc_spawn_context() + var/datum/npc_spawn_context/context = new(owner, role = "ordinary") + var/mob/living/basic/legion_brood/minion = spawn_npc_in_zone(/mob/living/basic/legion_brood, owner.loc, context, FALSE) + minion.assign_creator(owner) + minion.ai_controller.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, target) + context.finalize() diff --git a/voidcrew/modules/npc_scaling/zone_profiles.dm b/voidcrew/modules/npc_scaling/zone_profiles.dm index ebd21c16099..4d796771f6b 100644 --- a/voidcrew/modules/npc_scaling/zone_profiles.dm +++ b/voidcrew/modules/npc_scaling/zone_profiles.dm @@ -45,8 +45,12 @@ if(!isnull(zone_type)) return resolver = new /datum/zone_resolver(source_turf, CALLBACK(src, PROC_REF(on_zone_resolved))) + // A synchronous callback runs before the constructor's result is assigned. + if(!isnull(zone_type)) + resolver = null /datum/npc_spawn_context/proc/on_zone_resolved(resolved_zone) + resolver = null if(!isnull(zone_type)) return zone_type = isnull(resolved_zone) ? ZONE_GREEN : resolved_zone @@ -120,7 +124,17 @@ /// Environmental auto gate: passive fauna and mobs without autonomous AI stay baseline. /mob/living/proc/is_npc_zone_hostile() - return ishostile(src) || (isbasicmob(src) && ai_controller && combat_mode) + if(ishostile(src)) + return TRUE + if(!isbasicmob(src) || !ai_controller) + return FALSE + if(combat_mode) + return TRUE + // Autonomous target acquisition does not depend on the pawn's combat stance. + for(var/datum/ai_planning_subtree/simple_find_target/targeting in ai_controller.planning_subtrees) + if(targeting.target_key == BB_BASIC_MOB_CURRENT_TARGET) + return TRUE + return FALSE /mob/living/proc/is_npc_zone_exempt() return npc_zone_exempt || npc_spawn_context?.exempt || client || mind || (FACTION_NEUTRAL in faction) diff --git a/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm index 6a31510e02b..2400fae7636 100644 --- a/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm +++ b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm @@ -11,6 +11,10 @@ unsuitable_cold_damage = 0 unsuitable_heat_damage = 0 +/mob/living/basic/npc_zone_test/passive + combat_mode = FALSE + ai_controller = /datum/ai_controller/basic_controller/simple + /mob/living/simple_animal/hostile/npc_zone_test health = 100 maxHealth = 100 @@ -104,8 +108,7 @@ qdel(body) qdel(child) var/datum/npc_spawn_context/passive_context = allocate(/datum/npc_spawn_context, src, 3) - var/mob/living/basic/passive = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, location, passive_context, FALSE) - passive.combat_mode = FALSE + var/mob/living/basic/passive = spawn_npc_in_zone(/mob/living/basic/npc_zone_test/passive, location, passive_context, FALSE) passive_context.finalize() TEST_ASSERT(!passive.npc_zone_applied, "Passive ambient fauna received a hostile profile") qdel(passive) @@ -256,6 +259,38 @@ for(var/band in 1 to 3) TEST_ASSERT_EQUAL(SSplanet_mobs.mob_cap_for_band(band), 15, "Band [band] does not have the flat fauna cap") +/datum/unit_test/voidcrew_npc_zone_skeleton_route/Run() + var/turf/location = run_loc_floor_bottom_left + var/obj/effect/zone_mobs/undead/marker = allocate(/obj/effect/zone_mobs/undead, null, list(1, 1)) + marker.forceMove(location) + marker.scatter_radius = 0 + marker.mobs_red = list(/mob/living/basic/skeleton/templar = 1) + marker.do_spawn(3) + var/mob/living/basic/skeleton/templar/skeleton = locate() in location + TEST_ASSERT_NOTNULL(skeleton, "Red undead marker did not produce its templar") + TEST_ASSERT(!skeleton.combat_mode, "Skeleton fixture no longer starts outside combat mode") + TEST_ASSERT_EQUAL(skeleton.npc_zone_role, "ordinary", "Hostile skeleton AI missed its ordinary profile") + TEST_ASSERT_EQUAL(skeleton.npc_spawn_context.zone_type, 3, "Skeleton route lost its red source") + TEST_ASSERT(abs(skeleton.maxHealth - initial(skeleton.maxHealth) * 1.8) < 0.001, "Red skeleton retained baseline health") + TEST_ASSERT(abs(skeleton.melee_damage_upper - initial(skeleton.melee_damage_upper) * 1.35) < 0.001, "Red skeleton retained baseline damage") + qdel(skeleton) + qdel(marker) + +/datum/unit_test/voidcrew_npc_zone_resolver_cleanup/Run() + // Nullspace leaves the resolver pending until its final fallback attempt. + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src) + var/mob/living/body = spawn_npc_in_zone(/mob/living/basic/npc_zone_test, run_loc_floor_bottom_left, context) + context.resolve_zone() + var/datum/zone_resolver/pending = context.resolver + TEST_ASSERT_NOTNULL(pending, "Unresolved context did not retain its pending resolver") + pending.attempts_left = 0 + pending.attempt() + TEST_ASSERT_EQUAL(context.zone_type, 1, "Resolver fallback did not finalize its context") + TEST_ASSERT(body.npc_zone_applied, "Resolver completion did not finalize its surviving NPC") + TEST_ASSERT(QDELETED(pending), "Completed resolver did not delete itself") + TEST_ASSERT_NULL(context.resolver, "Surviving NPC context retained a completed resolver") + qdel(body) + /datum/unit_test/voidcrew_npc_zone_deferred/Run() var/turf/location = run_loc_floor_bottom_left var/datum/planet_mob_tracker/tracker = allocate(/datum/planet_mob_tracker) @@ -361,6 +396,7 @@ continue body.npc_spawn_context.resolve_zone() TEST_ASSERT_EQUAL(body.npc_spawn_context.zone_type, band, "Mapped replacement resolved a different site") + TEST_ASSERT_NULL(body.npc_spawn_context.resolver, "Synchronous construction retained its completed resolver") TEST_ASSERT_EQUAL(body.maxHealth, band == 1 ? 100 : 180, "Mapped replacement used its neighbour's factor") body.forceMove(locations[band == 1 ? 2 : 1]) body.finalize_npc_zone() @@ -924,6 +960,29 @@ QDEL_LIST(mediums) qdel(parent) +/datum/unit_test/voidcrew_npc_zone_legion_skull_route/Run() + var/turf/location = run_loc_floor_bottom_left + var/turf/landing = run_loc_floor_top_right + var/mob/living/basic/bait = allocate(/mob/living/basic/npc_zone_test, location) + for(var/exempt in list(FALSE, TRUE)) + var/datum/npc_spawn_context/context = allocate(/datum/npc_spawn_context, src, 3, "boss", exempt, location) + var/mob/living/simple_animal/hostile/megafauna/legion/parent = spawn_npc_in_zone(/mob/living/simple_animal/hostile/megafauna/legion, location, context) + parent.forceMove(landing) + parent.create_legion_skull.create(bait) + var/mob/living/basic/legion_brood/skull = locate() in landing + check_npc_zone_child(skull, context, exempt) + TEST_ASSERT_EQUAL(skull.npc_spawn_context.source_turf, location, "Megafauna skull repinned its source after its creator moved") + TEST_ASSERT_EQUAL(skull.created_by.resolve(), parent, "Megafauna skull lost its creator assignment") + TEST_ASSERT_EQUAL(skull.ai_controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET], bait, "Megafauna skull lost its attack target") + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent, landing) + skull.infest(victim) + var/mob/living/basic/mining/legion/infested = locate() in landing + check_npc_zone_child(infested, context, exempt) + TEST_ASSERT_EQUAL(infested.npc_spawn_context.source_turf, location, "Infestation lost the megafauna's pinned source") + TEST_ASSERT_EQUAL(infested.stored_mob, victim, "Megafauna skull infestation did not consume its victim") + qdel(infested) + qdel(parent) + /// The post hook overrides health and faction and must run before finalization. /datum/action/cooldown/spell/conjure/npc_zone_test summon_type = list(/mob/living/basic/npc_zone_test/replacement) From 549cdf6c0882582c9e544d27fdb02f6fdbf26801 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:41:08 -0700 Subject: [PATCH 038/105] Mission rewards on the ship console and guarded missions --- tgstation.dme | 1 + voidcrew/_DEFINES/missions.dm | 7 +- voidcrew/modules/bounties/bounty_lair.dm | 7 + voidcrew/modules/metrics/mission_metrics.dm | 47 +- voidcrew/modules/missions/_missions.dm | 135 ++++-- .../code/controllers/subsystem/missions.dm | 48 +- voidcrew/modules/missions/mission_board.dm | 19 +- .../missions/missions/big_game_hunt.dm | 23 +- .../modules/missions/missions/delivery.dm | 28 +- .../modules/missions/missions/exploration.dm | 6 +- .../missions/missions/field_expedition.dm | 11 +- .../modules/missions/missions/gas_harvest.dm | 26 +- .../modules/missions/missions/live_capture.dm | 25 +- .../modules/missions/missions/poacher_bust.dm | 21 +- .../missions/missions/prospect_stake.dm | 41 +- .../modules/missions/missions/recovery.dm | 24 +- .../missions/missions/recovery_variants.dm | 27 +- voidcrew/modules/missions/missions/rescue.dm | 12 +- .../modules/missions/missions/research.dm | 49 +- .../modules/missions/missions/suppression.dm | 16 +- voidcrew/modules/missions/missions/survey.dm | 72 +-- .../modules/missions/objectives/combat.dm | 2 +- .../modules/missions/objectives/deliver.dm | 19 +- .../modules/missions/objectives/site_ops.dm | 14 +- .../faction_pirates/faction_pirate_mobs.dm | 2 +- .../overmap/code/modules/overmap/ship.dm | 72 ++- voidcrew/modules/unit_tests/_unit_tests.dm | 1 + .../unit_tests/voidcrew_launch_access.dm | 7 +- .../voidcrew_mission_console_rewards.dm | 458 ++++++++++++++++++ .../unit_tests/voidcrew_mission_metrics.dm | 3 +- .../modules/unit_tests/voidcrew_missions.dm | 9 + .../unit_tests/voidcrew_shop_catalog.dm | 10 + 32 files changed, 936 insertions(+), 306 deletions(-) create mode 100644 voidcrew/modules/unit_tests/voidcrew_mission_console_rewards.dm diff --git a/tgstation.dme b/tgstation.dme index f9dddc25d60..ae86be0543d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7687,6 +7687,7 @@ #include "voidcrew\modules\transporter\transporter_transponder.dm" #if defined(UNIT_TESTS) || defined(SPACEMAN_DMM) #include "voidcrew\modules\unit_tests\voidcrew_mission_board_rewards.dm" +#include "voidcrew\modules\unit_tests\voidcrew_mission_console_rewards.dm" #endif #include "voidcrew\modules\vehicles\atv.dm" #include "voidcrew\modules\vending\_vending.dm" diff --git a/voidcrew/_DEFINES/missions.dm b/voidcrew/_DEFINES/missions.dm index e853888f043..1191aad2b90 100644 --- a/voidcrew/_DEFINES/missions.dm +++ b/voidcrew/_DEFINES/missions.dm @@ -16,11 +16,8 @@ #define DEFAULT_AVAILABLE_MISSIONS 5 #define DEFAULT_MAX_ACTIVE_MISSIONS 3 #define DEFAULT_MISSION_DURATION (30 MINUTES) -/// Board reroll wipes all five offers, so a short cooldown made it free to fish -/// for the top-paying contract type. Five minutes makes the posted board a hand -/// you play rather than one you redraw. -#define MISSION_REFRESH_COOLDOWN (5 MINUTES) -/// Unaccepted board offers older than this are rotated out by SSmissions +/// The ship keeps one fixed set of offers until its scheduled refresh. +#define MISSION_REFRESH_COOLDOWN (20 MINUTES) #define MISSION_BOARD_EXPIRY (20 MINUTES) /** diff --git a/voidcrew/modules/bounties/bounty_lair.dm b/voidcrew/modules/bounties/bounty_lair.dm index c23df9f8138..cc58a5def03 100644 --- a/voidcrew/modules/bounties/bounty_lair.dm +++ b/voidcrew/modules/bounties/bounty_lair.dm @@ -302,6 +302,13 @@ lair_kind = null return ..() +/// The existing atomic claim closes the bounty before returning its successful pay. +/datum/criminal_bounty/kill_only/lair/board_claim(obj/structure/overmap/ship/ship, obj/machinery/mission_pad/pad, atom/movable/target, state, mob/user) + var/prize_zone = board_zone + . = ..() + if(islist(.) && !QDELETED(ship)) + ship.award_guarded_prize("lair", prize_zone, pad, type) + /// Its clock also waits while anyone is inside the lair: a crew deep in it never loses the bounty to the clock /datum/criminal_bounty/kill_only/lair/board_clock_held(now = world.time) if(..()) diff --git a/voidcrew/modules/metrics/mission_metrics.dm b/voidcrew/modules/metrics/mission_metrics.dm index 6e6a9eb910c..59f20291fee 100644 --- a/voidcrew/modules/metrics/mission_metrics.dm +++ b/voidcrew/modules/metrics/mission_metrics.dm @@ -42,6 +42,10 @@ // Hook: /obj/structure/overmap/trader_outpost/ensure_shop_offers(). // board_refreshed - a crew rerolled its mission board. ckey, ship. quantity: offers thrown // away. Hook: the mission board's "refresh" action. +// mission_quote_posted - the quoted cash, vouchers, research and package value of one offer. +// guarded_prize_paid - diagnostic item row for a suit or gadget, including its family, quote +// zone and first_suit_s. Console/contract mission_completed.total_value already includes +// this prize; do not add this diagnostic row a second time to mission receipts. // pirate_bounty_accepted - a crew took a bounty on an NPC pirate ship from its mission board. // ckey, ship. subject: the pirate ship's typepath. zone: where the pirate is. // details: reward, heavy. @@ -88,6 +92,8 @@ /// The zone name of this mission's target, or null when it has none. /datum/mission/proc/metric_target_zone() + if(!isnull(quote_zone)) + return metric_zone_name(quote_zone) var/zone_type = target?.get_zone_type() if(!isnull(zone_type)) return metric_zone_name(zone_type) @@ -147,7 +153,12 @@ * a back-room prize at CONTRACT_EXCLUSIVE_VALUE. Called once, when the contract is generated. */ /datum/mission/proc/note_metric_item_value() - if(!shop || !SSmetrics.accepting) + if(!SSmetrics.accepting) + return + if(!shop) + metric_item_value = 0 + for(var/reward_type in get_reward_types()) + metric_item_value += mission_utility_value(reward_type) return var/list/reward_types = get_reward_types() if(!length(reward_types)) @@ -165,6 +176,27 @@ total += sku_values[reward_type] || 0 metric_item_value = total +/// Value utility at its catalog price without constructing shops or consuming stock. +/proc/mission_utility_value(item_type) + var/static/list/prices + if(isnull(prices)) + prices = list() + for(var/datum/shop_sku/sku_type as anything in subtypesof(/datum/shop_sku)) + var/item_path = initial(sku_type.item_path) + var/price = initial(sku_type.price_credits) + initial(sku_type.price_vouchers) * VOUCHER_CREDIT_VALUE + if(!item_path || price <= 0) + continue + if(!prices[item_path] || price < prices[item_path]) + prices[item_path] = price + return prices[item_type] || 0 + +/// One row per actual named prize, shared by console, outpost kills and bounty lairs. +/proc/record_guarded_prize(obj/structure/overmap/ship/ship, family, category, zone, prize_type, source_type) + var/list/details = list("family" = family, "prize_type" = category, "source" = source_type, "item_value" = category == "suit" ? 9000 : 3600) + if(category == "suit") + details["first_suit_s"] = ship.mission_first_suit_seconds + record_metric(METRIC_MISSION, "guarded_prize_paid", ship = ship, zone = metric_zone_name(zone), subject = prize_type, quantity = 1, details = details) + /// Remembers the ship parts in a prize crate this mission just paid. /datum/mission/proc/note_metric_ship_parts(obj/structure/closet/crate/prize) if(!prize || !SSmetrics.accepting) @@ -235,6 +267,12 @@ var/item_value = paid_goods ? metric_item_value : 0 if(item_value > 0) details["item_value"] = item_value + if(paid_goods && guarded_prize) + var/prize_value = ispath(guarded_prize, /obj/item/mod/control) ? 9000 : 3600 + details["prize"] = guarded_prize + details["prize_value"] = prize_value + item_value += prize_value + item_count++ details["total_value"] = paid_credits + item_value + paid_vouchers * VOUCHER_CREDIT_VALUE if(favor) details["favor"] = favor @@ -276,6 +314,13 @@ if(!SSmetrics.accepting || QDELETED(offer)) return tally_metric(METRIC_MISSION, event, ship = ship, zone = offer.metric_target_zone(), subject = offer.type) + if(event == "mission_offered" || event == "contract_offered") + var/list/details = offer.metric_base_details() + details["item_value"] = offer.metric_item_value + details["offer"] = offer.value + details["vouchers"] = offer.voucher_count + details["research"] = offer.research_reward + record_metric(METRIC_MISSION, "mission_quote_posted", ship = ship, zone = offer.metric_target_zone(), subject = offer.type, details = details) /// board_refreshed. Called before the board is cleared, so the count is what was thrown away. /proc/record_mission_board_refreshed(obj/structure/overmap/ship/ship, mob/user) diff --git a/voidcrew/modules/missions/_missions.dm b/voidcrew/modules/missions/_missions.dm index 031b7c9c80a..3fbf3bc6de8 100644 --- a/voidcrew/modules/missions/_missions.dm +++ b/voidcrew/modules/missions/_missions.dm @@ -98,6 +98,15 @@ var/named_kill_completed = FALSE /// Shared by every incarnation of this mission's named pirate target. var/boss_cash_issued = FALSE + /// Reward band fixed when posted, independent of ask difficulty. + var/quote_zone + var/zone_scaling_applied = FALSE + /// Family eligible for a completion prize; null for unguarded work. + var/guarded_prize_family + var/guarded_prize_rolled = FALSE + var/guarded_prize + /// Prevent reentrant partial handovers as well as final settlements. + var/turning_in = FALSE // ===== TARGET ===== /// Where the mission points on the overmap, if anywhere @@ -146,12 +155,13 @@ /// linked later still gets the full set and cleanup drops every tag. var/list/aux_gps_beacons -/datum/mission/New(datum/outpost_shop/shop, preferred_zone) +/datum/mission/New(datum/outpost_shop/shop, preferred_zone, posting_zone) . = ..() src.shop = shop // Has to land before generate_mission_details(): setup_target() builds the // target datum, which copies this off us in its own New(). src.preferred_zone = preferred_zone + quote_zone = posting_zone posted_at = world.time generate_mission_details() @@ -195,14 +205,23 @@ return if(target) - var/zone_type = target.get_zone_type() - if(!isnull(zone_type)) - apply_zone_scaling(zone_type) + quote_zone = target.get_zone_type() + if(!isnull(quote_zone)) + // Board quotes and the drug run keep their existing generation hooks. + if(shop) + apply_zone_scaling(quote_zone) + else + set_zone_details(quote_zone) generate_details() if(generation_failed) return + if(!shop) + if(!isnull(quote_zone)) + apply_zone_scaling(quote_zone) + roll_posted_rewards() + build_objectives() if(generation_failed) return @@ -246,32 +265,41 @@ objectives += objective return objective -/** - * The zone scaling service: one table mapping the target's zone to - * difficulty, zone name, pay multiplier and a red-zone voucher bonus. - * Types tune pay by setting their green-zone value band. - */ +/// Targeted work takes its difficulty from the site; asks keep their own. +/datum/mission/proc/set_zone_details(zone_type) + quote_zone = zone_type + switch(zone_type) + if(ZONE_YELLOW) + target_zone_name = ZONE_NAME_YELLOW + if(ZONE_RED) + target_zone_name = ZONE_NAME_RED + else + target_zone_name = ZONE_NAME_GREEN + if(target || shop) + difficulty = zone_type + +/// Scale only once, after the chosen ask and hazard have set their base bands. /datum/mission/proc/apply_zone_scaling(zone_type) - var/static/list/zone_scaling = list( - "[ZONE_GREEN]" = list("name" = ZONE_NAME_GREEN, "difficulty" = MISSION_DIFFICULTY_EASY, "value_mult" = 1, "research_mult" = 1, "voucher_bonus" = 0), - "[ZONE_YELLOW]" = list("name" = ZONE_NAME_YELLOW, "difficulty" = MISSION_DIFFICULTY_MEDIUM, "value_mult" = 1.7, "research_mult" = 1.4, "voucher_bonus" = 0), - "[ZONE_RED]" = list("name" = ZONE_NAME_RED, "difficulty" = MISSION_DIFFICULTY_HARD, "value_mult" = 2.6, "research_mult" = 1.8, "voucher_bonus" = 1), - ) - var/list/row = zone_scaling["[zone_type]"] || zone_scaling["[ZONE_GREEN]"] - target_zone_name = row["name"] - difficulty = row["difficulty"] - value_min = round(value_min * row["value_mult"], 10) - value_max = round(value_max * row["value_mult"], 10) - // Points scale slower than credits on purpose. Credits are spent and gone, so a - // deep-band contract can pay several times a green one without distorting - // anything; research is permanent progress on a tree the whole ship shares, and - // riding the 2.6x credit multiplier put one Lawless contract ahead of every other - // point faucet in the game combined. The danger premium is paid in credits and - // vouchers - the band (MISSION_RESEARCH_PAY_*) is what sets the science. + if(zone_scaling_applied) + return + zone_scaling_applied = TRUE + set_zone_details(zone_type) + if(shop) + return // M1 packages and currency already define the complete board quote. + var/value_mult = zone_type == ZONE_RED ? 2.2 : (zone_type == ZONE_YELLOW ? 1.5 : 1) + var/research_mult = zone_type == ZONE_RED ? 1.8 : (zone_type == ZONE_YELLOW ? 1.4 : 1) + if(!istype(src, /datum/mission/delivery) && !istype(src, /datum/mission/suppression)) + value_min = round(value_min * value_mult, 10) + value_max = round(value_max * value_mult, 10) if(research_reward > 0) - research_reward = round(research_reward * row["research_mult"], 10) - if(voucher_count > 0) - voucher_count += row["voucher_bonus"] + research_reward = round(research_reward * research_mult, 10) + +/// One posting-time voucher roll; utility rewards override this hook too. +/datum/mission/proc/roll_posted_rewards() + if(istype(src, /datum/mission/prospect_stake)) + voucher_count = 1 + else if(guarded_prize_family || istype(src, /datum/mission/suppression)) + voucher_count = prob(quote_zone == ZONE_RED ? 75 : (quote_zone == ZONE_YELLOW ? 50 : 25)) ? 1 : 0 /** * Rebuilds name/desc from current state. Called at the end of generation and @@ -305,12 +333,12 @@ /datum/mission/proc/start_mission(obj/structure/overmap/ship/ship) if(!ship) return FALSE - if(active) + if(QDELETED(src) || active || failed || completed) return FALSE // The target may have died while the mission sat on the board if(target && !target.is_valid()) - if(!target.resolve()) + if(!resolve_quoted_target()) return FALSE update_text() @@ -558,6 +586,9 @@ /datum/mission/proc/on_target_moved() if(failed || completed) return + if(!isnull(quote_zone) && target?.get_zone_type() != quote_zone) + handle_quest_loss() + return update_text() if(active) push_waypoint() @@ -626,7 +657,7 @@ if(retargets_left < 0) fail(reason) return - if(!target?.resolve()) + if(!resolve_quoted_target()) fail(reason) return @@ -638,6 +669,16 @@ push_waypoint() servant?.ship_notify("[name]: target signal relocated to ([target.target_x], [target.target_y]), [target_zone_name].", "MISSION UPDATE", SHIP_NOTIFY_WARNING, 'voidcrew/sound/notify2.ogg', 50) +/// Target preferences may fall back across zones; a fixed quote may not. +/datum/mission/proc/resolve_quoted_target() + if(!target) + return FALSE + if(!isnull(quote_zone)) + target.preferred_zone = quote_zone + if(!target.resolve()) + return FALSE + return isnull(quote_zone) || target.get_zone_type() == quote_zone + // ========================================================================= // COMPLETION & TURN-IN // ========================================================================= @@ -753,8 +794,16 @@ * (it is qdeleted by then) or just advanced a counted hand-over. */ /datum/mission/proc/turn_in(atom/reward_anchor, obj/item/turned_in_item, force = FALSE) - if(failed || completed) + if(QDELETED(src) || failed || completed || turning_in) + return FALSE + // Console handovers validate the account before consuming even a partial ask. + if(!shop && (QDELETED(servant) || QDELETED(servant.ship_account) || !active || !get_turf(reward_anchor) || !can_turn_in_at(reward_anchor))) return FALSE + turning_in = TRUE + . = settle_turn_in(reward_anchor, turned_in_item, force) + turning_in = FALSE + +/datum/mission/proc/settle_turn_in(atom/reward_anchor, obj/item/turned_in_item, force = FALSE) if(!force) if(requires_item) @@ -762,6 +811,8 @@ return FALSE var/datum/mission_objective/objective = current_objective() var/result = objective.accept_item(turned_in_item, reward_anchor) + if(result == MISSION_ITEM_REFUSED) + return FALSE if(result == MISSION_ITEM_PROGRESS) return TRUE // partial hand-over; mission continues if(!all_objectives_satisfied()) @@ -777,6 +828,8 @@ * The mission is done: run objective finalizers, pay out, notify, clean up. */ /datum/mission/proc/finish_mission(atom/reward_anchor) + if(QDELETED(src) || failed || completed) + return completed = TRUE active = FALSE @@ -956,13 +1009,12 @@ . += mission_rewards /** - * Human-readable summary of the item rewards, e.g. "a standard missile, 2× - * light warhead and an ablative vest". Returns "goods" when nothing is set. + * Human-readable item summary, empty when the settlement is currency only. */ /datum/mission/proc/get_reward_summary() var/list/types = get_reward_types() if(!length(types)) - return "goods" + return "" // Collapse duplicates into counts so a bundle reads "2× light missile" var/list/counts = list() for(var/reward_type in types) @@ -978,13 +1030,16 @@ /** * The whole of what an outpost contract pays, goods and scrip together, e.g. - * "a laser gun and 2× stimpack + 2 trade vouchers". Board contracts never pay - * credits, so the item bundle plus any voucher top-up is the entire settlement. + * "a laser gun and 2× stimpack + 2 trade vouchers + 50 cr". */ /datum/mission/proc/get_contract_pay_summary() - var/list/parts = list(get_reward_summary()) + var/list/parts = list() + if(length(get_reward_types())) + parts += get_reward_summary() if(voucher_count > 0) parts += "[voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]" + if(value > 0) + parts += "[value] cr" return parts.Join(" + ") /** @@ -1027,6 +1082,10 @@ new /obj/item/stack/trade_voucher(reward_turf, voucher_count) flash_reward_anchor(reward_anchor) + if(completed && !failed && guarded_prize_family && !guarded_prize_rolled) + guarded_prize_rolled = TRUE + guarded_prize = servant.award_guarded_prize(guarded_prize_family, quote_zone, reward_anchor, type) + /** * Turn-in visual: pads get their teleport effect, other anchors stay quiet * (the outpost board plays its own sounds). diff --git a/voidcrew/modules/missions/code/controllers/subsystem/missions.dm b/voidcrew/modules/missions/code/controllers/subsystem/missions.dm index 948716f3c90..0229eb423f2 100644 --- a/voidcrew/modules/missions/code/controllers/subsystem/missions.dm +++ b/voidcrew/modules/missions/code/controllers/subsystem/missions.dm @@ -45,7 +45,7 @@ SUBSYSTEM_DEF(missions) CHECK_TICK /** - * Fills a ship's available missions list up to the default count. + * Replaces a ship's fixed offer set only when its scheduled refresh is due. * * ship - The ship to refresh missions for */ /datum/controller/subsystem/missions/proc/refresh_ship_missions(obj/structure/overmap/ship/ship) @@ -55,28 +55,35 @@ SUBSYSTEM_DEF(missions) if(istype(ship, /obj/structure/overmap/ship/npc)) return - // Remove deleted missions and rotate out offers that sat unaccepted too long + // Deletion leaves a vacancy, not a retained reference or an early replacement. + for(var/index in length(ship.available_missions) to 1 step -1) + if(QDELETED(ship.available_missions[index])) + ship.available_missions.Cut(index, index + 1) + if(world.time < ship.next_mission_refresh) + return FALSE + // Claim the schedule before generation, so console rebuilds and vacant slots cannot reroll it. + ship.next_mission_refresh = world.time + MISSION_REFRESH_COOLDOWN + ship.last_mission_refresh = world.time for(var/datum/mission/mission as anything in ship.available_missions) - if(QDELETED(mission)) - ship.available_missions -= mission - continue - if(world.time - mission.posted_at > MISSION_BOARD_EXPIRY) - ship.available_missions -= mission + if(!QDELETED(mission)) tally_mission_offer(mission, ship, "mission_offer_expired") // round metrics, voidcrew/modules/metrics/mission_metrics.dm qdel(mission) + ship.available_missions = list() // Reserve one of the existing slots before rolling the rest of the board. ensure_safe_exploration_offer(ship) - // Fill up to default count - var/missions_needed = DEFAULT_AVAILABLE_MISSIONS - length(ship.available_missions) // Asked once and reused: the lookup walks the hull for an R&D server the // first time it misses, and five offers is five walks. var/unarmed = !ship.has_ship_combat_research() - for(var/i in 1 to missions_needed) - var/datum/mission/new_mission = generate_random_mission(roll_offer_zone_preference(unarmed)) + var/posting_zone = SSovermap_zones?.get_zone_type(get_turf(ship)) + // Resolve failed rolls inside this scheduled batch; never retry vacancies afterward. + var/attempts_left = DEFAULT_AVAILABLE_MISSIONS * 10 + while(length(ship.available_missions) < DEFAULT_AVAILABLE_MISSIONS && attempts_left-- > 0) + var/datum/mission/new_mission = generate_random_mission(roll_offer_zone_preference(unarmed), posting_zone) if(new_mission) ship.available_missions += new_mission tally_mission_offer(new_mission, ship, "mission_offered") // round metrics, voidcrew/modules/metrics/mission_metrics.dm + return TRUE /** * The zone band the next offer should prefer, rolled per offer. @@ -96,11 +103,11 @@ SUBSYSTEM_DEF(missions) * Returns a new mission datum, or null if none available. * * preferred_zone - ZONE_* band the offer should aim at where it can, or null */ -/datum/controller/subsystem/missions/proc/generate_random_mission(preferred_zone) +/datum/controller/subsystem/missions/proc/generate_random_mission(preferred_zone, posting_zone) var/mission_type = get_weighted_mission_type() if(!mission_type) return null - return create_mission(mission_type, preferred_zone) + return create_mission(mission_type, preferred_zone, posting_zone) /** * Selects a random mission type based on weight. @@ -136,10 +143,10 @@ SUBSYSTEM_DEF(missions) * Creates a new mission of the specified type. * * mission_type - The type path of the mission to create */ -/datum/controller/subsystem/missions/proc/create_mission(mission_type, preferred_zone) +/datum/controller/subsystem/missions/proc/create_mission(mission_type, preferred_zone, posting_zone) if(!mission_type) return null - var/datum/mission/mission = new mission_type(null, preferred_zone) + var/datum/mission/mission = new mission_type(null, preferred_zone, posting_zone) // Some mission types (e.g. recovery) can fail generation if no valid target exists if(mission.generation_failed) qdel(mission) @@ -147,21 +154,14 @@ SUBSYSTEM_DEF(missions) return mission /** - * Force-generates new available missions for a specific ship. - * Clears existing available missions and generates fresh ones. + * Requests a scheduled refresh for a specific ship; never bypasses its timer. * * ship - The ship to regenerate missions for */ /datum/controller/subsystem/missions/proc/force_refresh_ship_missions(obj/structure/overmap/ship/ship) if(!ship || istype(ship, /obj/structure/overmap/ship/npc)) return - // Delete existing available missions - for(var/datum/mission/mission as anything in ship.available_missions) - if(!QDELETED(mission)) - qdel(mission) - ship.available_missions = list() - - refresh_ship_missions(ship) + return refresh_ship_missions(ship) /// Retain or reserve one valid green travel job; never exceed the board's five slots. /datum/controller/subsystem/missions/proc/ensure_safe_exploration_offer(obj/structure/overmap/ship/ship) diff --git a/voidcrew/modules/missions/mission_board.dm b/voidcrew/modules/missions/mission_board.dm index 2228c4b2308..cc3580e8133 100644 --- a/voidcrew/modules/missions/mission_board.dm +++ b/voidcrew/modules/missions/mission_board.dm @@ -113,7 +113,7 @@ balloon_alert(user, "[live_beacons] beacon[live_beacons > 1 ? "s" : ""] linked") playsound(src, 'sound/machines/ding.ogg', 50, TRUE) else if(linked) - balloon_alert(user, "linked - no objective marked yet") + balloon_alert(user, "signal pending") else // A hunt at a trader outpost has no tracker by design: say so rather than sound broken var/why_none = bounty_gps_refusal(ship) @@ -139,7 +139,7 @@ data["active_count"] = length(ship.active_missions) data["has_pad"] = !!linked_pad data["has_mod_gps"] = !!get_worn_mod_gps(user) - data["refresh_cooldown_remaining"] = max(0, round((MISSION_REFRESH_COOLDOWN - (world.time - ship.last_mission_refresh)) / 10)) + data["refresh_cooldown_remaining"] = max(0, round((ship.next_mission_refresh - world.time) / 10)) // Available missions data["available_missions"] = list() @@ -188,6 +188,11 @@ if(!ship) balloon_alert(usr, "console not on a ship!") return TRUE + if(!is_operational || !ui.user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) + return TRUE + if(!ship.is_ship_crew(ui.user)) + balloon_alert(ui.user, "Crew access only.") + return TRUE switch(action) if("link_mod_gps") @@ -232,11 +237,9 @@ return TRUE if("refresh") - var/cooldown_remaining = MISSION_REFRESH_COOLDOWN - (world.time - ship.last_mission_refresh) - if(cooldown_remaining > 0) - balloon_alert(usr, "wait [round(cooldown_remaining / 10)]s") + if(world.time < ship.next_mission_refresh) + balloon_alert(usr, "Offer closed.") return TRUE - ship.last_mission_refresh = world.time record_mission_board_refreshed(ship, usr) // round metrics, voidcrew/modules/metrics/mission_metrics.dm SSmissions.force_refresh_ship_missions(ship) balloon_alert(usr, "missions refreshed!") @@ -322,7 +325,7 @@ var/obj/item/ship_key/key = locate() in linked_pad.get_items_on_pad() if(!key) - balloon_alert(usr, "place captain's key on pad!") + balloon_alert(usr, "captain's key missing!") return TRUE // Find what bounty this ship is hunting (ships can only have one) @@ -470,7 +473,7 @@ // Get items on pad var/list/items_on_pad = linked_pad.get_items_on_pad() if(!length(items_on_pad)) - balloon_alert(usr, "place items on pad first!") + balloon_alert(usr, "shipment missing!") return TRUE // Create the offer diff --git a/voidcrew/modules/missions/missions/big_game_hunt.dm b/voidcrew/modules/missions/missions/big_game_hunt.dm index 6d864d23e66..9653298a019 100644 --- a/voidcrew/modules/missions/missions/big_game_hunt.dm +++ b/voidcrew/modules/missions/missions/big_game_hunt.dm @@ -23,17 +23,18 @@ /datum/mission/big_game_hunt name = "Big Game Hunt" + guarded_prize_family = "hunt" weight = 7 mission_limit = 1 duration = 40 MINUTES - voucher_count = 2 + voucher_count = 0 quest_lost_policy = MISSION_QUEST_LOST_FAIL gps_tag_prefix = "TROPHY" // Green-band pay a notch over field_expedition: staking a lure and killing // an apex beast beats pulling a probe core. The zone table makes a // Lawless-zone hunt a serious payday. - value_min = 1000 - value_max = 1400 + value_min = 650 + value_max = 850 /// Per-planet hunt tables, keyed by /datum/overmap/planet typepath: /// the apex beast, its entourage pool, its possible names, the trophy the @@ -163,7 +164,7 @@ /datum/mission/big_game_hunt/build_objectives() var/datum/mission_objective/goto_coords/approach = new - approach.arrival_message = "On station over the hunting ground. Take the lure down to the surface and stake it in open ground." + approach.arrival_message = "On station over the hunting ground." add_objective(approach) lure = new @@ -197,12 +198,7 @@ var/datum/mission_target/planet/planet_target = target var/planet_name = istype(planet_target) ? (planet_target.planet?.name || "the planet") : "the planet" name = "Big Game Hunt: [objective_name]" - desc = "[flavor_line] \ - [objective_name] holds the [hunt_row["ground"]] of the [planet_name] at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - A hunting lure lands on your mission pad when you accept. Fly out, use the lure in hand to stake it in open ground on the surface, and kill [objective_name] when it arrives. \ - The guild pays on the [trophy_part] - bring it back to the mission pad. \ - Payment includes [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]. \ - Tap a GPS unit on the mission board to follow the hunt's beacon ([gps_tag])." + desc = "Hunt [objective_name] on [planet_name] at ([target.target_x], [target.target_y]) in the [target_zone_name]. The guild wants its [trophy_part]." /datum/mission/big_game_hunt/waypoint_label() return "Hunt: [objective_name]" @@ -251,7 +247,7 @@ kit.objective_ref = WEAKREF(src) // Losing the lure voids the hunt (and points the GPS chain at it meanwhile) mission.register_quest_atom(kit) - notify_crew("Hunting lure delivered to your mission pad. Stake it in open ground on the hunt planet's surface.") + notify_crew("Hunting lure delivered.") return TRUE /// The lure was staked: record the spot for the kill step and advance @@ -353,8 +349,7 @@ */ /obj/item/hunting_lure name = "apex hunting lure" - desc = "A folding guild lure rig: chum reservoir, pheromone wicks and a seismic thumper. \ - Use it in hand to stake it in open ground on the contracted planet, then get somewhere defensible." + desc = "A folding guild lure rig with a chum reservoir, pheromone wicks and a seismic thumper." icon = 'voidcrew/modules/missions/icons/recovery.dmi' icon_state = "recovery_anchored" w_class = WEIGHT_CLASS_NORMAL @@ -398,7 +393,7 @@ */ /obj/item/mission_recovery/trophy name = "hunting trophy" - desc = "A field-dressed piece of something enormous, tagged and sealed for the guild's assayer. The mission pad will accept it." + desc = "A field-dressed piece of something enormous, tagged for the guild's assayer." icon_state = "recovery" w_class = WEIGHT_CLASS_BULKY diff --git a/voidcrew/modules/missions/missions/delivery.dm b/voidcrew/modules/missions/missions/delivery.dm index 2b05aebd61b..08357971d3f 100644 --- a/voidcrew/modules/missions/missions/delivery.dm +++ b/voidcrew/modules/missions/missions/delivery.dm @@ -6,19 +6,35 @@ */ /datum/mission/delivery name = "Delivery Contract" - weight = 0 + weight = 10 /// The rolled ask (kept for UI keys) - var/required_type = /obj/item/stack/ore/iron - var/required_name = "iron ore" + var/required_type = /obj/item/stack/spice_pods + var/required_name = "spice pods" var/required_amount = 1 + /// Equal row weights; these asks accept stored goods and pay flat credits. + var/static/list/delivery_asks = list( + list("type" = /obj/item/stack/spice_pods, "amount" = 3, "difficulty" = MISSION_DIFFICULTY_EASY, "value_min" = 320, "value_max" = 400), + list("type" = /obj/item/stack/sheet/sinew, "amount" = 2, "difficulty" = MISSION_DIFFICULTY_EASY, "value_min" = 260, "value_max" = 340), + list("type" = /obj/item/stack/sheet/animalhide/goliath_hide, "amount" = 2, "difficulty" = MISSION_DIFFICULTY_MEDIUM, "value_min" = 400, "value_max" = 550), + list("type" = /obj/item/stack/glacial_core, "amount" = 3, "difficulty" = MISSION_DIFFICULTY_MEDIUM, "value_min" = 550, "value_max" = 700), + list("type" = /obj/item/stack/telecrystal_raw, "amount" = 5, "difficulty" = MISSION_DIFFICULTY_HARD, "value_min" = 1500, "value_max" = 1700), + list("type" = /obj/item/sea_crystal, "amount" = 1, "difficulty" = MISSION_DIFFICULTY_HARD, "value_min" = 1000, "value_max" = 1200), + list("type" = /obj/item/documents/syndicate, "amount" = 1, "difficulty" = MISSION_DIFFICULTY_HARD, "value_min" = 3000, "value_max" = 3300), + ) /datum/mission/delivery/generate_details() - // Suspended until compliant replacement rows receive their own reward design. - generation_failed = TRUE + var/list/ask = pick(delivery_asks) + required_type = ask["type"] + var/obj/item/goods = required_type + required_name = initial(goods.name) + required_amount = ask["amount"] + difficulty = ask["difficulty"] + value_min = ask["value_min"] + value_max = ask["value_max"] /datum/mission/delivery/build_objectives() - var/datum/mission_objective/deliver/ask = new + var/datum/mission_objective/deliver/console/ask = new ask.required_type = required_type ask.required_name = required_name ask.required_amount = required_amount diff --git a/voidcrew/modules/missions/missions/exploration.dm b/voidcrew/modules/missions/missions/exploration.dm index c4771fbddf2..0286df3c74c 100644 --- a/voidcrew/modules/missions/missions/exploration.dm +++ b/voidcrew/modules/missions/missions/exploration.dm @@ -9,8 +9,8 @@ name = "Exploration Contract" weight = 10 // Green-band pay; apply_zone_scaling() raises it for deeper zones - value_min = 400 - value_max = 700 + value_min = 150 + value_max = 250 /datum/mission/exploration/setup_target() var/datum/mission_target/coords/coords = new(src) @@ -31,7 +31,7 @@ /datum/mission/exploration/update_text() name = "Exploration Contract: ([target.target_x], [target.target_y])" - desc = "Chart the sector at coordinates ([target.target_x], [target.target_y]) in the [target_zone_name]. Fly to this location, then return to the mission board to collect the fee." + desc = "Chart the sector at ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/exploration/waypoint_label() return "Survey site" diff --git a/voidcrew/modules/missions/missions/field_expedition.dm b/voidcrew/modules/missions/missions/field_expedition.dm index 0f13e73df2d..81fd90250d9 100644 --- a/voidcrew/modules/missions/missions/field_expedition.dm +++ b/voidcrew/modules/missions/missions/field_expedition.dm @@ -14,13 +14,13 @@ name = "Field Expedition" weight = 9 mission_limit = 2 - voucher_count = 1 + voucher_count = 0 quest_lost_policy = MISSION_QUEST_LOST_RETARGET gps_tag_prefix = "XPDN" // Green-band pay, a notch over plain recovery: planets mean weather, // wildlife and a walk from the dock - value_min = 800 - value_max = 1100 + value_min = 500 + value_max = 700 /// zone_mobs theme that may answer the pickup var/wave_theme @@ -69,10 +69,7 @@ /datum/mission/field_expedition/update_text() name = "Field Expedition: [objective_name]" - desc = "Our [objective_name] is down on the planet at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - Land, locate the beacon-marked salvage and bring it to the mission pad. Picking it up may draw an ambush. \ - Payment includes [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]. \ - Tap a GPS unit on the mission board to receive the salvage's beacon ([gps_tag])." + desc = "Recover our [objective_name] from the planet at ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/field_expedition/waypoint_label() return "Expedition: [objective_name]" diff --git a/voidcrew/modules/missions/missions/gas_harvest.dm b/voidcrew/modules/missions/missions/gas_harvest.dm index 1778415c4b6..15ca2f5a508 100644 --- a/voidcrew/modules/missions/missions/gas_harvest.dm +++ b/voidcrew/modules/missions/missions/gas_harvest.dm @@ -20,21 +20,22 @@ /// Moles asked for in one tank var/required_moles = 600 + var/static/list/gas_asks = list( + /datum/gas/plasma = list("moles" = list(600, 900), "value" = list(250, 350), "difficulty" = MISSION_DIFFICULTY_EASY, "vouchers" = 0), + /datum/gas/nitrogen = list("moles" = list(600, 900), "value" = list(220, 320), "difficulty" = MISSION_DIFFICULTY_EASY, "vouchers" = 0), + /datum/gas/water_vapor = list("moles" = list(600, 900), "value" = list(220, 320), "difficulty" = MISSION_DIFFICULTY_EASY, "vouchers" = 0), + /datum/gas/miasma = list("moles" = list(400, 700), "value" = list(300, 450), "difficulty" = MISSION_DIFFICULTY_MEDIUM, "vouchers" = 0), + /datum/gas/tritium = list("moles" = list(250, 450), "value" = list(450, 650), "difficulty" = MISSION_DIFFICULTY_MEDIUM, "vouchers" = 1), + /datum/gas/pluoxium = list("moles" = list(200, 350), "value" = list(650, 850), "difficulty" = MISSION_DIFFICULTY_HARD, "vouchers" = 1), + /datum/gas/nitrium = list("moles" = list(200, 350), "value" = list(650, 850), "difficulty" = MISSION_DIFFICULTY_HARD, "vouchers" = 1), + /datum/gas/hypernoblium = list("moles" = list(150, 300), "value" = list(750, 950), "difficulty" = MISSION_DIFFICULTY_HARD, "vouchers" = 1), + ) + /datum/mission/gas_harvest/get_archetype() return "procurement" /datum/mission/gas_harvest/generate_details() // Ask parameters per gas: moles band, pay band, difficulty, voucher - var/static/list/gas_asks = list( - /datum/gas/plasma = list("moles" = list(600, 900), "value" = list(800, 1200), "difficulty" = MISSION_DIFFICULTY_EASY, "vouchers" = 0), - /datum/gas/nitrogen = list("moles" = list(600, 900), "value" = list(700, 1100), "difficulty" = MISSION_DIFFICULTY_EASY, "vouchers" = 0), - /datum/gas/water_vapor = list("moles" = list(600, 900), "value" = list(700, 1100), "difficulty" = MISSION_DIFFICULTY_EASY, "vouchers" = 0), - /datum/gas/miasma = list("moles" = list(400, 700), "value" = list(900, 1400), "difficulty" = MISSION_DIFFICULTY_MEDIUM, "vouchers" = 0), - /datum/gas/tritium = list("moles" = list(250, 450), "value" = list(1500, 2200), "difficulty" = MISSION_DIFFICULTY_MEDIUM, "vouchers" = 1), - /datum/gas/pluoxium = list("moles" = list(200, 350), "value" = list(2000, 2800), "difficulty" = MISSION_DIFFICULTY_HARD, "vouchers" = 1), - /datum/gas/nitrium = list("moles" = list(200, 350), "value" = list(2000, 2800), "difficulty" = MISSION_DIFFICULTY_HARD, "vouchers" = 1), - /datum/gas/hypernoblium = list("moles" = list(150, 300), "value" = list(2400, 3200), "difficulty" = MISSION_DIFFICULTY_HARD, "vouchers" = 1), - ) // Only ask for gas somebody can actually go scoop: poll the live nebulas. // No nebula scan hit -> fall back to the common green-band gases. @@ -67,7 +68,4 @@ /datum/mission/gas_harvest/update_text() name = "Gas Harvest: [gas_name]" - var/voucher_line = voucher_count > 0 ? " Payment includes [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]." : "" - desc = "Deliver one handheld gas tank holding at least [required_moles] mol of [LOWER_TEXT(gas_name)] to the mission pad. \ - A ram scoop can harvest it while your ship holds still inside a matching nebula; transfer the gas from the pipe network into the tank. \ - Gas from any source counts, and mixtures are accepted if the requested gas meets the full quota in that one tank. We keep the tank and its contents.[voucher_line]" + desc = "Nebula sample requested: [required_moles] mol [LOWER_TEXT(gas_name)]." diff --git a/voidcrew/modules/missions/missions/live_capture.dm b/voidcrew/modules/missions/missions/live_capture.dm index bf2505fc5a5..395a0be4b27 100644 --- a/voidcrew/modules/missions/missions/live_capture.dm +++ b/voidcrew/modules/missions/missions/live_capture.dm @@ -42,17 +42,18 @@ /datum/mission/live_capture name = "Live Capture" + guarded_prize_family = "capture" weight = 8 mission_limit = 1 duration = 35 MINUTES - voucher_count = 1 + voucher_count = 0 quest_lost_policy = MISSION_QUEST_LOST_FAIL gps_tag_prefix = "FAUNA" // Green-band pay between field_expedition and big_game_hunt: harder than // pulling a probe core, gentler than killing an apex - the specimen is // smaller fauna, but you have to win WITHOUT the killing blow. - value_min = 900 - value_max = 1250 + value_min = 600 + value_max = 800 /// Per-planet capture tables, keyed by /datum/overmap/planet typepath: /// the specimen, the board-title form, the ask phrase, and the habitat @@ -150,7 +151,7 @@ /datum/mission/live_capture/build_objectives() var/datum/mission_objective/goto_coords/approach = new - approach.arrival_message = "On station over the habitat. Take the capture crate down to the surface and find the marked specimen." + approach.arrival_message = "On station over the habitat." add_objective(approach) capture = new @@ -168,12 +169,7 @@ var/datum/mission_target/planet/planet_target = target var/planet_name = istype(planet_target) ? (planet_target.planet?.name || "the planet") : "the planet" name = "Live Capture: [capture_row["title"]]" - desc = "[flavor_line] \ - The guild survey has tagged [objective_name] in the [capture_row["ground"]] of [planet_name] at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - A capture crate lands on your mission pad when you accept. Find the marked specimen and reduce it to [CAPTURE_HEALTH_FRACTION * 100]% health or less, or incapacitate it, while keeping it alive. \ - With combat mode off, use the crate on the tagged animal while it is on the ground. Bring the sealed crate to the mission pad with the specimen alive; its death voids the contract. \ - Payment includes [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]. \ - Tap a GPS unit on the mission board to follow the specimen's survey tag ([gps_tag])." + desc = "Bring back [objective_name] alive from [planet_name] at ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/live_capture/waypoint_label() return "Capture: [objective_name]" @@ -249,7 +245,7 @@ mission.bind_item(kit) // One crate per contract: losing it voids the capture RegisterSignal(kit, COMSIG_QDELETING, PROC_REF(on_crate_destroyed)) - notify_crew("Capture crate delivered to your mission pad. It only seals the survey-marked specimen, and only subdued.") + notify_crew("Capture crate delivered.") return TRUE /datum/mission_objective/field/capture_beast/spawn_field_objects(turf/spawn_turf) @@ -261,7 +257,7 @@ beast.npc_spawn_context.finalize() RegisterSignal(beast, COMSIG_LIVING_DEATH, PROC_REF(on_target_death)) mission.register_quest_atom(beast) - notify_crew("Survey tag live - the marked specimen is on the surface ([mission.gps_tag]). Wear it down and crate it breathing.", type = SHIP_NOTIFY_WARNING, sound = 'voidcrew/sound/notify2.ogg') + notify_crew("Specimen sighted ([mission.gps_tag]).", type = SHIP_NOTIFY_WARNING, sound = 'voidcrew/sound/notify2.ogg') /** * The specimen died before delivery: the client pays for live capture only. @@ -296,7 +292,7 @@ if(deliver_objective) deliver_objective.crate = crate deliver_objective.beast = beast - notify_crew("Specimen sealed and stable in suspension. Bring the crate back to the mission pad alive.", sound = 'voidcrew/sound/notify2.ogg') + notify_crew("Specimen secured.", sound = 'voidcrew/sound/notify2.ogg') complete() /datum/mission_objective/field/capture_beast/get_progress_string() @@ -446,8 +442,7 @@ */ /obj/item/mission_recovery/capture_crate name = "capture crate" - desc = "A guild-issue xenofauna transport pod: reinforced shell, intake maw, suspension-field emitter. \ - It only takes the survey-marked specimen, and only once it's been worn down. After it seals, nobody opens it but the client's assayer." + desc = "A guild-issue xenofauna transport pod with a reinforced shell and suspension-field emitter." icon_state = "capture_crate" base_icon_state = "capture_crate" w_class = WEIGHT_CLASS_BULKY diff --git a/voidcrew/modules/missions/missions/poacher_bust.dm b/voidcrew/modules/missions/missions/poacher_bust.dm index fa9552c3dff..878b2b98581 100644 --- a/voidcrew/modules/missions/missions/poacher_bust.dm +++ b/voidcrew/modules/missions/missions/poacher_bust.dm @@ -33,17 +33,18 @@ */ /datum/mission/poacher_bust name = "Poacher Bust" + guarded_prize_family = "poacher" weight = 7 mission_limit = 1 duration = 40 MINUTES - voucher_count = 2 + voucher_count = 0 quest_lost_policy = MISSION_QUEST_LOST_FAIL gps_tag_prefix = "WARDN" // Green-band pay between field_expedition and big_game_hunt: a squad // fight plus a counted evidence haul, but no elite at the end of it. // The zone table makes a Lawless-zone bust a serious payday. - value_min = 900 - value_max = 1200 + value_min = 600 + value_max = 800 /// Per-planet bust tables, keyed by /datum/overmap/planet typepath: the /// protected species (named for the planet's actual fauna), the hunting @@ -197,7 +198,7 @@ /datum/mission/poacher_bust/build_objectives() var/datum/mission_objective/goto_coords/approach = new - approach.arrival_message = "On station over the poaching grounds. Take a ground team down and sweep for [objective_name]'s camp." + approach.arrival_message = "On station over the poaching grounds." add_objective(approach) wipe = new @@ -238,11 +239,7 @@ var/datum/mission_target/planet/planet_target = target var/planet_name = istype(planet_target) ? (planet_target.planet?.name || "the planet") : "the planet" name = "Poacher Bust: [objective_name]" - desc = "[flavor_line] \ - Warden's warrant: [objective_name] are running an illegal [protected_species] harvest from a camp in the [bust_row["ground"]] of [planet_name] at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - Kill the whole squad to unlock their trophy cache, then return all [evidence_count] pieces of tagged evidence to the mission pad, one at a time. Destroying any evidence voids the contract. \ - Payment includes [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]. \ - Tap a GPS unit on the mission board to follow the case beacon ([gps_tag])." + desc = "Wanted dead: [objective_name], poaching [protected_species] on [planet_name] at ([target.target_x], [target.target_y]) in the [target_zone_name]. Recover [evidence_count] pieces of evidence." /datum/mission/poacher_bust/waypoint_label() return "Bust: [objective_name]" @@ -456,7 +453,7 @@ cache.locked = FALSE cache.update_appearance() cache.visible_message(span_notice("[cache]'s mag-seal releases with a hiss.")) - notify_crew("Camp cleared - all [squad_size] poachers accounted for. Warden override sent: the trophy cache is unlocked. Recover the evidence and return it to the mission pad.") + notify_crew("Camp cleared. Trophy cache unlocked.") /datum/mission_objective/field/wipe_camp/get_progress_string() if(!spawned) @@ -538,7 +535,7 @@ */ /obj/item/mission_recovery/poacher_evidence name = "tagged evidence" - desc = "A confiscated poaching trophy under a warden-service evidence tag. Destroying it kills the case - the mission pad will accept it." + desc = "A confiscated poaching trophy under a warden-service evidence tag." icon_state = "recovery" w_class = WEIGHT_CLASS_NORMAL @@ -552,7 +549,7 @@ */ /obj/structure/closet/crate/secure/poacher_cache name = "sealed trophy cache" - desc = "A battered cargo crate under a poacher outfit's mag-seal. The warden service can override the lock once the camp is confirmed clear." + desc = "A battered cargo crate under a poacher outfit's mag-seal." /obj/structure/closet/crate/secure/poacher_cache/togglelock(mob/living/user, silent) if(locked) diff --git a/voidcrew/modules/missions/missions/prospect_stake.dm b/voidcrew/modules/missions/missions/prospect_stake.dm index 45b984c5269..adcc1ff938b 100644 --- a/voidcrew/modules/missions/missions/prospect_stake.dm +++ b/voidcrew/modules/missions/missions/prospect_stake.dm @@ -14,23 +14,21 @@ */ /datum/mission/prospect_stake name = "Prospect Stake" + guarded_prize_family = "stake" weight = 6 mission_limit = 1 duration = 40 MINUTES quest_lost_policy = MISSION_QUEST_LOST_FAIL // the beacon IS the contract gps_tag_prefix = "CLAIM" // Top of the mission pay curve - it's an announced fight - value_min = 2200 - value_max = 3000 - voucher_count = 3 + value_min = 1400 + value_max = 1800 + voucher_count = 1 /// zone_mobs theme answering the claim var/wave_theme /// The defense objective (kit dispensing at start) var/datum/mission_objective/claim_defense/defense - /// Whether this stake pays a ship-part prize crate instead of vouchers - var/pays_ship_parts = FALSE - /datum/mission/prospect_stake/Destroy() defense = null return ..() @@ -54,16 +52,9 @@ /datum/mission/prospect_stake/generate_details() objective_name = "notarized claim deed" wave_theme = pick_weight(MISSION_WAVE_THEMES) - // Red-zone stakes can trade the voucher stack for a ship-part crate - if(difficulty == MISSION_DIFFICULTY_HARD) - voucher_count = 4 - if(prob(35)) - pays_ship_parts = TRUE - voucher_count = 0 - /datum/mission/prospect_stake/build_objectives() var/datum/mission_objective/goto_coords/approach = new - approach.arrival_message = "On station. Deploy the claim beacon while holding these coordinates." + approach.arrival_message = "On station over the claim." add_objective(approach) defense = new defense.wave_theme = wave_theme @@ -75,23 +66,11 @@ /datum/mission/prospect_stake/update_text() name = "Prospect Stake: ([target.target_x], [target.target_y])" - desc = "File our mineral-rights claim at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - A claim beacon kit lands on your mission pad when you sign. Fly out, deploy it aboard your ship while holding at those coordinates, and keep it in one piece for [defense ? round(defense.defend_duration / (1 MINUTES)) : 8] minutes. The clock only runs while the ship holds station. \ - The filing goes out on Wideband, so [target_zone_name == ZONE_NAME_RED ? "every pirate in red space will know exactly where you are" : "the whole lane will hear it"]. Expect boarders. \ - The deed prints at the beacon once the claim matures; bring it to the mission pad. \ - Pays [pays_ship_parts ? "a bonded crate of ship-grade components" : "[voucher_count] trade vouchers"] on top of the fee." + desc = "File our mineral-rights claim at ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/prospect_stake/waypoint_label() return "Prospect stake" -/datum/mission/prospect_stake/distribute_rewards(atom/reward_anchor) - ..() - if(pays_ship_parts) - var/turf/reward_turf = get_turf(reward_anchor) - if(reward_turf) - note_metric_ship_parts(spawn_ship_part_prize(reward_turf)) // round metrics, voidcrew/modules/metrics/mission_metrics.dm - flash_reward_anchor(reward_anchor) - /** * # Claim Beacon Kit * @@ -101,7 +80,7 @@ */ /obj/item/claim_beacon_kit name = "claim beacon kit" - desc = "A folded prospecting claim beacon, bonded and pre-registered. Use it in hand while your ship holds at the contracted coordinates. Filings are public, so expect company." + desc = "A folded prospecting claim beacon, bonded and pre-registered." icon = 'voidcrew/modules/missions/icons/recovery.dmi' icon_state = "recovery_anchored" w_class = WEIGHT_CLASS_BULKY @@ -140,7 +119,7 @@ */ /obj/structure/mission_claim_beacon name = "prospecting claim beacon" - desc = "A registered mineral-rights beacon, broadcasting its claim on every open channel. Keeping it in one piece is the whole job." + desc = "A registered mineral-rights beacon, broadcasting its claim on every open channel." icon = 'voidcrew/modules/missions/icons/recovery.dmi' icon_state = "survey_pylon" anchored = TRUE @@ -189,9 +168,9 @@ if(!COOLDOWN_FINISHED(src, offstation_warn_cooldown)) return COOLDOWN_START(src, offstation_warn_cooldown, 15 SECONDS) - balloon_alert_to_viewers("claim clock paused - off station!") + balloon_alert_to_viewers("off station!") var/datum/mission_objective/claim_defense/objective = objective_ref?.resolve() - objective?.notify_crew("Claim beacon reports the ship off station - the clock is paused.", type = SHIP_NOTIFY_WARNING, sound = 'voidcrew/sound/notify2.ogg') + objective?.notify_crew("Claim beacon reports the ship off station.", type = SHIP_NOTIFY_WARNING, sound = 'voidcrew/sound/notify2.ogg') /// The claim matured: stop being a mission object, stay as scenery /obj/structure/mission_claim_beacon/proc/retire() diff --git a/voidcrew/modules/missions/missions/recovery.dm b/voidcrew/modules/missions/missions/recovery.dm index f7e081bd1d2..a018e34a098 100644 --- a/voidcrew/modules/missions/missions/recovery.dm +++ b/voidcrew/modules/missions/missions/recovery.dm @@ -12,12 +12,12 @@ name = "Recovery Contract" weight = 10 mission_limit = 3 - voucher_count = 1 + voucher_count = 0 quest_lost_policy = MISSION_QUEST_LOST_RETARGET gps_tag_prefix = "RCVRY" // Green-band pay; the zone table scales it up - value_min = 700 - value_max = 1000 + value_min = 450 + value_max = 650 /datum/mission/recovery/setup_target() var/datum/mission_target/space_ruin/ruin_target = new(src) @@ -43,9 +43,7 @@ /datum/mission/recovery/update_text() name = "Recovery Contract: [objective_name]" - desc = "Recover the [objective_name] from the signal at ([target.target_x], [target.target_y]) in the [target_zone_name], and return it to the mission pad. \ - Payment includes [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]. \ - Tap a GPS unit on the mission board to receive the objective's beacon ([gps_tag])." + desc = "Recover the [objective_name] from ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/recovery/waypoint_label() return "Recovery: [objective_name]" @@ -65,6 +63,9 @@ */ /datum/mission/recovery/kill name = "Kill Contract" + value_min = 500 + value_max = 700 + guarded_prize_family = "kill" weight = 8 mission_limit = 2 gps_tag_prefix = "HUNT" @@ -125,10 +126,7 @@ /datum/mission/recovery/kill/update_text() name = "Kill Contract: [objective_name]" - desc = "Hunt down [objective_name], holed up at the signal at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - Return their identification tag to the mission pad. \ - Payment includes [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]. \ - Tap a GPS unit on the mission board to receive the target's transponder beacon ([gps_tag])." + desc = "Wanted dead: [objective_name]. Last seen at ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/recovery/kill/waypoint_label() return "Hunt: [objective_name]" @@ -142,7 +140,7 @@ */ /obj/item/mission_recovery name = "recovery objective" - desc = "Salvage flagged for recovery under a standing contract. The mission pad will accept it." + desc = "Salvage flagged for recovery under a standing contract." icon = 'voidcrew/modules/missions/icons/recovery.dmi' icon_state = "recovery" inhand_icon_state = "recovery" @@ -163,13 +161,13 @@ // Sites get shared, so somebody else's objective can end up in your hands. // Say whose it is rather than letting the pad refuse it with no explanation. if(mission.servant) - . += span_notice("Filed to the [mission.servant.name]. Only that vessel's pad will take it.") + . += span_notice("Filed to the [mission.servant.name].") else . += span_warning("The contract this was tagged for has expired.") /obj/item/mission_recovery/proof name = "identification tag" - desc = "Proof that somebody's career ended violently. The mission pad will accept it." + desc = "Proof that somebody's career ended violently." icon_state = "recovery_proof" inhand_icon_state = null w_class = WEIGHT_CLASS_TINY diff --git a/voidcrew/modules/missions/missions/recovery_variants.dm b/voidcrew/modules/missions/missions/recovery_variants.dm index 09300188225..7a38e0c38bc 100644 --- a/voidcrew/modules/missions/missions/recovery_variants.dm +++ b/voidcrew/modules/missions/missions/recovery_variants.dm @@ -29,6 +29,9 @@ /datum/mission/recovery/survey name = "Survey Contract" + value_min = 550 + value_max = 750 + guarded_prize_family = "waves" weight = 8 mission_limit = 2 gps_tag_prefix = "SRVY" @@ -61,11 +64,7 @@ /datum/mission/recovery/survey/update_text() name = "Survey Contract: [objective_name]" - desc = "Our probes seeded [chain ? chain.points_total : 3] survey pylons through the signal at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - Calibrate each with an empty hand, in any order. Each completed calibration draws a wave of hostiles, so go armed. \ - The last pylon you finish prints the survey core; bring that back to the mission pad. \ - Payment includes [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]. \ - Tap a GPS unit on the mission board to receive a beacon for every pylon still standing ([gps_tag])." + desc = "Survey requested at ([target.target_x], [target.target_y]) in the [target_zone_name]: [objective_name]." /datum/mission/recovery/survey/waypoint_label() return "Survey: [objective_name]" @@ -78,7 +77,7 @@ */ /obj/structure/mission_survey_pylon name = "survey pylon" - desc = "A tripod-mounted survey unit, dropped from orbit and waiting on someone to calibrate it. The routine is very loud." + desc = "A tripod-mounted survey unit, dropped from orbit." icon = 'voidcrew/modules/missions/icons/recovery.dmi' icon_state = "survey_pylon" anchored = TRUE @@ -94,7 +93,7 @@ if(calibrated) . += span_notice("Its display reads: SURVEY SEGMENT COMPLETE.") else - . += span_notice("Its display blinks: AWAITING FIELD CALIBRATION. Use an empty hand to start it. The routine takes a while, and it is loud.") + . += span_notice("Its display blinks: AWAITING FIELD CALIBRATION.") /obj/structure/mission_survey_pylon/attack_hand(mob/living/user, list/modifiers) . = ..() @@ -133,6 +132,9 @@ /datum/mission/recovery/extraction name = "Extraction Contract" + value_min = 500 + value_max = 700 + guarded_prize_family = "waves" weight = 8 mission_limit = 2 gps_tag_prefix = "XTRC" @@ -174,10 +176,7 @@ /datum/mission/recovery/extraction/update_text() name = "Extraction Contract: [objective_name]" - desc = "A [objective_name] is bolted down inside the signal at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - Use an empty hand to start wrenching it loose. It takes a while and it will trip the site's alarm, so plan for company, then haul it to the mission pad. \ - Payment includes [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]. \ - Tap a GPS unit on the mission board to receive the cargo's beacon ([gps_tag])." + desc = "Recover the [objective_name] from ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/recovery/extraction/waypoint_label() return "Extraction: [objective_name]" @@ -192,7 +191,7 @@ var/turf/site = get_turf(cargo) new wave_theme(site, list(1, 2)) second_wave_timer = addtimer(CALLBACK(src, PROC_REF(second_wave), site), EXTRACTION_SECOND_WAVE_DELAY, TIMER_STOPPABLE) - servant?.ship_notify("[name]: site security tripped. Expect resistance in waves.", "MISSION UPDATE", SHIP_NOTIFY_WARNING, 'voidcrew/sound/notify2.ogg', 50) + servant?.ship_notify("[name]: site security alarm triggered.", "MISSION UPDATE", SHIP_NOTIFY_WARNING, 'voidcrew/sound/notify2.ogg', 50) /datum/mission/recovery/extraction/proc/second_wave(turf/site) second_wave_timer = null @@ -207,7 +206,7 @@ * the deck. Unbolting is a channel that trips the mission's alarm. */ /obj/item/mission_recovery/anchored - desc = "Flagged for recovery under a standing contract, and bolted to the deck. Getting it loose takes a while, and it won't be quiet." + desc = "Contracted salvage, bolted to the deck." icon_state = "recovery_anchored" anchored = TRUE w_class = WEIGHT_CLASS_BULKY @@ -215,7 +214,7 @@ /obj/item/mission_recovery/anchored/examine(mob/user) . = ..() if(anchored) - . += span_warning("It is bolted down. Use an empty hand to start wrenching it free.") + . += span_warning("It is bolted down.") /obj/item/mission_recovery/anchored/attack_hand(mob/living/user, list/modifiers) if(!anchored) diff --git a/voidcrew/modules/missions/missions/rescue.dm b/voidcrew/modules/missions/missions/rescue.dm index 3e542031045..0a3e7b6527a 100644 --- a/voidcrew/modules/missions/missions/rescue.dm +++ b/voidcrew/modules/missions/missions/rescue.dm @@ -13,15 +13,15 @@ name = "Rescue Contract" weight = 8 mission_limit = 2 - voucher_count = 1 + voucher_count = 0 quest_lost_policy = MISSION_QUEST_LOST_RETARGET gps_tag_prefix = "RESQ" // The survivor cannot defend themselves, so this contract does not share a // wreck with a bounty's entourage or anybody else's spawns exclusive_site = TRUE // Green-band base pay - value_min = 800 - value_max = 1100 + value_min = 650 + value_max = 850 /datum/mission/rescue/setup_target() var/datum/mission_target/space_ruin/ruin_target = new(src) @@ -46,7 +46,7 @@ /datum/mission/rescue/update_text() name = "Rescue Contract: [objective_name]" - desc = "A [objective_name]'s survival beacon is still pinging at ([target.target_x], [target.target_y]) in the [target_zone_name]. Bring them home alive." + desc = "Bring [objective_name] home. Last signal at ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/rescue/waypoint_label() return "Rescue: [objective_name]" @@ -97,9 +97,9 @@ . = ..() var/mob/following = following_ref?.resolve() if(following) - . += span_notice("They're sticking close to [following]. An empty hand tells them to stay put.") + . += span_notice("They're sticking close to [following].") else - . += span_notice("Offer them an empty hand and they'll follow you.") + . += span_notice("They look lost.") /mob/living/basic/mission_survivor/attack_hand(mob/living/user, list/modifiers) . = ..() diff --git a/voidcrew/modules/missions/missions/research.dm b/voidcrew/modules/missions/missions/research.dm index d366d7248a0..6d0eb139800 100644 --- a/voidcrew/modules/missions/missions/research.dm +++ b/voidcrew/modules/missions/missions/research.dm @@ -85,6 +85,17 @@ /// The scan objective, for UI progress keys var/datum/mission_objective/scan_celestial/scan + var/static/list/telemetry_asks = list( + list("type" = "nebulas", "name" = "nebulas", "name_singular" = "nebula", "amount" = 2, "research" = MISSION_RESEARCH_PAY_LOW, "value_min" = 60, "value_max" = 100, "difficulty" = MISSION_DIFFICULTY_EASY), + list("type" = "asteroids", "name" = "asteroid fields", "name_singular" = "asteroid field", "amount" = 2, "research" = MISSION_RESEARCH_PAY_LOW, "value_min" = 60, "value_max" = 100, "difficulty" = MISSION_DIFFICULTY_EASY), + list("type" = "any", "name" = "celestial objects", "name_singular" = "celestial object", "amount" = 3, "research" = MISSION_RESEARCH_PAY_LOW, "value_min" = 80, "value_max" = 120, "difficulty" = MISSION_DIFFICULTY_EASY), + list("type" = "planets", "name" = "planets", "name_singular" = "planet", "amount" = 2, "research" = MISSION_RESEARCH_PAY_MEDIUM, "value_min" = 100, "value_max" = 160, "difficulty" = MISSION_DIFFICULTY_MEDIUM), + list("type" = "space_ruins", "name" = "space ruins", "name_singular" = "space ruin", "amount" = 2, "research" = MISSION_RESEARCH_PAY_MEDIUM, "value_min" = 100, "value_max" = 160, "difficulty" = MISSION_DIFFICULTY_MEDIUM), + list("type" = "electric_storms", "name" = "electrical storms", "name_singular" = "electrical storm", "amount" = 2, "research" = MISSION_RESEARCH_PAY_MEDIUM, "value_min" = 100, "value_max" = 160, "difficulty" = MISSION_DIFFICULTY_MEDIUM), + list("type" = "emp_storms", "name" = "EMP storms", "name_singular" = "EMP storm", "amount" = 2, "research" = MISSION_RESEARCH_PAY_HIGH, "value_min" = 160, "value_max" = 240, "difficulty" = MISSION_DIFFICULTY_HARD), + list("type" = "stars", "name" = "stars", "name_singular" = "star", "amount" = 1, "research" = MISSION_RESEARCH_PAY_HIGH, "value_min" = 100, "value_max" = 160, "difficulty" = MISSION_DIFFICULTY_HARD), + ) + /datum/mission/research/telemetry/Destroy() scan = null return ..() @@ -96,16 +107,6 @@ // design: the crew is paid twice for one action, because the survey console has // already banked its own points for each of these scans (250 for a nebula, 1000 // for a star), and this contract is the bonus on top of that. - var/static/list/telemetry_asks = list( - list("type" = "nebulas", "name" = "nebulas", "name_singular" = "nebula", "amount" = 2, "research" = MISSION_RESEARCH_PAY_LOW, "value_min" = 150, "value_max" = 250, "difficulty" = MISSION_DIFFICULTY_EASY), - list("type" = "asteroids", "name" = "asteroid fields", "name_singular" = "asteroid field", "amount" = 2, "research" = MISSION_RESEARCH_PAY_LOW, "value_min" = 150, "value_max" = 250, "difficulty" = MISSION_DIFFICULTY_EASY), - list("type" = "any", "name" = "celestial objects", "name_singular" = "celestial object", "amount" = 3, "research" = MISSION_RESEARCH_PAY_LOW, "value_min" = 200, "value_max" = 300, "difficulty" = MISSION_DIFFICULTY_EASY), - list("type" = "planets", "name" = "planets", "name_singular" = "planet", "amount" = 2, "research" = MISSION_RESEARCH_PAY_MEDIUM, "value_min" = 300, "value_max" = 450, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = "space_ruins", "name" = "space ruins", "name_singular" = "space ruin", "amount" = 2, "research" = MISSION_RESEARCH_PAY_MEDIUM, "value_min" = 300, "value_max" = 450, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = "electric_storms", "name" = "electrical storms", "name_singular" = "electrical storm", "amount" = 2, "research" = MISSION_RESEARCH_PAY_MEDIUM, "value_min" = 300, "value_max" = 450, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = "emp_storms", "name" = "EMP storms", "name_singular" = "EMP storm", "amount" = 2, "research" = MISSION_RESEARCH_PAY_HIGH, "value_min" = 450, "value_max" = 700, "difficulty" = MISSION_DIFFICULTY_HARD), - list("type" = "stars", "name" = "stars", "name_singular" = "star", "amount" = 1, "research" = MISSION_RESEARCH_PAY_HIGH, "value_min" = 450, "value_max" = 700, "difficulty" = MISSION_DIFFICULTY_HARD), - ) var/list/ask = pick(telemetry_asks) target_type = ask["type"] @@ -128,10 +129,7 @@ /datum/mission/research/telemetry/update_text() var/display_name = required_amount == 1 ? target_name_singular : target_name name = "Telemetry Contract: [display_name]" - desc = "Use your ship's orbital survey console to scan [required_amount] [display_name] after accepting this contract. \ - Nothing to bring back - the contract settles at the mission board. \ - Pays [research_reward] research points as a data dossier, plus [value] credits in expenses. \ - Slot the dossier into an R&D console to bank the points." + desc = "Survey requested: [required_amount] [display_name]." /datum/mission/research/telemetry/get_ui_data() var/list/data = ..() @@ -157,8 +155,8 @@ research_origin = "anomalous physics" // Green band; the zone table scales both, then the anomaly's own hazard // multiplier is applied to the credits on top in generate_details(). - value_min = 500 - value_max = 800 + value_min = 350 + value_max = 550 // The most science on the board: the only contract that puts a live anomaly in // front of the crew, and the only one that gives up its core. research_reward = MISSION_RESEARCH_PAY_HIGH @@ -269,11 +267,7 @@ /datum/mission/research/containment/update_text() name = "Containment Contract: [anomaly_name]" - desc = "A [anomaly_name] has settled inside the derelict at ([target.target_x], [target.target_y]) in the [target_zone_name], and it is stable - it will still be there whenever you arrive. \ - [hazard_brief] \ - Neutralize it the standard way: read its field with a handheld analyzer for the frequency and code, dial those into a signaler, and trigger the signaler beside it. \ - It sheds its core when it goes. Bring that core to the mission pad. \ - Pays [research_reward] research points as a data dossier - slot it into an R&D console to bank them." + desc = "Recover a [anomaly_name] core from ([target.target_x], [target.target_y]) in the [target_zone_name]." /datum/mission/research/containment/waypoint_label() return "Containment: [anomaly_name]" @@ -292,12 +286,13 @@ name = "Core Sample Contract" weight = 7 mission_limit = 1 - voucher_count = 1 + voucher_count = 0 + guarded_prize_family = "waves" quest_lost_policy = MISSION_QUEST_LOST_RETARGET gps_tag_prefix = "STRAT" research_origin = "planetary geology" - value_min = 450 - value_max = 700 + value_min = 300 + value_max = 450 // Green band; the zone table scales it. Middle of the ladder: a real trip and a // fight for it, but the crew brings back rock rather than live physics. research_reward = MISSION_RESEARCH_PAY_MEDIUM @@ -342,11 +337,7 @@ /datum/mission/research/core_sample/update_text() name = "Core Sample Contract: [objective_name]" - desc = "We need a [objective_name] off the planet at ([target.target_x], [target.target_y]) in the [target_zone_name]. \ - Our drop seeded [chain ? chain.points_total : 3] survey pylons across one stretch of the surface. Calibrate each with an empty hand, in any order. \ - Each calibration draws a wave of hostiles, so go armed. The last pylon prints the [objective_name] core; bring that core to the mission pad. \ - Pays [research_reward] research points as a data dossier plus [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]. Slot the dossier into an R&D console to bank the points. \ - Tap a GPS unit on the mission board to receive a beacon for every pylon still standing ([gps_tag])." + desc = "Sample requested from ([target.target_x], [target.target_y]) in the [target_zone_name]: [objective_name]." /datum/mission/research/core_sample/waypoint_label() return "Core Sample: [objective_name]" diff --git a/voidcrew/modules/missions/missions/suppression.dm b/voidcrew/modules/missions/missions/suppression.dm index af7723ddb51..8d7f9bebc0d 100644 --- a/voidcrew/modules/missions/missions/suppression.dm +++ b/voidcrew/modules/missions/missions/suppression.dm @@ -13,7 +13,7 @@ name = "Suppression Sweep" weight = 8 mission_limit = 2 - voucher_count = 1 + voucher_count = 0 /// Kills asked for var/required_kills = 8 @@ -34,18 +34,20 @@ if(prob(30)) minimum_zone = ZONE_RED required_kills = rand(5, 7) - value_min = 1800 - value_max = 2600 + value_min = 1100 + value_max = 1500 difficulty = MISSION_DIFFICULTY_HARD target_zone_name = ZONE_NAME_RED else minimum_zone = ZONE_YELLOW required_kills = rand(7, 10) - value_min = 1100 - value_max = 1600 + value_min = 700 + value_max = 1000 difficulty = MISSION_DIFFICULTY_MEDIUM target_zone_name = ZONE_NAME_YELLOW + quote_zone = minimum_zone + /datum/mission/suppression/build_objectives() counter = new counter.required_kills = required_kills @@ -54,6 +56,4 @@ /datum/mission/suppression/update_text() name = "Suppression Sweep: [target_zone_name]" - desc = "Confirm [required_kills] pirate faction NPC kills in the [target_zone_name][minimum_zone == ZONE_YELLOW ? " or deeper" : ""] after accepting this contract. \ - Your crew must make the kill or have a living member nearby to confirm it. Player pirates and destroyed ships do not count. \ - Complete the full quota, then collect the contract payment at the mission board. Includes [voucher_count] trade voucher[voucher_count > 1 ? "s" : ""]." + desc = "Wanted dead: [required_kills] pirates in the [target_zone_name][minimum_zone == ZONE_YELLOW ? " or deeper" : ""]." diff --git a/voidcrew/modules/missions/missions/survey.dm b/voidcrew/modules/missions/missions/survey.dm index 8283b516d33..12f4a6bca63 100644 --- a/voidcrew/modules/missions/missions/survey.dm +++ b/voidcrew/modules/missions/missions/survey.dm @@ -16,39 +16,27 @@ /// The scan objective, for UI progress keys var/datum/mission_objective/scan_celestial/scan -/datum/mission/survey/Destroy() - scan = null - return ..() - -/datum/mission/survey/generate_details() - // Types match the keys from survey_research.survey_objects_by_type var/static/list/survey_targets = list( // Easy - common, easy to find objects - list("type" = "any", "name" = "celestial objects", "name_singular" = "celestial object", "amount" = 3, "value_min" = 400, "value_max" = 600, "difficulty" = MISSION_DIFFICULTY_EASY), - list("type" = "nebulas", "name" = "nebulas", "name_singular" = "nebula", "amount" = 2, "value_min" = 300, "value_max" = 500, "difficulty" = MISSION_DIFFICULTY_EASY), - list("type" = "asteroids", "name" = "asteroid fields", "name_singular" = "asteroid field", "amount" = 2, "value_min" = 400, "value_max" = 600, "difficulty" = MISSION_DIFFICULTY_EASY), + list("type" = "any", "name" = "celestial objects", "name_singular" = "celestial object", "amount" = 3, "value_min" = 100, "value_max" = 160, "difficulty" = MISSION_DIFFICULTY_EASY), + list("type" = "nebulas", "name" = "nebulas", "name_singular" = "nebula", "amount" = 2, "value_min" = 80, "value_max" = 120, "difficulty" = MISSION_DIFFICULTY_EASY), + list("type" = "asteroids", "name" = "asteroid fields", "name_singular" = "asteroid field", "amount" = 2, "value_min" = 100, "value_max" = 160, "difficulty" = MISSION_DIFFICULTY_EASY), // Medium - require more exploration or specific types - list("type" = "planets", "name" = "planets", "name_singular" = "planet", "amount" = 2, "value_min" = 700, "value_max" = 1000, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = "electric_storms", "name" = "electrical storms", "name_singular" = "electrical storm", "amount" = 2, "value_min" = 600, "value_max" = 900, "difficulty" = MISSION_DIFFICULTY_MEDIUM), - list("type" = "space_ruins", "name" = "space ruins", "name_singular" = "space ruin", "amount" = 2, "value_min" = 700, "value_max" = 1000, "difficulty" = MISSION_DIFFICULTY_MEDIUM), + list("type" = "planets", "name" = "planets", "name_singular" = "planet", "amount" = 2, "value_min" = 180, "value_max" = 260, "difficulty" = MISSION_DIFFICULTY_MEDIUM), + list("type" = "electric_storms", "name" = "electrical storms", "name_singular" = "electrical storm", "amount" = 2, "value_min" = 160, "value_max" = 240, "difficulty" = MISSION_DIFFICULTY_MEDIUM), + list("type" = "space_ruins", "name" = "space ruins", "name_singular" = "space ruin", "amount" = 2, "value_min" = 180, "value_max" = 260, "difficulty" = MISSION_DIFFICULTY_MEDIUM), // Hard - rare or dangerous objects - list("type" = "stars", "name" = "stars", "name_singular" = "star", "amount" = 1, "value_min" = 1200, "value_max" = 1800, "difficulty" = MISSION_DIFFICULTY_HARD), - list("type" = "emp_storms", "name" = "EMP storms", "name_singular" = "EMP storm", "amount" = 2, "value_min" = 1000, "value_max" = 1500, "difficulty" = MISSION_DIFFICULTY_HARD), - list("type" = "planets", "name" = "planets", "name_singular" = "planet", "amount" = 4, "value_min" = 1400, "value_max" = 2000, "difficulty" = MISSION_DIFFICULTY_HARD), + list("type" = "stars", "name" = "stars", "name_singular" = "star", "amount" = 1, "value_min" = 160, "value_max" = 240, "difficulty" = MISSION_DIFFICULTY_HARD), + list("type" = "emp_storms", "name" = "EMP storms", "name_singular" = "EMP storm", "amount" = 2, "value_min" = 240, "value_max" = 360, "difficulty" = MISSION_DIFFICULTY_HARD), + list("type" = "planets", "name" = "planets", "name_singular" = "planet", "amount" = 4, "value_min" = 320, "value_max" = 440, "difficulty" = MISSION_DIFFICULTY_HARD), ) - // Possible item rewards by difficulty - var/static/list/medium_rewards = list( - /obj/item/gun/ballistic/automatic/pistol, - /obj/item/gun/energy/laser/retro, - /obj/item/gun/ballistic/revolver, - ) - var/static/list/hard_rewards = list( - /obj/item/gun/energy/laser, - /obj/item/gun/energy/laser/carbine, - /obj/item/gun/ballistic/shotgun/riot, - /obj/item/gun/ballistic/automatic/wt550, - ) +/datum/mission/survey/Destroy() + scan = null + return ..() + +/datum/mission/survey/generate_details() + // Types match the keys from survey_research.survey_objects_by_type var/list/ask = pick(survey_targets) target_type = ask["type"] @@ -59,13 +47,26 @@ value_max = ask["value_max"] difficulty = ask["difficulty"] - // Assign random item reward based on difficulty - switch(difficulty) - if(MISSION_DIFFICULTY_MEDIUM) - if(prob(50)) // 50% chance for item reward - mission_reward = pick(medium_rewards) - if(MISSION_DIFFICULTY_HARD) - mission_reward = pick(hard_rewards) // Always get a reward for hard +/// Utility is rolled once, after the posting zone and ask difficulty are fixed. +/datum/mission/survey/roll_posted_rewards() + ..() + if(difficulty == MISSION_DIFFICULTY_EASY || (difficulty == MISSION_DIFFICULTY_MEDIUM && !prob(50))) + return + mission_reward = pick(get_utility_pool()) + +/datum/mission/survey/proc/get_utility_pool() + var/static/list/medium = list( + list(/obj/item/gps, /obj/item/extraction_pack), + list(/obj/item/t_scanner/adv_mining_scanner, /obj/item/analyzer/ranged), + list(/obj/item/clothing/glasses/meson/night, /obj/item/inducer/orderable), + ) + var/static/list/hard = list( + list(/obj/item/t_scanner/adv_mining_scanner, /obj/item/survivalcapsule), + list(/obj/item/healthanalyzer/advanced, /obj/item/tank/jetpack/oxygen), + list(/obj/item/construction/rcd, /obj/item/survivalcapsule), + ) + var/zone = quote_zone || ZONE_GREEN + return difficulty == MISSION_DIFFICULTY_HARD ? hard[zone] : medium[zone] /datum/mission/survey/build_objectives() scan = new @@ -78,8 +79,7 @@ /datum/mission/survey/update_text() var/display_name = required_amount == 1 ? target_name_singular : target_name name = "Survey Contract: [display_name]" - desc = "Use your ship's orbital survey console to scan [required_amount] [display_name] after accepting this contract. \ - Nothing to bring back - payment is settled at the mission board once the scans are logged." + desc = "Survey requested: [required_amount] [display_name]." /datum/mission/survey/get_ui_data() var/list/data = ..() diff --git a/voidcrew/modules/missions/objectives/combat.dm b/voidcrew/modules/missions/objectives/combat.dm index d1eb3da108a..a9f08365fff 100644 --- a/voidcrew/modules/missions/objectives/combat.dm +++ b/voidcrew/modules/missions/objectives/combat.dm @@ -275,7 +275,7 @@ return kill_count++ if(kill_count >= required_kills) - notify_crew("Suppression quota met ([kill_count]/[required_kills]). Return to the mission board to collect payment.") + notify_crew("Suppression sweep complete.") complete() return notify_crew("Kill confirmed: [kill_count]/[required_kills].", sound = 'voidcrew/sound/notify2.ogg') diff --git a/voidcrew/modules/missions/objectives/deliver.dm b/voidcrew/modules/missions/objectives/deliver.dm index d5cffbdc03f..06576ec849e 100644 --- a/voidcrew/modules/missions/objectives/deliver.dm +++ b/voidcrew/modules/missions/objectives/deliver.dm @@ -26,15 +26,9 @@ /datum/mission_objective/deliver/proc/describe_ask() return required_amount > 1 ? "[required_amount] [required_name]" : required_name -/// Shared contract text for the item forms and stack sizes accepted at turn-in. +/// Kept for callers that used to append delivery instructions. /datum/mission_objective/deliver/proc/get_delivery_instructions() - . = "" - if(ispath(required_type, /obj/item/stack) && required_amount > 1) - . += " Bring the full quantity in one stack; only the requested amount will be taken." - if(ispath(required_type, /obj/item/stack/ore/bluespace_crystal)) - . += " Natural, refined, or artificial individual bluespace crystals are accepted. Split bluespace polycrystals into individual crystals before delivery." - else if(ispath(required_type, /obj/item/stack/ore)) - . += " Keep the material unrefined; smelted sheets do not count." + return "" /datum/mission_objective/deliver/get_progress_string() if(required_amount > 1 && delivered_count > 0) @@ -65,6 +59,8 @@ return ..() /datum/mission_objective/deliver/accept_item(obj/item/item, atom/reward_anchor) + if(completed || QDELETED(item) || !can_turn_in(item)) + return MISSION_ITEM_REFUSED // The delivered item is often the mission's tracked quest atom; stop the // destruction watch before consuming it, or qdel fires it synchronously and // handle_quest_loss() voids the contract mid-turn-in (outpost_quests.dm @@ -83,6 +79,13 @@ notify_crew("[mission.name]: [delivered_count]/[required_amount] [required_name] received.") return MISSION_ITEM_PROGRESS +/// The console's salvage rows use the exact listed goods, never manufactured descendants. +/datum/mission_objective/deliver/console/matches_ask(obj/item/item) + return !QDELETED(item) && item.type == required_type + +/datum/mission_objective/deliver/console/can_turn_in(obj/item/item) + return !completed && matches_ask(item) && ..() + // ========================================================================= // BOUND ITEM: a specific quest item this mission spawned // ========================================================================= diff --git a/voidcrew/modules/missions/objectives/site_ops.dm b/voidcrew/modules/missions/objectives/site_ops.dm index c8d8e4e7b2e..0689c21430e 100644 --- a/voidcrew/modules/missions/objectives/site_ops.dm +++ b/voidcrew/modules/missions/objectives/site_ops.dm @@ -178,7 +178,7 @@ // Survey complete: the last pylon prints the core var/obj/item/mission_recovery/core = new(pylon.drop_location()) core.name = "[mission.objective_name] core" - core.desc = "A completed survey core, warm from compiling. The mission pad will accept it." + core.desc = "A completed survey core, warm from compiling." mission.bind_item(core) mission.register_quest_atom(core) notify_crew("Survey complete. Recover the [mission.objective_name] core and return it to the mission pad.") @@ -253,7 +253,7 @@ anomaly.stabilize(anchor = TRUE) anomaly.countdown?.stop() RegisterSignal(anomaly, COMSIG_QDELETING, PROC_REF(on_anomaly_gone)) - notify_crew("Containment target is live and holding at the site. Read its field with an analyzer, then match that frequency and code on a signaler to neutralize it.") + notify_crew("Containment target confirmed at the site.") /** * The anomaly is gone. A proper neutralization has already dropped its core on @@ -391,7 +391,7 @@ if(grace_timer) // already counting down; a re-death mid-revival doesn't restart it return grace_timer = addtimer(CALLBACK(src, PROC_REF(on_grace_expired)), revival_grace, TIMER_STOPPABLE) - notify_crew("Survivor's vitals flatlined - the beacon is still holding their tag. Get them breathing again within [DisplayTimeText(revival_grace)] and the contract stands.", type = SHIP_NOTIFY_WARNING) + notify_crew("Survivor's vitals flatlined.", type = SHIP_NOTIFY_WARNING) /// Somebody got them back up inside the window /datum/mission_objective/field/escort/proc/on_survivor_revived(mob/living/source, full_heal_flags) @@ -402,7 +402,7 @@ return clear_grace() was_revived = TRUE - notify_crew("Survivor is breathing again. Bring them to the pad - the fee holds, the unharmed bonus does not.") + notify_crew("Survivor is breathing again.") /// Nobody brought them back in time /datum/mission_objective/field/escort/proc/on_grace_expired() @@ -517,7 +517,7 @@ return FALSE kit = new(kit_turf) kit.objective_ref = WEAKREF(src) - notify_crew("Claim beacon kit delivered to your mission pad. Deploy it while holding at the marked coordinates.") + notify_crew("Claim beacon kit delivered.") return TRUE /// Whether the ship is close enough to the stake coordinates to count @@ -539,7 +539,7 @@ QDEL_NULL(kit) var/datum/mission_target/target = mission.target beacon.file_claim("Prospect filing: mineral-rights claim staked at grid [target.target_x], [target.target_y]. Claim matures in [round(defend_duration / (1 MINUTES))] minutes. All counterclaims settled on-site.") - notify_crew("Claim filed on Wideband. The whole sector heard it - hold the site for [round(defend_duration / (1 MINUTES))] minutes.", type = SHIP_NOTIFY_WARNING) + notify_crew("Claim filed on Wideband.", type = SHIP_NOTIFY_WARNING) /// One second of defending, ticked by the beacon's process /datum/mission_objective/claim_defense/proc/tick_defense(seconds) @@ -565,7 +565,7 @@ deed_printed = TRUE var/obj/item/mission_recovery/deed = new(beacon.drop_location()) deed.name = "notarized claim deed" - deed.desc = "A matured mineral-rights filing, printed and bonded. The mission pad will accept it." + deed.desc = "A matured mineral-rights filing, printed and bonded." mission.bind_item(deed) mission.register_quest_atom(deed) beacon.retire() diff --git a/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm b/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm index e7e407f76d4..be02669d918 100644 --- a/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm +++ b/voidcrew/modules/npc_ships/code/faction_pirates/faction_pirate_mobs.dm @@ -540,7 +540,7 @@ r_hand = /obj/item/fireaxe/boardingaxe loot_pool = list(/obj/item/fireaxe/boardingaxe) random_loot = null - plunder_credits = 300 + plunder_credits = 1000 /mob/living/basic/trooper/pirate/faction/medieval/captain/Initialize(mapload) . = ..() diff --git a/voidcrew/modules/overmap/code/modules/overmap/ship.dm b/voidcrew/modules/overmap/code/modules/overmap/ship.dm index d15ad4ed61c..a3ee2aa906b 100644 --- a/voidcrew/modules/overmap/code/modules/overmap/ship.dm +++ b/voidcrew/modules/overmap/code/modules/overmap/ship.dm @@ -209,9 +209,14 @@ var/list/datum/mission/active_missions = list() /// Maximum number of active missions (captain can adjust) var/max_missions = DEFAULT_MAX_ACTIVE_MISSIONS - /// World time of the last manual mission refresh (rate-limited). Starts a whole cooldown back, so a - /// ship that never refreshed can, rather than waiting out the first minutes after the server boots. + /// Last scheduled refresh, retained for callers of the original board API. var/last_mission_refresh = -MISSION_REFRESH_COOLDOWN + /// Fixed offer-set schedule, shared by every console on this hull. + var/next_mission_refresh = 0 + /// Guarded prizes are round-local entitlements of the hull, including after transfer. + var/mission_suit_paid = FALSE + var/mission_gadget_paid = FALSE + var/mission_first_suit_seconds var/pending_dock = FALSE var/pending_dock_timer @@ -4646,6 +4651,69 @@ // ===== MISSION PROCS ===== +/// Disjoint ranges on a single roll, in tenths of a percent. +/proc/mission_prize_outcome(zone, roll) + var/suit_chance = zone == ZONE_RED ? 200 : (zone == ZONE_YELLOW ? 40 : 30) + var/gadget_chance = zone == ZONE_RED ? 100 : (zone == ZONE_YELLOW ? 20 : 15) + if(roll <= suit_chance) + return "suit" + if(roll <= suit_chance + gadget_chance) + return "gadget" + return null + +/// Every eligible family uses the same caps, regardless of its completion surface. +/proc/mission_prize_pool(family, category) + var/static/list/suits = list( + "kill" = list(/obj/item/mod/control/pre_equipped/traitor_elite), + "hunt" = list(/obj/item/mod/control/pre_equipped/safeguard), + "poacher" = list(/obj/item/mod/control/pre_equipped/empty/ninja), + "capture" = list(/obj/item/mod/control/pre_equipped/empty/ninja), + "waves" = list(/obj/item/mod/control/pre_equipped/magnate, /obj/item/mod/control/pre_equipped/safeguard), + "stake" = list(/obj/item/mod/control/pre_equipped/safeguard), + "lair" = list(/obj/item/mod/control/pre_equipped/traitor_elite, /obj/item/mod/control/pre_equipped/safeguard), + ) + var/static/list/gadgets = list( + "kill" = list(/obj/item/gun/energy/laser/captain), + "hunt" = list(/obj/item/organ/cyberimp/cyberware/piledriver), + "poacher" = list(/obj/item/circuitboard/machine/ship_combat/cloak_device), + "capture" = list(/obj/item/gun/energy/laser/captain), + "waves" = list(/obj/item/gun/energy/laser/captain, /obj/item/organ/cyberimp/cyberware/piledriver, /obj/item/circuitboard/machine/ship_combat/cloak_device), + "stake" = list(/obj/item/gun/energy/laser/captain, /obj/item/organ/cyberimp/cyberware/piledriver, /obj/item/circuitboard/machine/ship_combat/cloak_device), + "lair" = list(/obj/item/gun/energy/laser/captain, /obj/item/organ/cyberimp/cyberware/piledriver, /obj/item/circuitboard/machine/ship_combat/cloak_device), + ) + return category == "suit" ? suits[family] : (category == "gadget" ? gadgets[family] : null) + +/obj/structure/overmap/ship/proc/roll_mission_prize(zone) + return mission_prize_outcome(zone, rand(1, 1000)) + +/// A capped result is spent without rerolling; claim before the constructor can yield. +/obj/structure/overmap/ship/proc/award_guarded_prize(family, zone, atom/reward_anchor, source_type) + if(QDELETED(src) || !(zone in list(ZONE_GREEN, ZONE_YELLOW, ZONE_RED))) + return null + if(zone == ZONE_GREEN && (family == "stake" || family == "lair")) + return null + var/turf/spot = get_turf(reward_anchor) + if(!spot || !length(mission_prize_pool(family, "suit"))) + return null + var/category = roll_mission_prize(zone) + var/list/pool = mission_prize_pool(family, category) + if(!length(pool)) + return null + if(category == "suit") + if(mission_suit_paid) + return null + mission_suit_paid = TRUE + mission_first_suit_seconds = metric_round_seconds() + else + if(mission_gadget_paid) + return null + mission_gadget_paid = TRUE + var/prize_type = pick(pool) + new prize_type(spot) + record_guarded_prize(src, family, category, zone, prize_type, source_type) + ship_notify("Requisition cleared.", "MISSION CONTROL", SHIP_NOTIFY_NOTICE, 'voidcrew/sound/notify.ogg', 50) + return prize_type + /** * Accepts a mission, moving it from available to active. * * mission - The mission to accept diff --git a/voidcrew/modules/unit_tests/_unit_tests.dm b/voidcrew/modules/unit_tests/_unit_tests.dm index ccc8ca6872f..a7a4ac49c35 100644 --- a/voidcrew/modules/unit_tests/_unit_tests.dm +++ b/voidcrew/modules/unit_tests/_unit_tests.dm @@ -99,6 +99,7 @@ #include "voidcrew_mining_input.dm" #include "voidcrew_mining_qol.dm" #include "voidcrew_mission_board_rewards.dm" +#include "voidcrew_mission_console_rewards.dm" #include "voidcrew_mission_gps.dm" #include "voidcrew_mission_metrics.dm" #include "voidcrew_missions.dm" diff --git a/voidcrew/modules/unit_tests/voidcrew_launch_access.dm b/voidcrew/modules/unit_tests/voidcrew_launch_access.dm index 549eeef43a1..7cef64f822b 100644 --- a/voidcrew/modules/unit_tests/voidcrew_launch_access.dm +++ b/voidcrew/modules/unit_tests/voidcrew_launch_access.dm @@ -61,11 +61,14 @@ var/datum/mission/exploration/safe_offer = locate() in ship.available_missions TEST_ASSERT_NOTNULL(safe_offer, "Full unsafe board did not reserve an exploration slot") TEST_ASSERT_EQUAL(safe_offer.target.get_zone_type(), 1, "Reserved job is outside green space") - TEST_ASSERT(safe_offer.value >= 400 && safe_offer.value <= 700, "Reserved job changed the existing green payout") + TEST_ASSERT(safe_offer.value >= 150 && safe_offer.value <= 250, "Reserved job left the green payout band") SSmissions.refresh_ship_missions(ship) TEST_ASSERT(safe_offer in ship.available_missions, "Refresh replaced an existing valid safe offer") + TEST_ASSERT(!SSmissions.force_refresh_ship_missions(ship), "Manual refresh bypassed the fixed offer timer") + TEST_ASSERT(safe_offer in ship.available_missions, "Early refresh replaced the green offer") + ship.next_mission_refresh = world.time SSmissions.force_refresh_ship_missions(ship) - TEST_ASSERT(QDELETED(safe_offer), "Reroll retained the old offer") + TEST_ASSERT(QDELETED(safe_offer), "Scheduled refresh retained the old offer") safe_offer = locate() in ship.available_missions TEST_ASSERT_NOTNULL(safe_offer, "Reroll omitted the reserved exploration offer") TEST_ASSERT_EQUAL(safe_offer.target.get_zone_type(), 1, "Reroll's first exploration job is not green") diff --git a/voidcrew/modules/unit_tests/voidcrew_mission_console_rewards.dm b/voidcrew/modules/unit_tests/voidcrew_mission_console_rewards.dm new file mode 100644 index 00000000000..570d49c3db5 --- /dev/null +++ b/voidcrew/modules/unit_tests/voidcrew_mission_console_rewards.dm @@ -0,0 +1,458 @@ +#ifndef VOIDCREW_MISSION_CONSOLE_REWARDS_TESTS +#define VOIDCREW_MISSION_CONSOLE_REWARDS_TESTS + +// Included before and after the fork defines; literals below name their corresponding constants. +/datum/mission/m2_rewards_test/generate_mission_details() + +/datum/mission/recovery/kill/m2_rewards_test + weight = 0 + +/datum/mission/recovery/kill/m2_rewards_test/generate_mission_details() + +/datum/mission/recovery/kill/outpost/m2_rewards_test/generate_mission_details() + +/obj/structure/overmap/ship/m2_rewards_test + var/prize_rolls = 0 + var/prize_category = "suit" + +/obj/structure/overmap/ship/m2_rewards_test/roll_mission_prize(zone) + prize_rolls++ + return prize_category + +/datum/mission_target/m2_rewards_test + var/resolved_zone = 1 // ZONE_GREEN + +/datum/mission_target/m2_rewards_test/resolve() + return TRUE + +/datum/mission_target/m2_rewards_test/get_zone_type() + return resolved_zone + +/obj/item/stack/spice_pods/m2_rewards_test + +/datum/unit_test/voidcrew_m2_rewards + abstract_type = /datum/unit_test/voidcrew_m2_rewards + var/old_accepting + var/list/old_pending + var/list/old_tallies + var/list/old_types + +/datum/unit_test/voidcrew_m2_rewards/New() + . = ..() + old_accepting = SSmetrics.accepting + old_pending = SSmetrics.pending + old_tallies = SSmetrics.tallies + old_types = SSmissions.mission_types + SSmetrics.accepting = FALSE + SSmetrics.pending = list() + SSmetrics.tallies = list() + +/datum/unit_test/voidcrew_m2_rewards/Destroy() + SSmetrics.accepting = old_accepting + SSmetrics.pending = old_pending + SSmetrics.tallies = old_tallies + SSmissions.mission_types = old_types + return ..() + +/datum/unit_test/voidcrew_m2_rewards/proc/test_ship() + var/obj/structure/overmap/ship/m2_rewards_test/ship = allocate(/obj/structure/overmap/ship/m2_rewards_test) + ship.ship_account = allocate(/datum/bank_account) + return ship + +/// All targeted base bands, one scaling pass, and the independent research factors. +/datum/unit_test/voidcrew_m2_rewards/bands/Run() + var/list/bands = list( + /datum/mission/exploration = list(150, 250), + /datum/mission/recovery = list(450, 650), + /datum/mission/recovery/kill = list(500, 700), + /datum/mission/recovery/survey = list(550, 750), + /datum/mission/recovery/extraction = list(500, 700), + /datum/mission/field_expedition = list(500, 700), + /datum/mission/rescue = list(650, 850), + /datum/mission/prospect_stake = list(1400, 1800), + /datum/mission/research/containment = list(350, 550), + /datum/mission/research/core_sample = list(300, 450), + /datum/mission/big_game_hunt = list(650, 850), + /datum/mission/live_capture = list(600, 800), + /datum/mission/poacher_bust = list(600, 800), + ) + var/list/multipliers = list(1, 1.5, 2.2) + var/list/research_multipliers = list(1, 1.4, 1.8) + for(var/datum/mission/mission_type as anything in bands) + var/list/band = bands[mission_type] + TEST_ASSERT_EQUAL(initial(mission_type.value_min), band[1], "[mission_type] has the wrong base minimum") + TEST_ASSERT_EQUAL(initial(mission_type.value_max), band[2], "[mission_type] has the wrong base maximum") + for(var/zone in 1 to 3) // ZONE_GREEN/YELLOW/RED + var/datum/mission/mission = allocate(/datum/mission/m2_rewards_test) + mission.target = allocate(/datum/mission_target/m2_rewards_test, mission) + mission.value_min = band[1] + mission.value_max = band[2] + mission.research_reward = 500 + mission.apply_zone_scaling(zone) + TEST_ASSERT_EQUAL(mission.value_min, round(band[1] * multipliers[zone], 10), "Wrong scaled minimum") + TEST_ASSERT_EQUAL(mission.value_max, round(band[2] * multipliers[zone], 10), "Wrong scaled maximum") + TEST_ASSERT_EQUAL(mission.research_reward, round(500 * research_multipliers[zone], 10), "Research used the credit factor") + var/quoted = mission.value_max + mission.apply_zone_scaling(zone) + TEST_ASSERT_EQUAL(mission.value_max, quoted, "Scaling applied twice") + TEST_ASSERT_EQUAL(mission.voucher_count, 0, "Scaling invented a red voucher") + var/datum/mission/suppression/sweep = allocate(/datum/mission/suppression) + var/lo = sweep.quote_zone == 3 ? 1100 : 700 + var/hi = sweep.quote_zone == 3 ? 1500 : 1000 + TEST_ASSERT(sweep.value >= lo && sweep.value <= hi, "Suppression must remain flat in its quoted band") + TEST_ASSERT(sweep.voucher_count in list(0, 1), "Suppression pays at most one ordinary voucher") + var/datum/mission/rescue/rescue_type = /datum/mission/rescue + TEST_ASSERT_EQUAL(initial(rescue_type.voucher_count), 0, "Rescue still guarantees vouchers") + +/// Verify every delivery row and accept stored goods, including account loss before partial delivery. +/datum/unit_test/voidcrew_m2_rewards/deliveries/Run() + var/datum/mission/delivery/catalog = allocate(/datum/mission/delivery) + var/list/expected = list( + /obj/item/stack/spice_pods = list(3, 1, 320, 400), + /obj/item/stack/sheet/sinew = list(2, 1, 260, 340), + /obj/item/stack/sheet/animalhide/goliath_hide = list(2, 2, 400, 550), + /obj/item/stack/glacial_core = list(3, 2, 550, 700), + /obj/item/stack/telecrystal_raw = list(5, 3, 1500, 1700), + /obj/item/sea_crystal = list(1, 3, 1000, 1200), + /obj/item/documents/syndicate = list(1, 3, 3000, 3300), + ) + TEST_ASSERT_EQUAL(catalog.weight, 10, "Delivery suspension was not lifted") + TEST_ASSERT_EQUAL(length(catalog.delivery_asks), length(expected), "Delivery catalog has extra or missing rows") + var/obj/structure/overmap/ship/ship = test_ship() + for(var/list/row as anything in catalog.delivery_asks) + var/list/wanted = expected[row["type"]] + TEST_ASSERT_NOTNULL(wanted, "Delivery asks for an unapproved item") + TEST_ASSERT_EQUAL(row["amount"], wanted[1], "Delivery quantity changed") + TEST_ASSERT_EQUAL(row["difficulty"], wanted[2], "Delivery difficulty changed") + TEST_ASSERT_EQUAL(row["value_min"], wanted[3], "Wrong delivery minimum") + TEST_ASSERT_EQUAL(row["value_max"], wanted[4], "Wrong delivery maximum") + var/datum/mission/mission = allocate(/datum/mission/m2_rewards_test) + mission.value_min = row["value_min"] + mission.value_max = row["value_max"] + var/datum/mission_objective/deliver/console/ask = new + ask.required_type = row["type"] + ask.required_amount = row["amount"] + mission.add_objective(ask) + mission.requires_item = TRUE + TEST_ASSERT(mission.start_mission(ship), "Stored-goods delivery did not start") + var/obj/item/item + if(ispath(ask.required_type, /obj/item/stack)) + item = allocate(ask.required_type, run_loc_floor_bottom_left, ask.required_amount + 2, FALSE) + else + item = allocate(ask.required_type) + TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left, item), "Stored qualifying goods were refused") + if(isstack(item)) + var/obj/item/stack/left = item + TEST_ASSERT_EQUAL(left.amount, 2, "Delivery consumed excess goods") + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left, item), "Stale hand-in paid twice") + var/datum/mission/delivery/flat = allocate(/datum/mission/delivery, null, null, 3) + var/list/flat_row + for(var/list/row as anything in flat.delivery_asks) + if(row["type"] == flat.required_type) + flat_row = row + TEST_ASSERT_EQUAL(flat.value_min, flat_row["value_min"], "Red scaled a flat delivery") + TEST_ASSERT_EQUAL(flat.difficulty, flat_row["difficulty"], "Red replaced ask difficulty") + TEST_ASSERT_EQUAL(flat.voucher_count, 0, "Delivery gained a voucher") + var/datum/mission/partial = allocate(/datum/mission/m2_rewards_test) + var/datum/mission_objective/deliver/ask = new + ask.required_type = /obj/item/sea_crystal + ask.required_amount = 2 + partial.add_objective(ask) + partial.requires_item = TRUE + partial.start_mission(ship) + var/obj/item/first = allocate(/obj/item/sea_crystal) + var/obj/item/second = allocate(/obj/item/sea_crystal) + var/datum/bank_account/account = ship.ship_account + ship.ship_account = null + TEST_ASSERT(!partial.turn_in(run_loc_floor_bottom_left, first), "Accountless partial delivery succeeded") + TEST_ASSERT(!QDELETED(first) && !ask.delivered_count, "Rejected delivery consumed goods") + ship.ship_account = account + TEST_ASSERT(partial.turn_in(run_loc_floor_bottom_left, first), "Valid partial delivery failed") + TEST_ASSERT(!partial.turn_in(run_loc_floor_bottom_left, first), "Consumed partial item counted twice") + ship.ship_account = null + TEST_ASSERT(!partial.turn_in(run_loc_floor_bottom_left, second), "Accountless final delivery succeeded") + TEST_ASSERT(!QDELETED(second), "Rejected final delivery consumed goods") + ship.ship_account = account + TEST_ASSERT(partial.turn_in(run_loc_floor_bottom_left, second), "Final delivery failed after account recovery") + var/datum/mission_objective/deliver/console/exact = allocate(/datum/mission_objective/deliver/console) + exact.required_type = /obj/item/stack/spice_pods + var/obj/item/descendant = allocate(/obj/item/stack/spice_pods/m2_rewards_test) + TEST_ASSERT(!exact.can_turn_in(descendant), "A descendant bypassed the exact goods path") + +/// Fixed sets survive acceptance, failure, deletion and rebuilding until the scheduled refresh. +/datum/unit_test/voidcrew_m2_rewards/offers/Run() + SSmissions.mission_types = list(/datum/mission/delivery) + var/obj/structure/overmap/ship/ship = test_ship() + TEST_ASSERT(SSmissions.refresh_ship_missions(ship), "Initial offer set was not posted") + TEST_ASSERT_EQUAL(length(ship.available_missions), 5, "Initial board does not contain five offers") + TEST_ASSERT_EQUAL(ship.next_mission_refresh, world.time + 20 MINUTES, "Offer timer is not twenty minutes") + var/datum/mission/taken = ship.available_missions[1] + TEST_ASSERT(taken.start_mission(ship), "Offer could not be accepted") + taken.fail("Abandoned.") + var/datum/mission/destroyed = ship.available_missions[1] + ship.available_missions -= destroyed + qdel(destroyed) + var/datum/mission/retained = ship.available_missions[1] + var/refresh_at = ship.next_mission_refresh + var/obj/machinery/computer/mission_board/console = allocate(/obj/machinery/computer/mission_board) + qdel(console) + console = allocate(/obj/machinery/computer/mission_board) + TEST_ASSERT(!SSmissions.force_refresh_ship_missions(ship), "Manual refresh bypassed the schedule") + TEST_ASSERT_EQUAL(length(ship.available_missions), 3, "Vacancies refilled before the timer") + TEST_ASSERT(retained in ship.available_missions, "Rebuilding or failing an offer rerolled the set") + TEST_ASSERT_EQUAL(ship.next_mission_refresh, refresh_at, "A console reset the ship timer") + ship.next_mission_refresh = world.time + TEST_ASSERT(SSmissions.refresh_ship_missions(ship), "Scheduled refresh did not run") + TEST_ASSERT(QDELETED(retained), "Scheduled refresh retained an old offer") + TEST_ASSERT_EQUAL(length(ship.available_missions), 5, "Scheduled refresh failed to replace the full set") + var/datum/mission/quoted = allocate(/datum/mission/m2_rewards_test) + var/datum/mission_target/m2_rewards_test/target = allocate(/datum/mission_target/m2_rewards_test, quoted) + quoted.target = target + quoted.quote_zone = 1 + target.resolved_zone = 2 + TEST_ASSERT(!quoted.resolve_quoted_target(), "Retarget escaped the quoted band") + target.resolved_zone = 1 + TEST_ASSERT(quoted.resolve_quoted_target(), "Same-band retarget failed") + +/// Every scan/gas row and all six utility cells retain ask difficulty independently of zone. +/datum/unit_test/voidcrew_m2_rewards/asks/Run() + var/datum/mission/survey/survey = allocate(/datum/mission/survey) + var/list/survey_rows = list( + list("any", 3, 100, 160, 1), list("nebulas", 2, 80, 120, 1), list("asteroids", 2, 100, 160, 1), + list("planets", 2, 180, 260, 2), list("electric_storms", 2, 160, 240, 2), list("space_ruins", 2, 180, 260, 2), + list("stars", 1, 160, 240, 3), list("emp_storms", 2, 240, 360, 3), list("planets", 4, 320, 440, 3), + ) + var/datum/mission/research/telemetry/telemetry = allocate(/datum/mission/research/telemetry) + TEST_ASSERT(!telemetry.generation_failed, "Telemetry generation failed") + var/list/telemetry_rows = list( + list("nebulas", 2, 60, 100, 1), list("asteroids", 2, 60, 100, 1), list("any", 3, 80, 120, 1), + list("planets", 2, 100, 160, 2), list("space_ruins", 2, 100, 160, 2), list("electric_storms", 2, 100, 160, 2), + list("emp_storms", 2, 160, 240, 3), list("stars", 1, 100, 160, 3), + ) + check_asks(survey.survey_targets, survey_rows) + check_asks(telemetry.telemetry_asks, telemetry_rows) + var/list/medium = list( + list(/obj/item/gps, /obj/item/extraction_pack), + list(/obj/item/t_scanner/adv_mining_scanner, /obj/item/analyzer/ranged), + list(/obj/item/clothing/glasses/meson/night, /obj/item/inducer/orderable), + ) + var/list/hard = list( + list(/obj/item/t_scanner/adv_mining_scanner, /obj/item/survivalcapsule), + list(/obj/item/healthanalyzer/advanced, /obj/item/tank/jetpack/oxygen), + list(/obj/item/construction/rcd, /obj/item/survivalcapsule), + ) + var/list/multipliers = list(1, 1.5, 2.2) + for(var/zone in 1 to 3) + for(var/ask_difficulty in 2 to 3) + survey.quote_zone = zone + survey.difficulty = ask_difficulty + var/list/pool = survey.get_utility_pool() + var/list/wanted = ask_difficulty == 3 ? hard[zone] : medium[zone] + TEST_ASSERT_EQUAL(length(pool), 2, "Utility cell must have exactly two equal choices") + TEST_ASSERT_EQUAL(length(pool & wanted), 2, "Wrong utility pool for zone and difficulty") + var/datum/mission/survey/posted = allocate(/datum/mission/survey, null, null, zone) + var/list/ask = matching_ask(posted.survey_targets, posted.target_type, posted.required_amount) + TEST_ASSERT_EQUAL(posted.value_min, round(ask["value_min"] * multipliers[zone], 10), "Survey scaling preceded the ask roll") + TEST_ASSERT_EQUAL(posted.difficulty, ask["difficulty"], "Survey lost its ask difficulty") + var/prize = posted.mission_reward + var/fee = posted.value + posted.update_text() + posted.apply_zone_scaling(1) + TEST_ASSERT_EQUAL(posted.mission_reward, prize, "Reopening changed utility") + TEST_ASSERT_EQUAL(posted.value, fee, "Moving changed the posted quote") + var/datum/mission/research/telemetry/science = allocate(/datum/mission/research/telemetry, null, null, zone) + ask = matching_ask(science.telemetry_asks, science.target_type, science.required_amount) + TEST_ASSERT_EQUAL(science.value_max, round(ask["value_max"] * multipliers[zone], 10), "Telemetry credits did not scale after details") + var/list/research_mult = list(1, 1.4, 1.8) + TEST_ASSERT_EQUAL(science.research_reward, round(ask["research"] * research_mult[zone], 10), "Telemetry research lost its separate factor") + var/datum/mission/gas_harvest/gas = allocate(/datum/mission/gas_harvest) + TEST_ASSERT(!gas.generation_failed, "Gas fallback generation failed") + var/list/gas_rows = list( + /datum/gas/plasma = list(600, 900, 250, 350, 1, 0), + /datum/gas/nitrogen = list(600, 900, 220, 320, 1, 0), + /datum/gas/water_vapor = list(600, 900, 220, 320, 1, 0), + /datum/gas/miasma = list(400, 700, 300, 450, 2, 0), + /datum/gas/tritium = list(250, 450, 450, 650, 2, 1), + /datum/gas/pluoxium = list(200, 350, 650, 850, 3, 1), + /datum/gas/nitrium = list(200, 350, 650, 850, 3, 1), + /datum/gas/hypernoblium = list(150, 300, 750, 950, 3, 1), + ) + TEST_ASSERT_EQUAL(length(gas.gas_asks), 8, "Gas catalog changed size") + for(var/gas_type in gas.gas_asks) + var/list/ask = gas.gas_asks[gas_type] + var/list/wanted = gas_rows[gas_type] + TEST_ASSERT_NOTNULL(wanted, "Unapproved gas row") + TEST_ASSERT_EQUAL(ask["moles"][1], wanted[1], "Gas minimum quantity changed") + TEST_ASSERT_EQUAL(ask["moles"][2], wanted[2], "Gas maximum quantity changed") + TEST_ASSERT_EQUAL(ask["value"][1], wanted[3], "Wrong gas minimum") + TEST_ASSERT_EQUAL(ask["value"][2], wanted[4], "Wrong gas maximum") + TEST_ASSERT_EQUAL(ask["difficulty"], wanted[5], "Gas ask difficulty changed") + TEST_ASSERT_EQUAL(ask["vouchers"], wanted[6], "Gas voucher count changed") + for(var/zone in 1 to 3) + var/datum/mission/gas_harvest/posted = allocate(/datum/mission/gas_harvest, null, null, zone) + var/list/ask = posted.gas_asks[posted.gas_type] + TEST_ASSERT_EQUAL(posted.value_max, round(ask["value"][2] * multipliers[zone], 10), "Gas quote did not use the posting zone") + TEST_ASSERT_EQUAL(posted.voucher_count, ask["vouchers"], "Gas gained an extra zone voucher") + +/datum/unit_test/voidcrew_m2_rewards/asks/proc/matching_ask(list/rows, object_type, amount) + for(var/list/row as anything in rows) + if(row["type"] == object_type && row["amount"] == amount) + return row + +/datum/unit_test/voidcrew_m2_rewards/asks/proc/check_asks(list/rows, list/expected) + TEST_ASSERT_EQUAL(length(rows), length(expected), "Scan ask catalog changed size") + for(var/index in 1 to length(expected)) + var/list/row = rows[index] + var/list/wanted = expected[index] + TEST_ASSERT_EQUAL(row["type"], wanted[1], "Wrong scan object") + TEST_ASSERT_EQUAL(row["amount"], wanted[2], "Scan quota changed") + TEST_ASSERT_EQUAL(row["value_min"], wanted[3], "Wrong scan minimum") + TEST_ASSERT_EQUAL(row["value_max"], wanted[4], "Wrong scan maximum") + TEST_ASSERT_EQUAL(row["difficulty"], wanted[5], "Scan difficulty changed") + +/// Exact disjoint odds, all seven green prizes, shared caps, and one completion roll. +/datum/unit_test/voidcrew_m2_rewards/prizes/Run() + var/list/suits = list(30, 40, 200) + var/list/gadgets = list(15, 20, 100) + for(var/zone in 1 to 3) + var/suit_count = 0 + var/gadget_count = 0 + for(var/roll in 1 to 1000) + var/outcome = mission_prize_outcome(zone, roll) + suit_count += outcome == "suit" + gadget_count += outcome == "gadget" + TEST_ASSERT_EQUAL(suit_count, suits[zone], "Wrong suit chance") + TEST_ASSERT_EQUAL(gadget_count, gadgets[zone], "Wrong gadget chance") + var/list/green_prizes = list() + for(var/family in list("kill", "hunt", "poacher", "capture", "waves")) + green_prizes |= mission_prize_pool(family, "suit") + green_prizes |= mission_prize_pool(family, "gadget") + TEST_ASSERT_EQUAL(length(green_prizes), 7, "Green work cannot reach all seven named prizes") + var/obj/structure/overmap/ship/m2_rewards_test/ship = test_ship() + for(var/mission_type in list(/datum/mission/recovery/kill/m2_rewards_test, /datum/mission/recovery/kill/outpost/m2_rewards_test)) + var/datum/mission/mission = allocate(mission_type) + mission.quote_zone = 1 + mission.value = 600 + mission.voucher_count = 1 + mission.start_mission(ship) + var/before = ship.ship_account.account_balance + TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left), "Completed guarded work failed") + TEST_ASSERT_EQUAL(ship.ship_account.account_balance - before, 600, "Prize replaced ordinary credits") + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left), "A stale completion succeeded") + mission.finish_mission(run_loc_floor_bottom_left) + TEST_ASSERT_EQUAL(ship.prize_rolls, 2, "Each completion must roll once, including outpost kills") + TEST_ASSERT(ship.mission_suit_paid && !ship.mission_gadget_paid, "Capped suit rerolled into a gadget") + TEST_ASSERT_EQUAL(length(run_loc_floor_bottom_left.get_all_contents_type(/obj/item/mod/control/pre_equipped/traitor_elite)), 1, "Suit cap allowed a duplicate") + ship.prize_category = "gadget" + TEST_ASSERT_EQUAL(ship.award_guarded_prize("kill", 1, run_loc_floor_bottom_left), /obj/item/gun/energy/laser/captain, "Suit cap blocked the separate gadget") + TEST_ASSERT_NULL(ship.award_guarded_prize("hunt", 3, run_loc_floor_bottom_left), "A different family bypassed the gadget cap") + var/rolls_before = ship.prize_rolls + var/datum/mission/failed = allocate(/datum/mission/recovery/kill/m2_rewards_test) + failed.start_mission(ship) + failed.fail("Abandoned.") + TEST_ASSERT_EQUAL(ship.prize_rolls, rolls_before, "Failed work rolled a prize") + TEST_ASSERT_NULL(ship.award_guarded_prize("stake", 1, run_loc_floor_bottom_left), "Green stake became eligible") + TEST_ASSERT_NULL(mission_prize_pool("suppression", "suit"), "Suppression gained a prize pool") + TEST_ASSERT_NULL(mission_prize_pool("expedition", "suit"), "Expedition ambush gained a prize pool") + var/list/families = list( + /datum/mission/recovery/kill = "kill", /datum/mission/recovery/kill/outpost = "kill", + /datum/mission/big_game_hunt = "hunt", /datum/mission/live_capture = "capture", /datum/mission/poacher_bust = "poacher", + /datum/mission/recovery/survey = "waves", /datum/mission/recovery/extraction = "waves", /datum/mission/research/core_sample = "waves", + /datum/mission/prospect_stake = "stake", + ) + for(var/datum/mission/mission_type as anything in families) + TEST_ASSERT_EQUAL(initial(mission_type.guarded_prize_family), families[mission_type], "Mission has the wrong guarded prize family") + +/// Lair claims use the same flags after the existing atomic bounty completion. +/datum/unit_test/voidcrew_m2_rewards/lair/Run() + var/obj/structure/overmap/ship/m2_rewards_test/ship = test_ship() + var/obj/machinery/mission_pad/pad = allocate(/obj/machinery/mission_pad) + var/datum/criminal_bounty/kill_only/lair/posting = allocate(/datum/criminal_bounty/kill_only/lair) + posting.record = bounty_kill_record("Test Boss", "testing", MALE, 5000, "test") + posting.value = 5000 + posting.board_vouchers = 3 + posting.board_zone = 2 // ZONE_YELLOW + var/obj/item/bounty_proof/trophy/proof = allocate(/obj/item/bounty_proof/trophy) + posting.kill_bind_trophy(proof) + var/before = ship.ship_account.account_balance + TEST_ASSERT(islist(posting.board_claim(ship, pad, proof, "dead")), "Lair trophy claim failed") + TEST_ASSERT_EQUAL(ship.ship_account.account_balance - before, 5000, "Lair pay changed") + TEST_ASSERT_EQUAL(ship.prize_rolls, 1, "Successful lair must roll one prize") + TEST_ASSERT(ship.mission_suit_paid, "Lair did not claim the hull's suit flag") + TEST_ASSERT(!islist(posting.board_claim(ship, pad, proof, "dead")), "Closed lair paid twice") + TEST_ASSERT_EQUAL(ship.prize_rolls, 1, "Closed lair rolled again") + +/// Chip amounts on both mission surfaces remain separate from the completion fee. +/datum/unit_test/voidcrew_m2_rewards/chips/Run() + var/datum/mission/recovery/kill/kill_type = allocate(/datum/mission/recovery/kill/m2_rewards_test) + TEST_ASSERT_EQUAL(kill_type.guarded_prize_family, "kill", "Kill fixture lost its production prize family") + var/easy_cash = 0 + for(var/mob/living/basic/trooper/pirate/faction/pirate_type as anything in kill_type.easy_targets) + easy_cash += initial(pirate_type.plunder_credits) + TEST_ASSERT_EQUAL(easy_cash / length(kill_type.easy_targets), 300, "Wrong green kill-chip expectation") + var/medium_cash = 0 + for(var/mob/living/basic/trooper/pirate/faction/pirate_type as anything in kill_type.medium_targets) + medium_cash += initial(pirate_type.plunder_credits) + TEST_ASSERT_EQUAL(medium_cash / length(kill_type.medium_targets) + 300, 568.75, "Wrong yellow kill-chip expectation") + for(var/mob/living/basic/trooper/pirate/faction/pirate_type as anything in kill_type.hard_targets) + TEST_ASSERT_EQUAL(initial(pirate_type.plunder_credits) + 2 * 25, 3050, "Wrong red kill-chip expectation") + var/mob/living/basic/trooper/pirate/faction/medieval/captain/captain_type = /mob/living/basic/trooper/pirate/faction/medieval/captain + TEST_ASSERT_EQUAL(initial(captain_type.plunder_credits), 1000, "Medieval captain kept its melee chip value") + +/// Rewinding and reviving a kill still yields one chip, one settlement and one prize roll. +/datum/unit_test/voidcrew_m2_rewards/rewind/Run() + var/obj/structure/overmap/ship/m2_rewards_test/ship = test_ship() + var/datum/mission/recovery/kill/m2_rewards_test/mission = allocate(/datum/mission/recovery/kill/m2_rewards_test) + mission.objective_name = "Testbeard" + mission.quote_zone = 1 + mission.value = 600 + mission.requires_item = TRUE + var/datum/mission_target/kill_rewind_test/target = allocate(/datum/mission_target/kill_rewind_test, mission) + target.spawn_turf = run_loc_floor_top_right + mission.target = target + var/datum/mission_objective/field/kill_named/hunt = new + hunt.target_mob_type = /mob/living/basic/trooper/pirate/faction/boss/mission_rewind_test + mission.add_objective(hunt) + mission.add_objective(new /datum/mission_objective/deliver/bound/proof) + TEST_ASSERT(mission.start_mission(ship), "Rewind hunt did not start") + var/mob/living/basic/trooper/pirate/faction/boss/mission_rewind_test/boss = hunt.target_mob + TEST_ASSERT_NOTNULL(boss, "Rewind fixture did not spawn its boss") + boss.death(FALSE) + TEST_ASSERT(mission.named_kill_completed && mission.boss_cash_issued, "Initial kill did not preserve S06 flags") + TEST_ASSERT(boss.revive(ADMIN_HEAL_ALL), "Test boss could not revive") + boss.death(FALSE) + for(var/rewind in 1 to 2) + var/obj/item/mission_recovery/old_proof = mission.quest_atom + target.interior_loaded = FALSE + mission.on_target_interior_unloaded() + qdel(old_proof) + target.interior_loaded = TRUE + mission.on_target_interior_loaded() + TEST_ASSERT(mission.can_turn_in(mission.quest_atom), "Rewind lost proof recovery") + TEST_ASSERT_NULL(hunt.target_mob, "Completed kill respawned a boss") + TEST_ASSERT_EQUAL(length(run_loc_floor_top_right.get_all_contents_type(/obj/item/holochip)), 1, "Rewind or revival issued another boss chip") + var/before = ship.ship_account.account_balance + TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left, mission.quest_atom), "Recovered proof did not settle") + TEST_ASSERT_EQUAL(ship.ship_account.account_balance - before, 600, "Recovered proof paid the wrong fee") + TEST_ASSERT_EQUAL(ship.prize_rolls, 1, "Recovered proof must make exactly one completion roll") + TEST_ASSERT(!mission.turn_in(run_loc_floor_bottom_left, null, TRUE), "Repeated proof settlement succeeded") + mission.finish_mission(run_loc_floor_bottom_left) + TEST_ASSERT_EQUAL(ship.prize_rolls, 1, "Stale completion rolled another prize") + TEST_ASSERT_EQUAL(ship.ship_account.account_balance - before, 600, "Stale completion paid another fee") + +/// Named prizes record the receiving hull, quote zone, value and first-suit time. +/datum/unit_test/voidcrew_m2_rewards/prize_metrics/Run() + SSmetrics.accepting = TRUE + var/obj/structure/overmap/ship/m2_rewards_test/ship = test_ship() + ship.award_guarded_prize("kill", 1, run_loc_floor_bottom_left, /datum/mission/recovery/kill) + TEST_ASSERT_EQUAL(length(SSmetrics.pending), 1, "A suit should write one prize row") + var/list/row = SSmetrics.pending[1] + TEST_ASSERT_EQUAL(row["event"], "guarded_prize_paid", "Wrong prize event") + TEST_ASSERT_EQUAL(row["zone"], "green", "Prize metric lost its quote zone") + var/list/details = json_decode(row["details"]) + TEST_ASSERT_EQUAL(details["item_value"], 9000, "Wrong suit value") + TEST_ASSERT_EQUAL(details["first_suit_s"], ship.mission_first_suit_seconds, "First suit time was not recorded") + ship.award_guarded_prize("kill", 3, run_loc_floor_bottom_left) + TEST_ASSERT_EQUAL(length(SSmetrics.pending), 1, "A capped outcome wrote another prize payment") + +#endif diff --git a/voidcrew/modules/unit_tests/voidcrew_mission_metrics.dm b/voidcrew/modules/unit_tests/voidcrew_mission_metrics.dm index ae26c632c43..7b691abfaf5 100644 --- a/voidcrew/modules/unit_tests/voidcrew_mission_metrics.dm +++ b/voidcrew/modules/unit_tests/voidcrew_mission_metrics.dm @@ -80,7 +80,8 @@ tally_mission_offer(posted, null, "contract_offered") TEST_ASSERT_EQUAL(length(SSmetrics.tallies), 1, "Offers of one type on one board share a tally") SSmetrics.fold_tallies() - row = SSmetrics.pending[1] + TEST_ASSERT_EQUAL(length(SSmetrics.pending), 3, "Two quote records and one folded offer tally must be present") + row = SSmetrics.pending[3] TEST_ASSERT_EQUAL(row["quantity"], 2, "The tally counts every offer") /datum/unit_test/voidcrew_mission_metrics/Destroy() diff --git a/voidcrew/modules/unit_tests/voidcrew_missions.dm b/voidcrew/modules/unit_tests/voidcrew_missions.dm index bf5faeb38fe..a9e4e806a84 100644 --- a/voidcrew/modules/unit_tests/voidcrew_missions.dm +++ b/voidcrew/modules/unit_tests/voidcrew_missions.dm @@ -170,6 +170,9 @@ for(var/core_type in core_types) var/datum/mission/mission = allocate(/datum/mission) mission.value = 0 + mission.servant = allocate(/obj/structure/overmap/ship) + mission.servant.ship_account = allocate(/datum/bank_account) + mission.active = TRUE mission.requires_item = TRUE var/datum/mission_objective/deliver/delivery = new delivery.required_type = core_type @@ -188,6 +191,9 @@ /datum/unit_test/voidcrew_mission_pad_requirements/Run() var/datum/mission/mission = allocate(/datum/mission) mission.value = 0 + mission.servant = allocate(/obj/structure/overmap/ship) + mission.servant.ship_account = allocate(/datum/bank_account) + mission.active = TRUE mission.requires_item = TRUE var/datum/mission_objective/deliver/delivery = new delivery.required_type = /obj/item/stack/ore/iron @@ -338,6 +344,7 @@ mission.value = 1000 mission.voucher_count = initial(rescue_type.voucher_count) mission.servant = ship + mission.active = TRUE var/datum/mission_objective/field/escort/escort = new mission.add_objective(escort) escort.spawn_field_objects(pad_turf) @@ -506,6 +513,8 @@ /datum/unit_test/voidcrew_mission_kill_rewind/proc/make_hunt(big_game = FALSE) var/datum/mission/kill_rewind_test/mission = allocate(__IMPLIED_TYPE__) + mission.servant = allocate(/obj/structure/overmap/ship) + mission.servant.ship_account = allocate(/datum/bank_account) mission.active = TRUE mission.requires_item = TRUE mission.objective_name = "Old Testbeard" diff --git a/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm b/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm index 3d6c9bb621f..086f4f82f87 100644 --- a/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm +++ b/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm @@ -205,6 +205,8 @@ /// Procurement rejects forged submissions and consumes only eligible goods. /datum/unit_test/voidcrew_procurement_turn_in/Run() + var/obj/structure/overmap/ship/receiving_ship = allocate(/obj/structure/overmap/ship) + receiving_ship.ship_account = allocate(/datum/bank_account) var/list/unsupported_types = list( /obj/item/stack/ore/iron, /obj/item/stack/sheet/plasteel, @@ -218,6 +220,8 @@ for(var/item_type in unsupported_types) var/datum/mission/mission = allocate(/datum/mission) mission.requires_item = TRUE + mission.servant = receiving_ship + mission.active = TRUE var/datum/mission_objective/deliver/procurement/ask = new ask.required_type = item_type mission.add_objective(ask) @@ -228,6 +232,8 @@ var/datum/mission/control_mission = allocate(/datum/mission) control_mission.requires_item = TRUE + control_mission.servant = receiving_ship + control_mission.active = TRUE var/datum/mission_objective/deliver/procurement/control_ask = new control_ask.required_type = /obj/item/mod/control/pre_equipped control_mission.add_objective(control_ask) @@ -254,6 +260,8 @@ for(var/item_type in loose_types) var/datum/mission/mission = allocate(/datum/mission) mission.requires_item = TRUE + mission.servant = receiving_ship + mission.active = TRUE var/datum/mission_objective/deliver/procurement/ask = new ask.required_type = item_type ask.required_amount = 2 @@ -275,6 +283,8 @@ for(var/list/stack_case as anything in stack_cases) var/datum/mission/mission = allocate(/datum/mission) mission.requires_item = TRUE + mission.servant = receiving_ship + mission.active = TRUE var/datum/mission_objective/deliver/procurement/ask = new ask.required_type = stack_case[1] ask.required_amount = stack_case[2] From 8dad4e1f14b5e7c055697458004959d999d0ef54 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:32:45 -0700 Subject: [PATCH 039/105] NPC zone profile in planet generation and ore vents --- .../objects/structures/lavaland/ore_vent.dm | 5 +- voidcrew/datums/mapgen/PlanetGenerator.dm | 17 ++- .../unit_tests/voidcrew_npc_zone_profiles.dm | 126 ++++++++++++++++++ 3 files changed, 140 insertions(+), 8 deletions(-) diff --git a/code/game/objects/structures/lavaland/ore_vent.dm b/code/game/objects/structures/lavaland/ore_vent.dm index 97dc3a16d33..4f0de1e7400 100644 --- a/code/game/objects/structures/lavaland/ore_vent.dm +++ b/code/game/objects/structures/lavaland/ore_vent.dm @@ -602,7 +602,10 @@ if(!COOLDOWN_FINISHED(src, wave_cooldown)) return // Completely override the normal wave defense, and just spawn the boss. - var/mob/living/simple_animal/hostile/megafauna/boss = new summoned_boss(loc) + // VOIDCREW EDIT ADDITION START - npc_scaling: capture the vent's planet band before construction. + var/datum/npc_spawn_context/context = new(src, SSovermap_zones.planet_zone_type_for_turf(get_turf(src)), "boss") + var/mob/living/simple_animal/hostile/megafauna/boss = spawn_npc_in_zone(summoned_boss, loc, context) + // VOIDCREW EDIT ADDITION END RegisterSignal(boss, COMSIG_LIVING_DEATH, PROC_REF(handle_wave_conclusion)) SSblackbox.record_feedback("tally", "ore_vent_mobs_spawned", 1, summoned_boss) COOLDOWN_START(src, wave_cooldown, INFINITY) //Basically forever diff --git a/voidcrew/datums/mapgen/PlanetGenerator.dm b/voidcrew/datums/mapgen/PlanetGenerator.dm index 9907985c0fa..4bfb47df656 100644 --- a/voidcrew/datums/mapgen/PlanetGenerator.dm +++ b/voidcrew/datums/mapgen/PlanetGenerator.dm @@ -551,7 +551,8 @@ break if(can_spawn) - new picked_mob(target_turf) + var/datum/npc_spawn_context/context = new(src, zone_band, "auto", source_turf = target_turf) + spawn_npc_in_zone(picked_mob, target_turf, context) spawned_something = TRUE // The expensive half of a planet build - every iteration runs several range() // scans - and the one that most needs to stop hogging the tick. See @@ -560,8 +561,8 @@ // forward-progress floor than the default, to keep its tick overshoot in line. SSovermap.worldgen_yield(throttled, min_iterations = 8) - var/spawners_placed = place_budgeted_spawners(spawner_candidates, spawner_budget) - var/megafauna_placed = place_planet_megafauna(megafauna_candidates) + var/spawners_placed = place_budgeted_spawners(spawner_candidates, spawner_budget, zone_band) + var/megafauna_placed = place_planet_megafauna(megafauna_candidates, zone_band) var/anomalies_placed = place_budgeted_anomalies(turfs, anomaly_budget) log_world("[name] terrain population finished in [(REALTIMEOFDAY - start_time)/10]s! \ @@ -577,7 +578,7 @@ * row-major, so taking the first N would put every tendril on the planet in the same * corner. Returns how many were placed. */ -/datum/map_generator/planet_generator/proc/place_budgeted_spawners(list/candidates, budget) +/datum/map_generator/planet_generator/proc/place_budgeted_spawners(list/candidates, budget, zone_band) if(!length(candidates) || budget <= 0) return 0 @@ -599,7 +600,8 @@ continue var/spawner_type = candidates[candidate] - new spawner_type(candidate) + var/datum/npc_spawn_context/context = new(src, zone_band, "auto", source_turf = candidate) + spawn_npc_in_zone(spawner_type, candidate, context) placed_at += candidate placed++ CHECK_TICK @@ -681,7 +683,7 @@ /// Places a single megafauna from the banked candidates. One per planet, and only where /// the zone band allows them at all - see megafauna_allowed in populate_terrain(). -/datum/map_generator/planet_generator/proc/place_planet_megafauna(list/candidates) +/datum/map_generator/planet_generator/proc/place_planet_megafauna(list/candidates, zone_band) if(!length(candidates)) return 0 @@ -691,7 +693,8 @@ if(!isturf(candidate) || candidate.density) continue var/megafauna_type = candidates[candidate] - new megafauna_type(candidate) + var/datum/npc_spawn_context/context = new(src, zone_band, "boss", source_turf = candidate) + spawn_npc_in_zone(megafauna_type, candidate, context) return 1 return 0 diff --git a/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm index 2400fae7636..db22432ab78 100644 --- a/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm +++ b/voidcrew/modules/unit_tests/voidcrew_npc_zone_profiles.dm @@ -310,6 +310,132 @@ TEST_ASSERT_EQUAL(body.npc_spawn_context.source_id, REF(tracker), "Deferred fauna lost tracker identity") qdel(body) +/// Keep these route fixtures focused on fauna and structures, without natural anomalies. +/datum/map_generator/planet_generator/npc_zone_test/place_budgeted_anomalies(list/turfs, budget) + return 0 + +/datum/unit_test/voidcrew_npc_zone_planet_routes + abstract_type = /datum/unit_test/voidcrew_npc_zone_planet_routes + var/turf/location + var/datum/biome/original_biome + var/original_flags + var/original_river + var/datum/biome/biome + var/datum/map_generator/planet_generator/npc_zone_test/generator + +/datum/unit_test/voidcrew_npc_zone_planet_routes/New() + . = ..() + location = run_loc_floor_bottom_left + original_biome = location.generating_biome + original_flags = location.turf_flags + original_river = location.planet_river + biome = allocate(/datum/biome) + biome.open_turf_types = list(location.type) + biome.flora_spawn_chance = 0 + biome.feature_spawn_chance = 0 + biome.mob_spawn_chance = 100 + biome.dangerous_mob_spawn_list = null + location.generating_biome = biome + location.turf_flags &= ~(NO_RUINS | TURF_BLOCKS_POPULATE_TERRAIN_FLORAFEATURES) + location.planet_river = FALSE + generator = allocate(/datum/map_generator/planet_generator/npc_zone_test) + generator.throttled = FALSE + +/datum/unit_test/voidcrew_npc_zone_planet_routes/Destroy() + location.generating_biome = original_biome + location.turf_flags = original_flags + location.planet_river = original_river + return ..() + +/datum/unit_test/voidcrew_npc_zone_planet_routes/fallback/Run() + TEST_ASSERT_NULL(SSplanet_mobs.tracker_for_turf(location), "Fallback fixture unexpectedly has deferred fauna tracking") + var/datum/npc_spawn_context/expected = allocate(/datum/npc_spawn_context, generator, 3, "auto", FALSE, location) + for(var/mob_type in list(/mob/living/basic/npc_zone_test, /mob/living/basic/npc_zone_test/replacement, /mob/living/basic/npc_zone_test/passive)) + biome.mob_spawn_list = list((mob_type) = 1) + generator.populate_terrain(list(location), get_area(location), 3) + var/mob/living/basic/npc_zone_test/body = locate() in location + TEST_ASSERT_NOTNULL(body, "Planet fallback did not produce [mob_type]") + allocated += body + TEST_ASSERT_EQUAL(body.npc_spawn_context?.role, "auto", "Planet fallback bypassed the environmental hostility gate") + TEST_ASSERT_EQUAL(body.npc_spawn_context.source_turf, location, "Planet fallback pinned the wrong source turf") + if(mob_type == /mob/living/basic/npc_zone_test/passive) + TEST_ASSERT(!body.npc_zone_applied, "Passive fallback fauna received a hostile profile") + TEST_ASSERT_EQUAL(body.maxHealth, 100, "Passive fallback fauna health changed") + else + check_npc_zone_child(body, expected) + qdel(body) + +/datum/unit_test/voidcrew_npc_zone_planet_routes/megafauna/Run() + biome.mob_spawn_list = list(SPAWN_MEGAFAUNA = 1) + biome.megafauna_spawn_list = list(/mob/living/simple_animal/hostile/megafauna = 1) + generator.populate_terrain(list(location), get_area(location), 3) + var/mob/living/simple_animal/hostile/megafauna/boss = locate() in location + TEST_ASSERT_NOTNULL(boss, "Planet generator did not place its red megafauna") + allocated += boss + TEST_ASSERT_EQUAL(boss.npc_spawn_context?.role, "boss", "Planet megafauna omitted its explicit boss role") + var/datum/npc_spawn_context/expected = allocate(/datum/npc_spawn_context, generator, 3, "boss", FALSE, location) + check_npc_zone_child(boss, expected, boss = TRUE) + +/// Both biome tables converge on the same budgeted structure placement route. +/datum/unit_test/voidcrew_npc_zone_planet_routes/nests/Run() + for(var/from_features in list(FALSE, TRUE)) + biome.mob_spawn_list = from_features ? null : list(/obj/structure/spawner = 1) + biome.feature_spawn_list = from_features ? list(/obj/structure/spawner = 1) : null + biome.feature_spawn_chance = from_features ? 100 : 0 + generator.populate_terrain(list(location), get_area(location), 3) + var/obj/structure/spawner/nest = locate() in location + TEST_ASSERT_NOTNULL(nest, "Planet generator lost a budgeted nest") + allocated += nest + TEST_ASSERT_EQUAL(nest.npc_spawn_context?.zone_type, 3, "Planet nest lost the selected band") + TEST_ASSERT_EQUAL(nest.npc_spawn_context.role, "auto", "Planet nest omitted its environmental role") + TEST_ASSERT_EQUAL(nest.npc_spawn_context.source_id, REF(generator), "Planet nest lost its generator source") + var/datum/npc_spawn_context/child_context = allocate(/datum/npc_spawn_context, nest) + var/mob/living/child = spawn_npc_in_zone(/mob/living/basic/npc_zone_test/replacement, run_loc_floor_top_right, child_context) + allocated += child + check_npc_zone_child(child, nest.npc_spawn_context) + qdel(child) + qdel(nest) + +/// Use the real vent boss route and a yellow planet footprint on the shared test level. +/datum/unit_test/voidcrew_npc_zone_ore_vent_route + parent_type = /datum/unit_test/voidcrew_npc_zone_packed + +/datum/unit_test/voidcrew_npc_zone_ore_vent_route/Run() + zones_were_active = SSovermap_zones.zones_active + SSovermap_zones.zones_active = TRUE + var/turf/base = run_loc_floor_bottom_left + var/original_type = base.type + var/turf/open/overmap/token = base.ChangeTurf(/turf/open/overmap) + overmap_turfs[token] = original_type + token.current_zone = allocate(/datum/overmap_zone, 2) + var/turf/location = run_loc_floor_top_right + var/datum/map_zone/zone = allocate(/datum/map_zone) + zone.z_levels = list(reservation) + var/datum/map_footprint/footprint = allocate(/datum/map_footprint) + footprint.z_value = location.z + footprint.set_rect(location.x, location.y, 1, 1) + var/obj/structure/overmap/planet/site = allocate(/obj/structure/overmap/planet, token) + sites += site + site.mapzone = zone + site.footprint = footprint + var/obj/structure/ore_vent/boss/vent = allocate(/obj/structure/ore_vent/boss, location) + vent.summoned_boss = /mob/living/simple_animal/hostile/megafauna + vent.start_wave_defense() + var/mob/living/simple_animal/hostile/megafauna/boss = locate() in location + TEST_ASSERT_NOTNULL(boss, "Vent did not summon its boss") + allocated += boss + TEST_ASSERT_EQUAL(boss.npc_spawn_context?.role, "boss", "Vent omitted its explicit boss role") + var/datum/npc_spawn_context/expected = allocate(/datum/npc_spawn_context, vent, 2, "boss", FALSE, location) + check_npc_zone_child(boss, expected, boss = TRUE) + // Death still reaches the original conclusion, and its neutral drone stays baseline. + boss.set_health(0) + boss.death() + var/mob/living/basic/node_drone/drone = locate() in location + TEST_ASSERT_NOTNULL(drone, "Profiled vent boss lost its death callback") + allocated += drone + TEST_ASSERT(drone.is_npc_zone_exempt() && !drone.npc_zone_applied, "Vent node drone received a hostile profile") + TEST_ASSERT_EQUAL(drone.maxHealth, initial(drone.maxHealth), "Vent node drone health was scaled") + /datum/unit_test/voidcrew_npc_zone_spawner var/mob/living/watcher var/watched_z From 77fc892149aa8b75c0fd3e720e0ad1b39f776f98 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 15:03:02 -0700 Subject: [PATCH 040/105] Ladder: trader catalogs --- .../modules/cyberware/ripperdoc_catalog.dm | 41 ++- voidcrew/modules/trade/shop.dm | 20 +- .../trade/shop_catalog_black_market.dm | 254 ++++++++++------ .../modules/trade/shop_catalog_general.dm | 133 +++------ .../trade/shop_catalog_general_vendors.dm | 85 +----- .../modules/trade/shop_catalog_outfitter.dm | 131 +++++---- .../unit_tests/voidcrew_shop_catalog.dm | 278 ++++++++++++++++++ 7 files changed, 614 insertions(+), 328 deletions(-) diff --git a/voidcrew/modules/cyberware/ripperdoc_catalog.dm b/voidcrew/modules/cyberware/ripperdoc_catalog.dm index ff4f0506e45..11ad9028802 100644 --- a/voidcrew/modules/cyberware/ripperdoc_catalog.dm +++ b/voidcrew/modules/cyberware/ripperdoc_catalog.dm @@ -3,10 +3,8 @@ * * The Undertow's chrome parlor: a vendor stall (own stock, own voice, own * ledger) fronted by Splice, who sits behind the counter in the neon annex off - * the Dregs. He sells cyberware and nothing else, the whole roster, tiered up - * the voucher ladder, with the flagships always on the shelf so the chase is - * plannable. Ammunition for the arm weapons is parlor-only: the return-visit - * hook. + * the Dregs. He sells utility chrome, limited melee implants and ammunition + * for salvaged gun arms. * * Balance shape mirrors Vex's counter: credits buy the street and pro-utility * ware, vouchers gate everything that changes how you fight. Splice's intake @@ -92,11 +90,9 @@ /datum/shop_sku/ripperdoc/atlas, /datum/shop_sku/ripperdoc/gorilla, /datum/shop_sku/ripperdoc/monowire, - /datum/shop_sku/ripperdoc/ronin, /datum/shop_sku/ripperdoc/rigger, /datum/shop_sku/ripperdoc/slabskin, /datum/shop_sku/ripperdoc/mantis, - /datum/shop_sku/ripperdoc/bunker_buster, /datum/shop_sku/ripperdoc/ghostskin, /datum/shop_sku/ripperdoc/lazarus, // ---- Legend Chrome (the chase, always listed) ---- @@ -334,20 +330,35 @@ /datum/shop_sku/ripperdoc/gorilla category = "Military Chrome" name = "Gorilla Arms (pair)" - desc = "A pair of chrome forearms that punch through people, doors, and rock in that order. Sold cased; install one side at a time." + desc = "A cased pair of heavy chrome forearms." item_path = /obj/item/cyberware_pair_case/gorilla_arms price_vouchers = 3 + stock_min = 1 + stock_max = 1 + restock_interval = INFINITY + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/ripperdoc/monowire category = "Military Chrome" item_path = /obj/item/organ/cyberimp/arm/toolkit/cyberware/monowire price_vouchers = 3 + stock_min = 1 + stock_max = 1 + restock_interval = INFINITY + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/ripperdoc/ronin category = "Military Chrome" - desc = "A submachine gun that folds into your forearm. Feeds a proprietary caliber only I sell. See the Ammunition shelf. Nobody is disarming you of it." + desc = "A submachine gun folded into a chrome forearm." item_path = /obj/item/organ/cyberimp/arm/toolkit/cyberware/ronin price_vouchers = 3 + stock_min = 0 + stock_max = 0 + restock_interval = INFINITY + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/ripperdoc/rigger category = "Military Chrome" @@ -363,15 +374,25 @@ /datum/shop_sku/ripperdoc/mantis category = "Military Chrome" name = "Mantis Blades (pair)" - desc = "A pair of folded blades where your forearms were. The lunge is the selling point; the reaction you get is free. Sold cased, install one side at a time." + desc = "A cased pair of folding forearm blades." item_path = /obj/item/cyberware_pair_case/mantis_blades price_vouchers = 4 + stock_min = 1 + stock_max = 1 + restock_interval = INFINITY + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/ripperdoc/bunker_buster category = "Military Chrome" - desc = "A two-shot rocket pod built into the forearm. Reloads are parlor-only. See the Ammunition shelf. Shaped charge, so it won't open your hull. Or theirs. Just whoever's standing in it." + desc = "A rocket pod built into a chrome forearm." item_path = /obj/item/organ/cyberimp/arm/toolkit/cyberware/bunker_buster price_vouchers = 4 + stock_min = 0 + stock_max = 0 + restock_interval = INFINITY + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/ripperdoc/ghostskin category = "Military Chrome" diff --git a/voidcrew/modules/trade/shop.dm b/voidcrew/modules/trade/shop.dm index 73f0aa9c589..5ee9c51ba07 100644 --- a/voidcrew/modules/trade/shop.dm +++ b/voidcrew/modules/trade/shop.dm @@ -196,7 +196,7 @@ if(sku.rotation != rotation) continue on_shelf += sku.type - if(sku.stock <= 0) + if(sku.stock <= 0 && !sku.restock_interval) sold_out += sku for(var/datum/shop_sku/gone as anything in sold_out) skus -= gone @@ -237,6 +237,9 @@ /datum/outpost_shop/proc/convoy_restock() // Core shelves creep back toward full for(var/datum/shop_sku/sku as anything in skus) + // Timed stock has its own clock; INFINITY keeps a finite shelf exhausted. + if(sku.restock_interval) + continue if(sku.shelf == SHELF_CORE && sku.stock < sku.stock_max - sku.reserved_stock) sku.stock = min(sku.stock_max - sku.reserved_stock, sku.stock + max(1, round(sku.stock_max / 2))) // A new paid chart creates a fresh ruin, so named tips can be sold again. @@ -249,7 +252,7 @@ // a sold tip for an unrelated good. Named tips replenish separately above. var/list/depleted = list() for(var/datum/shop_sku/sku as anything in skus) - if(sku.shelf == SHELF_ROTATING && !sku.is_chart && !sku.rotation && sku.stock <= 0) + if(sku.shelf == SHELF_ROTATING && !sku.is_chart && !sku.rotation && !sku.restock_interval && sku.stock <= 0) depleted += sku if(length(depleted)) var/datum/shop_sku/gone = pick(depleted) @@ -448,10 +451,16 @@ var/fixed_price = FALSE /// Whether outpost contracts may pay this out as part of a reward bundle var/contract_reward = TRUE + /// 0 uses convoys; a positive interval returns one unit; INFINITY never refills. + var/restock_interval = 0 + /// Independent of convoy arrivals, visits, specials and crew ownership. + var/restock_timer /datum/shop_sku/New() ..() stock = rand(stock_min, stock_max) + if(restock_interval > 0 && restock_interval < INFINITY) + restock_timer = addtimer(CALLBACK(src, PROC_REF(restock_unit)), restock_interval, TIMER_STOPPABLE | TIMER_LOOP | TIMER_DELETE_ME) if(item_path) var/atom/movable/cast = item_path if(!name) @@ -460,10 +469,17 @@ desc = initial(cast.desc) /datum/shop_sku/Destroy() + if(restock_timer) + deltimer(restock_timer) + restock_timer = null shop = null rotation = null return ..() +/// Never bank missed deliveries while full, or replenish a reserved contract unit. +/datum/shop_sku/proc/restock_unit() + stock = min(max(0, stock_max - reserved_stock), stock + 1) + /** * The credit price after discounts, rounded down to a clean 5. With a buyer, * their crew's favor discount competes with the special: the better of the two diff --git a/voidcrew/modules/trade/shop_catalog_black_market.dm b/voidcrew/modules/trade/shop_catalog_black_market.dm index 1d4c73bee23..24cbbfd65fc 100644 --- a/voidcrew/modules/trade/shop_catalog_black_market.dm +++ b/voidcrew/modules/trade/shop_catalog_black_market.dm @@ -58,14 +58,14 @@ ) sku_types = list( // Weapons - /datum/shop_sku/black_market/pistol, + /datum/shop_sku/black_market/boarding_axe, + /datum/shop_sku/black_market/cutlass, + /datum/shop_sku/black_market/c20r, + /datum/shop_sku/black_market/wt550, + /datum/shop_sku/black_market/rotating/mateba, /datum/shop_sku/black_market/pistol_mag, - /datum/shop_sku/black_market/revolver, /datum/shop_sku/black_market/speedloader, - /datum/shop_sku/black_market/suppressor, /datum/shop_sku/black_market/quiet_word_mag, - /datum/shop_sku/black_market/combat_knife, - /datum/shop_sku/black_market/switchblade, // Explosives /datum/shop_sku/black_market/c4, /datum/shop_sku/black_market/emp_grenade, @@ -136,25 +136,19 @@ ) chart_picks = 3 rotating_pool = list( - /datum/shop_sku/black_market/rotating/mateba, - /datum/shop_sku/black_market/rotating/ebow, /datum/shop_sku/black_market/rotating/minibomb, - /datum/shop_sku/black_market/rotating/dart_pistol, /datum/shop_sku/black_market/rotating/mod_flamethrower, /datum/shop_sku/black_market/rotating/mod_chameleon, - /datum/shop_sku/black_market/rotating/mod_active_sonar, /datum/shop_sku/black_market/rotating/ew_runaway_burn, /datum/shop_sku/black_market/rotating/ew_helm_poltergeist, ) rare_pool = list( /datum/shop_sku/black_market/rare/energy_sword, - /datum/shop_sku/black_market/rare/energy_shield, /datum/shop_sku/black_market/rare/mod_adrenaline, ) // The back room: Trusted-standing uniques, per-crew supply (trader_favor.dm) favor_sku_types = list( /datum/shop_sku/favor/vex_insurance, - /datum/shop_sku/favor/quiet_word, ) // The consignment window: Vex fences planet exotics and ruin loot at the // best rates in the system. Voucher payouts are strictly planet/danger-gated. @@ -227,14 +221,6 @@ // ===== WEAPONS ===== -/datum/shop_sku/black_market/pistol - category = "Weapons" - item_path = /obj/item/gun/ballistic/automatic/pistol - price_vouchers = 2 - price_credits = 1500 - stock_min = 2 - stock_max = 4 - /datum/shop_sku/black_market/pistol_mag category = "Weapons" item_path = /obj/item/ammo_box/magazine/m9mm @@ -242,13 +228,6 @@ stock_min = 4 stock_max = 8 -/datum/shop_sku/black_market/revolver - category = "Weapons" - item_path = /obj/item/gun/ballistic/revolver - price_vouchers = 3 - stock_min = 1 - stock_max = 2 - /datum/shop_sku/black_market/speedloader category = "Weapons" item_path = /obj/item/ammo_box/a357 @@ -256,15 +235,7 @@ stock_min = 2 stock_max = 5 -/datum/shop_sku/black_market/suppressor - category = "Weapons" - item_path = /obj/item/suppressor - price_credits = 1200 - stock_min = 2 - stock_max = 4 - -// Feeds the back room's Quiet Word (and any 10mm pistol); on the open shelf so -// the gun stays fed after the one-per-crew purchase is spent +// Reloads for salvaged 10mm pistols. /datum/shop_sku/black_market/quiet_word_mag category = "Weapons" item_path = /obj/item/ammo_box/magazine/m10mm/quiet_word @@ -272,20 +243,6 @@ stock_min = 3 stock_max = 6 -/datum/shop_sku/black_market/combat_knife - category = "Weapons" - item_path = /obj/item/knife/combat - price_credits = 1050 - stock_min = 2 - stock_max = 4 - -/datum/shop_sku/black_market/switchblade - category = "Weapons" - item_path = /obj/item/switchblade - price_credits = 900 - stock_min = 2 - stock_max = 4 - // ===== EXPLOSIVES ===== /datum/shop_sku/black_market/c4 @@ -640,29 +597,32 @@ // through chart_pool above. The generic rumor rides the core shelf. // ===== MYSTERY CARGO ===== -// The gamble channel, sold over the counter: sealed caches rolling the zone -// loot tables. The crate pins its band to the spawn turf, bought at the -// Undertow, it rolls on lawless odds. The reinforced one is not a different -// table, just a fuller crate; nothing here is unobtainable from a cache -// found in the field. +// Bought caches keep syndicate supplies but use freight weapon odds and classes. +// The premium crate adds nonweapon draws only. /datum/shop_sku/black_market/mystery_cache category = "Mystery Cargo" name = "sealed cache" desc = "A locked syndicate supply cache, contents sight-unseen. Vex guarantees it's worth something. Vex guarantees nothing else." - item_path = /obj/structure/closet/crate/zone_loot/syndicate + item_path = /obj/structure/closet/crate/zone_loot/syndicate/trader price_vouchers = 2 - stock_min = 2 - stock_max = 3 + stock_min = 1 + stock_max = 1 + restock_interval = INFINITY + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/black_market/mystery_cache_rare category = "Mystery Cargo" name = "reinforced cache" desc = "The good crate. The one from the back room. Even Vex looks curious when one moves." - item_path = /obj/structure/closet/crate/zone_loot/syndicate/reinforced + item_path = /obj/structure/closet/crate/zone_loot/syndicate/trader/reinforced price_vouchers = 4 stock_min = 1 stock_max = 1 + restock_interval = INFINITY + fixed_price = TRUE + contract_reward = FALSE // ===== SUNDRIES ===== @@ -693,24 +653,19 @@ /datum/shop_sku/black_market/rotating/mateba category = "Weapons" item_path = /obj/item/gun/ballistic/revolver/mateba - price_vouchers = 4 - -/datum/shop_sku/black_market/rotating/ebow - category = "Weapons" - name = "miniature energy crossbow" - item_path = /obj/item/gun/energy/recharge/ebow - price_vouchers = 6 + price_vouchers = 1 + price_credits = 3000 + stock_min = 1 + stock_max = 1 + restock_interval = 1 HOURS + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/black_market/rotating/minibomb category = "Explosives" item_path = /obj/item/grenade/syndieminibomb price_vouchers = 3 -/datum/shop_sku/black_market/rotating/dart_pistol - category = "Weapons" - item_path = /obj/item/gun/syringe/syndicate - price_vouchers = 2 - /datum/shop_sku/black_market/rotating/mod_flamethrower category = "MODsuits" desc = "A suit-mounted flamethrower. Three seconds between bursts and it costs a lot of charge, so pick your moment." @@ -723,12 +678,6 @@ item_path = /obj/item/mod/module/chameleon price_vouchers = 2 -/datum/shop_sku/black_market/rotating/mod_active_sonar - category = "MODsuits" - desc = "Pings for living things around you and puts them on your HUD. Everyone in earshot hears the ping too." - item_path = /obj/item/mod/module/active_sonar - price_vouchers = 2 - /datum/shop_sku/black_market/rotating/ew_runaway_burn category = "Exploit Software" name = "Runaway Burn exploit cartridge" @@ -749,11 +698,12 @@ category = "Weapons" item_path = /obj/item/melee/energy/sword/saber price_vouchers = 4 - -/datum/shop_sku/black_market/rare/energy_shield - category = "Weapons" - item_path = /obj/item/shield/energy - price_vouchers = 3 + price_credits = 4000 + stock_min = 1 + stock_max = 1 + restock_interval = INFINITY + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/black_market/rare/mod_adrenaline category = "MODsuits" @@ -843,7 +793,7 @@ demand_max = 5 // ===== BACK ROOM ===== -// Vex's favor uniques: Trusted standing only, up to FAVOR_UNIQUE_CREW_LIMIT +// Vex's favor unique: Trusted standing only, up to FAVOR_UNIQUE_CREW_LIMIT // per crew per round. Priced above the rare shelf on purpose, standing opens // the door, it doesn't pay the bill. All prices PROVISIONAL BALANCE. @@ -854,7 +804,141 @@ price_credits = 3000 price_vouchers = 3 -/datum/shop_sku/favor/quiet_word - item_path = /obj/item/gun/ballistic/automatic/pistol/clandestine/quiet_word - price_credits = 2000 +// ===== COUNTER ARMS ===== + +/datum/shop_sku/black_market/boarding_axe + category = "Weapons" + item_path = /obj/item/fireaxe/boardingaxe + price_credits = 2400 + price_vouchers = 0 + stock_min = 1 + stock_max = 1 + +/datum/shop_sku/black_market/cutlass + category = "Weapons" + item_path = /obj/item/claymore/cutlass + price_credits = 3000 price_vouchers = 3 + stock_min = 1 + stock_max = 1 + restock_interval = INFINITY + fixed_price = TRUE + contract_reward = FALSE + +/datum/shop_sku/black_market/c20r + category = "Weapons" + item_path = /obj/item/gun/ballistic/automatic/c20r/unrestricted + price_credits = 3600 + price_vouchers = 2 + stock_min = 1 + stock_max = 1 + restock_interval = 1 HOURS + fixed_price = TRUE + contract_reward = FALSE + +/datum/shop_sku/black_market/wt550 + category = "Weapons" + item_path = /obj/item/gun/ballistic/automatic/wt550 + price_credits = 4200 + price_vouchers = 2 + stock_min = 1 + stock_max = 1 + restock_interval = 1 HOURS + fixed_price = TRUE + contract_reward = FALSE + +/// Counter-bought caches retain themed supplies, with a single freight weapon roll. +/// Kept separate from guarded caches so buying a crate cannot buy advanced guns. +/obj/structure/closet/crate/zone_loot/syndicate/trader + var/manifest_opened = FALSE + +/obj/structure/closet/crate/zone_loot/syndicate/trader/reinforced + name = "reinforced syndicate cache" + desc = "A matte-black drop crate in an extra layer of plating." + bonus_draws = 2 + +/// Replaces the guarded-cache payout; deliberately does not call its parent. +/obj/structure/closet/crate/zone_loot/syndicate/trader/PopulateContents() + if(manifest_opened) + return + manifest_opened = TRUE + if(isnull(loot_zone)) + loot_zone = SSovermap_zones.get_zone_type_anywhere(spawn_turf) + if(isnull(loot_zone)) + loot_zone = ZONE_GREEN + spawn_turf = null + + var/list/pools = get_supply_pools() + var/draws_min = ZONE_LOOT_DRAWS_MIN_GREEN + var/draws_max = ZONE_LOOT_DRAWS_MAX_GREEN + var/list/tier_odds = ZONE_LOOT_ODDS_GREEN + switch(loot_zone) + if(ZONE_YELLOW) + draws_min = ZONE_LOOT_DRAWS_MIN_YELLOW + draws_max = ZONE_LOOT_DRAWS_MAX_YELLOW + tier_odds = ZONE_LOOT_ODDS_YELLOW + if(ZONE_RED) + draws_min = ZONE_LOOT_DRAWS_MIN_RED + draws_max = ZONE_LOOT_DRAWS_MAX_RED + tier_odds = ZONE_LOOT_ODDS_RED + // The weapon replaces one ordinary draw; premium draws remain supplies. + roll_loot_draws(src, pools, rand(draws_min, draws_max) - 1 + bonus_draws, tier_odds) + var/weapon_path = roll_weapon() + new weapon_path(src) + var/spare_ammo = GLOB.loot_gun_spare_ammo[weapon_path] + if(spare_ammo) + new spare_ammo(src) + +/// Working copies only: filtering a bought crate must never change field loot. +/obj/structure/closet/crate/zone_loot/syndicate/trader/proc/get_supply_pools() + var/datum/loot_theme/loot_theme = GLOB.loot_themes[theme] + var/list/pools = list( + "[LOOT_TIER_COMMON]" = loot_theme.loot_common.Copy(), + "[LOOT_TIER_UNCOMMON]" = loot_theme.loot_uncommon.Copy(), + "[LOOT_TIER_PRIME]" = loot_theme.loot_prime.Copy(), + "[LOOT_TIER_UNIQUE]" = loot_theme.loot_uniques.Copy(), + ) + for(var/tier in pools) + var/list/pool = pools[tier] + for(var/loot_path in pool.Copy()) + if(ispath(loot_path, /obj/item/gun) || ispath(loot_path, /obj/item/knife) || ispath(loot_path, /obj/item/melee) \ + || ispath(loot_path, /obj/item/claymore) || ispath(loot_path, /obj/item/katana) || ispath(loot_path, /obj/item/fireaxe) \ + || ispath(loot_path, /obj/item/spear) || ispath(loot_path, /obj/item/hatchet) || ispath(loot_path, /obj/item/mjollnir) \ + || ispath(loot_path, /obj/item/organ/cyberimp) || ispath(loot_path, /obj/item/organ/eyes/robotic/cyberware) \ + || ispath(loot_path, /obj/item/cyberware_pair_case) || ispath(loot_path, /obj/item/storage/case/cyberware)) + pool -= loot_path + return pools + +/obj/structure/closet/crate/zone_loot/syndicate/trader/proc/get_gun_chance() + switch(loot_zone) + if(ZONE_YELLOW) + return 19 + if(ZONE_RED) + return 33 + return 8 + +/obj/structure/closet/crate/zone_loot/syndicate/trader/proc/get_weapon_class_weights(gun) + switch(loot_zone) + if(ZONE_YELLOW) + return gun ? list("green" = 45, "yellow" = 54, "red" = 1) : list("green" = 35, "yellow" = 64, "red" = 1) + if(ZONE_RED) + return gun ? list("green" = 15, "yellow" = 35, "red" = 50) : list("green" = 10, "yellow" = 45, "red" = 45) + return gun ? list("green" = 940, "yellow" = 59, "red" = 1) : list("green" = 900, "yellow" = 99, "red" = 1) + +/obj/structure/closet/crate/zone_loot/syndicate/trader/proc/get_weapon_pool(gun, weapon_class) + if(gun) + if(weapon_class == "green") + return list(/obj/item/gun/ballistic/rifle/boltaction/surplus, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver/c38/detective, /obj/item/gun/ballistic/shotgun/doublebarrel) + // Freight substitutes ordinary guns even when the advanced class wins. + return list(/obj/item/gun/ballistic/shotgun/riot, /obj/item/gun/ballistic/automatic/tommygun, /obj/item/gun/ballistic/automatic/mini_uzi) + switch(weapon_class) + if("green") + return list(/obj/item/knife/combat/survival, /obj/item/spear, /obj/item/hatchet, /obj/item/melee/baseball_bat) + if("yellow") + return list(/obj/item/knife/combat, /obj/item/claymore/shortsword, /obj/item/melee/baseball_bat/ablative, /obj/item/fireaxe, /obj/item/melee/cleric_mace, /obj/item/melee/sabre) + if("red") + return list(/obj/item/claymore, /obj/item/claymore/cutlass, /obj/item/katana, /obj/item/mjollnir, /obj/item/melee/energy/sword/saber, /obj/item/melee/energy/sword/pirate) + +/obj/structure/closet/crate/zone_loot/syndicate/trader/proc/roll_weapon() + var/gun = prob(get_gun_chance()) + return pick(get_weapon_pool(gun, pick_weight(get_weapon_class_weights(gun)))) diff --git a/voidcrew/modules/trade/shop_catalog_general.dm b/voidcrew/modules/trade/shop_catalog_general.dm index c795c0b01b7..18f8676ace4 100644 --- a/voidcrew/modules/trade/shop_catalog_general.dm +++ b/voidcrew/modules/trade/shop_catalog_general.dm @@ -2,7 +2,7 @@ * # Waystation Halcyon: the green-zone general store * * Sundries, survival kit and honest prices for the safe inner ring. Credits - * only; the most dangerous thing on the shelf is the chili in the rations. + * only, with surplus arms behind the counter. * Shop machinery lives in shop.dm; this file is pure catalog. */ @@ -34,6 +34,7 @@ "Tools & Repair", "Medical", "Prospecting", + "Arms", "Fuel & Gas", "Galley & Comforts", "Ship Sundries", @@ -49,35 +50,29 @@ /datum/shop_sku/general/breath_mask, /datum/shop_sku/general/eva_suit, /datum/shop_sku/general/eva_helmet, - /datum/shop_sku/general/gps, /datum/shop_sku/general/flare, /datum/shop_sku/general/glowstick, /datum/shop_sku/general/survival_medipen, /datum/shop_sku/general/oxygen_canister, /datum/shop_sku/general/jetpack, // Tools & Repair - /datum/shop_sku/general/toolbelt, - /datum/shop_sku/general/big_welder, /datum/shop_sku/general/welding_fuel, - /datum/shop_sku/general/light_replacer, - /datum/shop_sku/general/holofan, - /datum/shop_sku/general/rcd, // Medical /datum/shop_sku/general/medkit, /datum/shop_sku/general/burn_kit, /datum/shop_sku/general/o2_kit, - /datum/shop_sku/general/health_analyzer, /datum/shop_sku/general/epipen, /datum/shop_sku/general/gauze, /datum/shop_sku/general/suture, /datum/shop_sku/general/regen_mesh, // Prospecting - /datum/shop_sku/general/pickaxe, - /datum/shop_sku/general/mesons, /datum/shop_sku/general/ore_bag, - /datum/shop_sku/general/mining_scanner, /datum/shop_sku/general/adv_mining_scanner, /datum/shop_sku/general/diamond_pick, + // Arms + /datum/shop_sku/general/hunting_knife, + /datum/shop_sku/general/survival_knife, + /datum/shop_sku/general/surplus_rifle, // Fuel & Gas /datum/shop_sku/general/plasma_canister, /datum/shop_sku/general/plasma_sheets, @@ -113,13 +108,8 @@ /datum/shop_sku/general/rotating/freight_crate, /datum/shop_sku/general/rotating/metalfoam, /datum/shop_sku/general/rotating/bikehorn, - /datum/shop_sku/general/rotating/welding_goggles, /datum/shop_sku/general/rotating/guitar, ) - rare_pool = list( - /datum/shop_sku/general/rare/bluespace_bodybag, - /datum/shop_sku/general/rare/drill, - ) // The back room: Trusted-standing uniques, per-crew supply (trader_favor.dm) favor_sku_types = list( /datum/shop_sku/favor/pike_ledger, @@ -253,11 +243,6 @@ stock_min = 10 stock_max = 20 -/datum/shop_sku/general/gps - category = "Survival & EVA" - item_path = /obj/item/gps - price_credits = 200 - /datum/shop_sku/general/flare category = "Survival & EVA" item_path = /obj/item/flashlight/flare @@ -299,19 +284,13 @@ // ===== TOOLS & REPAIR ===== +// Retained for the ordinary-shelf unit-test fixture; not sold at an outpost. /datum/shop_sku/general/toolbelt category = "Tools & Repair" item_path = /obj/item/storage/belt/utility/full - desc = "A loaded repair belt with hand tools, a multitool and cable. Supplies the tools and wiring needed to assemble a replacement autolathe and link a research bay." + desc = "A loaded repair belt with hand tools and cable." price_credits = 500 -// The large-tank welder only prints on a hacked lathe, so this is the cheap -// rung on a shelf that otherwise starts at 250 cr. -/datum/shop_sku/general/big_welder - category = "Tools & Repair" - item_path = /obj/item/weldingtool/largetank - price_credits = 300 - /datum/shop_sku/general/welding_fuel name = "welding fuel tank" desc = "A thousand units of industrial welding fuel in a tank you can drag aboard. Enough to keep a repair crew going for a long shift. Don't weld it." @@ -321,32 +300,6 @@ stock_min = 2 stock_max = 4 -/datum/shop_sku/general/light_replacer - category = "Tools & Repair" - item_path = /obj/item/lightreplacer - price_credits = 400 - stock_min = 1 - stock_max = 3 - -/datum/shop_sku/general/holofan - category = "Tools & Repair" - name = "holofan projector" - item_path = /obj/item/holosign_creator/atmos - price_credits = 600 - stock_min = 1 - stock_max = 2 - -// The expensive rung on the repair shelf, and the reason ships limp back here -// instead of to a depot: a breach closes in seconds instead of a welding shift. -/datum/shop_sku/general/rcd - name = "rapid construction device" - desc = "Lays and removes walls, floors and airlocks out of stored matter. The fast way to shut a breach while the compartment is still venting. Feed it iron, glass, or compressed matter cartridges." - category = "Tools & Repair" - item_path = /obj/item/construction/rcd - price_credits = 2400 - stock_min = 1 - stock_max = 2 - // ===== MEDICAL ===== /datum/shop_sku/general/medkit @@ -370,11 +323,6 @@ item_path = /obj/item/storage/medkit/o2 price_credits = 400 -/datum/shop_sku/general/health_analyzer - category = "Medical" - item_path = /obj/item/healthanalyzer - price_credits = 200 - /datum/shop_sku/general/epipen category = "Medical" item_path = /obj/item/reagent_containers/hypospray/medipen @@ -411,26 +359,11 @@ // ===== PROSPECTING ===== -/datum/shop_sku/general/pickaxe - category = "Prospecting" - item_path = /obj/item/pickaxe - price_credits = 200 - -/datum/shop_sku/general/mesons - category = "Prospecting" - item_path = /obj/item/clothing/glasses/meson - price_credits = 400 - /datum/shop_sku/general/ore_bag category = "Prospecting" item_path = /obj/item/storage/bag/ore price_credits = 200 -/datum/shop_sku/general/mining_scanner - category = "Prospecting" - item_path = /obj/item/t_scanner/adv_mining_scanner/lesser - price_credits = 450 - /datum/shop_sku/general/adv_mining_scanner desc = "The full-range model of the scanner on the shelf beside it: seven tiles of rock instead of four, and it re-sweeps half again as fast. Worth it on a planet where the good seams sit deep." category = "Prospecting" @@ -625,8 +558,13 @@ category = "Ship Sundries" name = "unclaimed freight" desc = "A sealed crate somebody never came back for. Barnaby hasn't looked inside, and he'd rather you opened it somewhere else." - item_path = /obj/structure/closet/crate/zone_loot/syndicate + item_path = /obj/structure/closet/crate/zone_loot/syndicate/trader price_credits = 750 + stock_min = 1 + stock_max = 1 + restock_interval = INFINITY + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/general/rotating/metalfoam category = "Ship Sundries" @@ -639,27 +577,12 @@ item_path = /obj/item/bikehorn price_credits = 80 -/datum/shop_sku/general/rotating/welding_goggles - category = "Tools & Repair" - item_path = /obj/item/clothing/glasses/welding - price_credits = 180 - /datum/shop_sku/general/rotating/guitar item_path = /obj/item/instrument/guitar price_credits = 400 // ===== RARE SHOWCASE ===== -/datum/shop_sku/general/rare/bluespace_bodybag - category = "Ship Sundries" - item_path = /obj/item/bodybag/bluespace - price_credits = 3000 - -/datum/shop_sku/general/rare/drill - category = "Prospecting" - item_path = /obj/item/pickaxe/drill - price_credits = 1800 - // ===== BARNABY'S PROSPECTOR COUNTER (buybacks) ===== /datum/shop_buyback/general/gold_ore @@ -775,3 +698,31 @@ price_credits = 300 stock_min = 3 stock_max = 6 +// ===== ARMS ===== + +/datum/shop_sku/general/hunting_knife + category = "Arms" + item_path = /obj/item/knife/hunting + price_credits = 200 + price_vouchers = 0 + stock_min = 4 + stock_max = 4 + +/datum/shop_sku/general/survival_knife + category = "Arms" + item_path = /obj/item/knife/combat/survival + price_credits = 350 + price_vouchers = 0 + stock_min = 4 + stock_max = 4 + +/datum/shop_sku/general/surplus_rifle + category = "Arms" + item_path = /obj/item/gun/ballistic/rifle/boltaction/surplus + price_credits = 900 + price_vouchers = 0 + stock_min = 2 + stock_max = 2 + restock_interval = 1 HOURS + fixed_price = TRUE + contract_reward = FALSE diff --git a/voidcrew/modules/trade/shop_catalog_general_vendors.dm b/voidcrew/modules/trade/shop_catalog_general_vendors.dm index 144476a6820..3a13706fa86 100644 --- a/voidcrew/modules/trade/shop_catalog_general_vendors.dm +++ b/voidcrew/modules/trade/shop_catalog_general_vendors.dm @@ -12,11 +12,8 @@ * and grower's supply, Pike owns tackle and the rods. Pike's stall stocks * nothing a stock ship autolathe prints for free, that ruled out the * aquarium kit and fish case. - * - Fern's hand tools ARE autolathe designs, and they're priced like it: pocket - * change, sold for the crew that wants a garden running before they've built - * a lathe or walked back to one. Her tray board is the real sale, it sits - * behind the hydroponics techweb node, so a ship with no R&D bay has no other - * way to add a tray. + * - Fern stocks seeds and supplies rather than printable hand tools. Her + * tray board is the fabrication-gated infrastructure for adding a garden. * - Fern's produce and graft buybacks pay pocket change on purpose: it's the * "sell your harvest at the waystation" fantasy, not an economy. Her graft * ledger refuses plain repeated-harvest cuttings so a tray of wheat can't be @@ -78,13 +75,6 @@ /datum/shop_sku/potting/robust_harvest, /datum/shop_sku/potting/left4zed, /datum/shop_sku/potting/overalls, - // Grower's Supply: hand tools - /datum/shop_sku/potting/cultivator, - /datum/shop_sku/potting/spade, - /datum/shop_sku/potting/hatchet, - /datum/shop_sku/potting/secateurs, - /datum/shop_sku/potting/watering_can, - /datum/shop_sku/potting/plant_analyzer, // Grower's Supply: the tray itself /datum/shop_sku/potting/tray_board, // The Apiary @@ -129,7 +119,6 @@ "The bees know the way to the pond and back. Nobody taught them. I don't ask.", "Bring me grafts with something actually in them. A cutting off a wheat stalk is just a cutting.", "Tray boards are on the shelf behind me. Two bins, a servo, a sheet of glass, and you've got a garden.", - "Take the tools while you're here. They're cheap, and I'd rather you weren't pulling weeds with your hands.", "Ash flora seeds off the burning worlds. I pay proper credits. They grow ANYWHERE. It's terrifying. I love them.", "Pike keeps saying fish fertilizer would double my yield. Pike is banned from the conservatory.", ), @@ -247,64 +236,8 @@ stock_min = 1 stock_max = 3 -// ----- Hand tools ----- -// Every one of these is a service autolathe design, so a ship with a working -// lathe can print the set for scrap. Priced accordingly: this is the rack you -// grab on the way out rather than a supply line. - -/datum/shop_sku/potting/cultivator - category = "Grower's Supply" - desc = "A hand rake for turning weeds out of a tray. Fern sells them by the bundle and still finds people pulling weeds by hand." - item_path = /obj/item/cultivator - price_credits = 30 - stock_min = 4 - stock_max = 8 - -/datum/shop_sku/potting/spade - category = "Grower's Supply" - desc = "For digging a plant out of a tray without killing it, and for repotting whatever you dug up." - item_path = /obj/item/shovel/spade - price_credits = 30 - stock_min = 4 - stock_max = 8 - -/datum/shop_sku/potting/hatchet - category = "Grower's Supply" - desc = "Chops down a tower cap, splits logs, and harvests anything too woody for bare hands. Fern would like it noted that it is a gardening tool." - item_path = /obj/item/hatchet - price_credits = 50 - stock_min = 3 - stock_max = 6 - -/datum/shop_sku/potting/secateurs - category = "Grower's Supply" - desc = "Pruning shears sharp enough to take a clean graft off a stem. The cutting keeps whatever trait the parent was carrying." - item_path = /obj/item/secateurs - price_credits = 50 - stock_min = 3 - stock_max = 6 - -/datum/shop_sku/potting/watering_can - category = "Grower's Supply" - desc = "Holds enough water for a row of trays. Fill it at any sink, or at Pike's pond if you want to hear his opinion about it." - item_path = /obj/item/reagent_containers/cup/watering_can - price_credits = 40 - stock_min = 3 - stock_max = 6 - -/datum/shop_sku/potting/plant_analyzer - category = "Grower's Supply" - desc = "Reads a plant's stats and traits, and a tray's water, nutrients and pest level. Growing without one works, but you're guessing." - item_path = /obj/item/plant_analyzer - price_credits = 60 - stock_min = 3 - stock_max = 6 - // ----- The tray itself ----- -// Unlike the hand tools this one is genuinely gated: the design sits behind the -// hydroponics techweb node, so it's the only tray a ship without an R&D bay can -// get hold of. Priced so two boards plus the tools still cost more loose than -// the botany starter pack in shop_catalog_job_packs.dm. +// Infrastructure for crews adding a garden without an existing research bay. /datum/shop_sku/potting/tray_board category = "Grower's Supply" @@ -486,9 +419,6 @@ /datum/shop_sku/bait/rotating/carp_plushie, /datum/shop_sku/bait/rotating/stocked_aquarium, ) - rare_pool = list( - /datum/shop_sku/bait/rare/tech_rod, - ) buyback_types = list( /datum/shop_buyback/bait/pike, /datum/shop_buyback/bait/donkfish, @@ -647,15 +577,6 @@ item_path = /obj/structure/aquarium/prefilled price_credits = 600 -// ===== RARE SHOWCASE ===== - -/datum/shop_sku/bait/rare/tech_rod - category = "Rods & Reels" - desc = "A self-reeling smart rod. Pike calls it cheating and stocks it anyway, because cheating sells." - item_path = /obj/item/fishing_rod/tech - price_vouchers = 1 - price_credits = 600 - // ===== PIKE'S TROPHY LEDGER (buybacks) ===== // The weird stuff only. Barnaby handles the by-the-fin chowder trade. diff --git a/voidcrew/modules/trade/shop_catalog_outfitter.dm b/voidcrew/modules/trade/shop_catalog_outfitter.dm index d0b546e0860..fc838e8be58 100644 --- a/voidcrew/modules/trade/shop_catalog_outfitter.dm +++ b/voidcrew/modules/trade/shop_catalog_outfitter.dm @@ -36,6 +36,7 @@ categories = list( "Armor", "Firearms & Ammo", + "Melee", "Ship Systems", "Ship Ordnance", "Security Gear", @@ -59,14 +60,19 @@ /datum/shop_sku/outfitter/disabler, /datum/shop_sku/outfitter/energy_gun, /datum/shop_sku/outfitter/laser_gun, - /datum/shop_sku/outfitter/double_barrel, /datum/shop_sku/outfitter/rubbershot, /datum/shop_sku/outfitter/lethalshot, - /datum/shop_sku/outfitter/boltaction, /datum/shop_sku/outfitter/rifle_clip, /datum/shop_sku/outfitter/smg_mag, /datum/shop_sku/outfitter/wt550_mag, /datum/shop_sku/outfitter/firing_pin, + /datum/shop_sku/outfitter/riot_shotgun, + // Melee + /datum/shop_sku/outfitter/combat_knife, + /datum/shop_sku/outfitter/shortsword, + /datum/shop_sku/outfitter/ablative_bat, + /datum/shop_sku/outfitter/fireaxe, + /datum/shop_sku/outfitter/sabre, // Ship Systems /datum/shop_sku/outfitter/engine_plasma, /datum/shop_sku/outfitter/engine_expulsion, @@ -79,8 +85,6 @@ /datum/shop_sku/outfitter/warhead_standard, /datum/shop_sku/outfitter/missile_light, // Security Gear - /datum/shop_sku/outfitter/seclite, - /datum/shop_sku/outfitter/flash, /datum/shop_sku/outfitter/security_belt, /datum/shop_sku/outfitter/pepper_spray, /datum/shop_sku/outfitter/riot_shield, @@ -97,8 +101,6 @@ /datum/shop_sku/outfitter/hot_sauce, // Utility /datum/shop_sku/outfitter/gas_mask, - /datum/shop_sku/outfitter/jaws, - /datum/shop_sku/outfitter/magboots, // Hull Stock /datum/shop_sku/outfitter/plasteel_stock, /datum/shop_sku/outfitter/iron_stock, @@ -143,8 +145,6 @@ ) rare_pool = list( /datum/shop_sku/outfitter/rare/ablative_vest, - /datum/shop_sku/outfitter/rare/compact_defib, - /datum/shop_sku/outfitter/rare/ion_rifle, /datum/shop_sku/outfitter/rare/missile_heavy, ) // The back room: Trusted-standing uniques, per-crew supply (trader_favor.dm) @@ -249,28 +249,30 @@ price_credits = 400 stock_min = 1 stock_max = 3 + restock_interval = 1 HOURS + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/outfitter/energy_gun category = "Firearms & Ammo" item_path = /obj/item/gun/energy/e_gun price_vouchers = 0 - price_credits = 1500 + price_credits = 2400 stock_min = 1 - stock_max = 2 + stock_max = 1 + restock_interval = 1 HOURS + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/outfitter/laser_gun category = "Firearms & Ammo" item_path = /obj/item/gun/energy/laser - price_credits = 600 - stock_min = 1 - stock_max = 2 - -/datum/shop_sku/outfitter/double_barrel - category = "Firearms & Ammo" - item_path = /obj/item/gun/ballistic/shotgun/doublebarrel - price_credits = 900 + price_credits = 1500 stock_min = 1 - stock_max = 2 + stock_max = 1 + restock_interval = 1 HOURS + fixed_price = TRUE + contract_reward = FALSE /datum/shop_sku/outfitter/rubbershot category = "Firearms & Ammo" @@ -286,13 +288,6 @@ stock_min = 10 stock_max = 20 -/datum/shop_sku/outfitter/boltaction - category = "Firearms & Ammo" - item_path = /obj/item/gun/ballistic/rifle/boltaction - price_credits = 900 - stock_min = 1 - stock_max = 2 - /datum/shop_sku/outfitter/rifle_clip category = "Firearms & Ammo" item_path = /obj/item/ammo_box/strilka310 @@ -416,16 +411,6 @@ // ===== SECURITY GEAR ===== -/datum/shop_sku/outfitter/seclite - category = "Security Gear" - item_path = /obj/item/flashlight/seclite - price_credits = 450 - -/datum/shop_sku/outfitter/flash - category = "Security Gear" - item_path = /obj/item/assembly/flash/handheld - price_credits = 750 - /datum/shop_sku/outfitter/security_belt category = "Security Gear" item_path = /obj/item/storage/belt/security/full @@ -528,22 +513,6 @@ item_path = /obj/item/clothing/mask/gas price_credits = 200 -/datum/shop_sku/outfitter/jaws - category = "Utility" - name = "jaws of life" - item_path = /obj/item/crowbar/power - price_vouchers = 1 - price_credits = 750 - stock_min = 1 - stock_max = 2 - -/datum/shop_sku/outfitter/magboots - category = "Utility" - item_path = /obj/item/clothing/shoes/magboots - price_credits = 1200 - stock_min = 1 - stock_max = 2 - // ===== HULL STOCK ===== // Bulk repair material for crews who can't mine or can't wait. Sold by the // stack, priced above what an ore redemption run costs you in time. @@ -664,12 +633,6 @@ item_path = /obj/item/defibrillator/compact price_credits = 2400 -/datum/shop_sku/outfitter/rare/ion_rifle - category = "Firearms & Ammo" - item_path = /obj/item/gun/energy/ionrifle - price_vouchers = 2 - price_credits = 3000 - /datum/shop_sku/outfitter/rare/missile_heavy category = "Ship Ordnance" name = "heavy missile (armed)" @@ -758,3 +721,55 @@ item_path = /obj/item/tank/jetpack/oxygen/harness/prototype price_credits = 3800 price_vouchers = 2 +/datum/shop_sku/outfitter/riot_shotgun + category = "Firearms & Ammo" + item_path = /obj/item/gun/ballistic/shotgun/riot + price_credits = 1800 + price_vouchers = 0 + stock_min = 1 + stock_max = 1 + restock_interval = 1 HOURS + fixed_price = TRUE + contract_reward = FALSE + +// ===== MELEE ===== + +/datum/shop_sku/outfitter/combat_knife + category = "Melee" + item_path = /obj/item/knife/combat + price_credits = 900 + price_vouchers = 0 + stock_min = 3 + stock_max = 3 + +/datum/shop_sku/outfitter/shortsword + category = "Melee" + item_path = /obj/item/claymore/shortsword + price_credits = 1200 + price_vouchers = 0 + stock_min = 2 + stock_max = 2 + +/datum/shop_sku/outfitter/ablative_bat + category = "Melee" + item_path = /obj/item/melee/baseball_bat/ablative + price_credits = 1000 + price_vouchers = 0 + stock_min = 2 + stock_max = 2 + +/datum/shop_sku/outfitter/fireaxe + category = "Melee" + item_path = /obj/item/fireaxe + price_credits = 1500 + price_vouchers = 0 + stock_min = 2 + stock_max = 2 + +/datum/shop_sku/outfitter/sabre + category = "Melee" + item_path = /obj/item/melee/sabre + price_credits = 1800 + price_vouchers = 0 + stock_min = 1 + stock_max = 1 diff --git a/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm b/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm index 086f4f82f87..dd2f51bd14a 100644 --- a/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm +++ b/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm @@ -298,3 +298,281 @@ TEST_ASSERT(mission.turn_in(run_loc_floor_bottom_left, full_stack), "A full eligible stack must be accepted") TEST_ASSERT_EQUAL(full_stack.amount, 2, "Only the configured stack quantity must be consumed") TEST_ASSERT(QDELETED(mission), "A full stack must finish the request") + +/// The authored ladder is shared stock, with exactly one SKU for each listed weapon. +/datum/unit_test/voidcrew_ladder_catalog/Run() + var/list/catalogs = list( + /datum/outpost_shop/general = list( + list(/datum/shop_sku/general/hunting_knife, /obj/item/knife/hunting, 4, 200, 0), + list(/datum/shop_sku/general/survival_knife, /obj/item/knife/combat/survival, 4, 350, 0), + list(/datum/shop_sku/general/surplus_rifle, /obj/item/gun/ballistic/rifle/boltaction/surplus, 2, 900, 0), + ), + /datum/outpost_shop/outfitter = list( + list(/datum/shop_sku/outfitter/combat_knife, /obj/item/knife/combat, 3, 900, 0), + list(/datum/shop_sku/outfitter/shortsword, /obj/item/claymore/shortsword, 2, 1200, 0), + list(/datum/shop_sku/outfitter/ablative_bat, /obj/item/melee/baseball_bat/ablative, 2, 1000, 0), + list(/datum/shop_sku/outfitter/fireaxe, /obj/item/fireaxe, 2, 1500, 0), + list(/datum/shop_sku/outfitter/sabre, /obj/item/melee/sabre, 1, 1800, 0), + list(/datum/shop_sku/outfitter/laser_gun, /obj/item/gun/energy/laser, 1, 1500, 0), + list(/datum/shop_sku/outfitter/riot_shotgun, /obj/item/gun/ballistic/shotgun/riot, 1, 1800, 0), + list(/datum/shop_sku/outfitter/energy_gun, /obj/item/gun/energy/e_gun, 1, 2400, 0), + ), + /datum/outpost_shop/black_market = list( + list(/datum/shop_sku/black_market/boarding_axe, /obj/item/fireaxe/boardingaxe, 1, 2400, 0), + list(/datum/shop_sku/black_market/cutlass, /obj/item/claymore/cutlass, 1, 3000, 3), + list(/datum/shop_sku/black_market/rare/energy_sword, /obj/item/melee/energy/sword/saber, 1, 4000, 4), + list(/datum/shop_sku/black_market/c20r, /obj/item/gun/ballistic/automatic/c20r/unrestricted, 1, 3600, 2), + list(/datum/shop_sku/black_market/wt550, /obj/item/gun/ballistic/automatic/wt550, 1, 4200, 2), + list(/datum/shop_sku/black_market/rotating/mateba, /obj/item/gun/ballistic/revolver/mateba, 1, 3000, 1), + ), + /datum/outpost_shop/vendor/ripperdoc = list( + list(/datum/shop_sku/ripperdoc/monowire, /obj/item/organ/cyberimp/arm/toolkit/cyberware/monowire, 1, 0, 3), + list(/datum/shop_sku/ripperdoc/mantis, /obj/item/cyberware_pair_case/mantis_blades, 1, 0, 4), + list(/datum/shop_sku/ripperdoc/gorilla, /obj/item/cyberware_pair_case/gorilla_arms, 1, 0, 3), + ), + ) + for(var/shop_type in catalogs) + var/datum/outpost_shop/shop = allocate(shop_type) + var/list/every_sku = shop.sku_types + shop.rotating_pool + shop.rare_pool + shop.favor_sku_types + for(var/list/row as anything in catalogs[shop_type]) + TEST_ASSERT(row[1] in every_sku, "[shop_type] lost [row[1]]") + var/datum/shop_sku/sku = allocate(row[1]) + TEST_ASSERT_EQUAL(sku.item_path, row[2], "[sku.type] dispenses the wrong weapon") + TEST_ASSERT_EQUAL(sku.stock_min, row[3], "[sku.type] has random lower stock") + TEST_ASSERT_EQUAL(sku.stock_max, row[3], "[sku.type] has the wrong stock cap") + TEST_ASSERT_EQUAL(sku.stock, row[3], "[sku.type] starts with the wrong stock") + TEST_ASSERT_EQUAL(sku.price_credits, row[4], "[sku.type] has the wrong credit price") + TEST_ASSERT_EQUAL(sku.price_vouchers, row[5], "[sku.type] has the wrong voucher price") + var/copies = 0 + for(var/datum/shop_sku/other as anything in every_sku) + if(initial(other.item_path) == sku.item_path) + copies++ + TEST_ASSERT_EQUAL(copies, 1, "[shop_type] has duplicate [sku.item_path] shelves") + if(ispath(sku.item_path, /obj/item/gun)) + TEST_ASSERT(row[1] in shop.sku_types, "A gun must stay on its core shelf") + TEST_ASSERT_EQUAL(sku.restock_interval, 1 HOURS, "Gun replenishment must be hourly") + TEST_ASSERT_EQUAL(timeleft(sku.restock_timer), 1 HOURS, "The hourly delivery is not scheduled") + else if(row[5]) + TEST_ASSERT_EQUAL(sku.restock_interval, INFINITY, "Red melee/chrome must remain finite") + TEST_ASSERT_NULL(sku.restock_timer, "Finite melee acquired a refill timer") + if(ispath(sku.item_path, /obj/item/gun) || row[5]) + TEST_ASSERT(sku.fixed_price, "A restricted weapon can be discounted") + TEST_ASSERT(!sku.contract_reward, "A restricted weapon can pay a contract") + +/// Check removed sources across all owned shelf families, including undealt stock. +/datum/unit_test/voidcrew_ladder_removed_shelves/Run() + var/list/allowed_guns = list( + /obj/item/gun/ballistic/rifle/boltaction/surplus, + /obj/item/gun/energy/disabler, + /obj/item/gun/energy/laser, + /obj/item/gun/energy/e_gun, + /obj/item/gun/ballistic/shotgun/riot, + /obj/item/gun/ballistic/automatic/c20r/unrestricted, + /obj/item/gun/ballistic/automatic/wt550, + /obj/item/gun/ballistic/revolver/mateba, + ) + var/list/printed_gear = list( + /obj/item/gps, /obj/item/storage/belt/utility/full, /obj/item/weldingtool/largetank, + /obj/item/lightreplacer, /obj/item/holosign_creator/atmos, /obj/item/construction/rcd/loaded, + /obj/item/healthanalyzer, /obj/item/pickaxe, /obj/item/pickaxe/drill, /obj/item/clothing/glasses/meson, + /obj/item/t_scanner/adv_mining_scanner/lesser, /obj/item/bodybag/bluespace, /obj/item/clothing/glasses/welding, + /obj/item/flashlight/seclite, /obj/item/assembly/flash/handheld, /obj/item/clothing/shoes/magboots, + /obj/item/crowbar/power, /obj/item/defibrillator/compact, /obj/item/suppressor, /obj/item/mod/module/active_sonar, + /obj/item/cultivator, /obj/item/shovel/spade, /obj/item/hatchet, /obj/item/secateurs, + /obj/item/reagent_containers/cup/watering_can, /obj/item/plant_analyzer, /obj/item/fishing_rod/tech, + ) + for(var/shop_type in list(/datum/outpost_shop/general, /datum/outpost_shop/outfitter, /datum/outpost_shop/black_market, /datum/outpost_shop/vendor/potting_shed, /datum/outpost_shop/vendor/bait_shop, /datum/outpost_shop/vendor/ripperdoc)) + var/datum/outpost_shop/shop = allocate(shop_type) + for(var/datum/shop_sku/sku_type as anything in shop.sku_types + shop.rotating_pool + shop.rare_pool + shop.favor_sku_types) + var/item_path = initial(sku_type.item_path) + TEST_ASSERT(!(item_path in printed_gear), "[shop_type] still sells printable gear [item_path]") + if(ispath(item_path, /obj/item/gun)) + TEST_ASSERT(item_path in allowed_guns, "[shop_type] bypasses the ladder with [item_path]") + TEST_ASSERT(item_path != /obj/item/organ/cyberimp/arm/toolkit/cyberware/ronin && item_path != /obj/item/organ/cyberimp/arm/toolkit/cyberware/bunker_buster, "Splice still sells a gun arm") + +/// Convoys and rotations cannot accelerate deliveries or revive finite stock. +/datum/unit_test/voidcrew_ladder_restock/Run() + var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) + shop.add_sku(/datum/shop_sku/general/surplus_rifle, "core") + var/datum/shop_sku/gun = shop.skus[1] + gun.stock = 0 + var/timer_id = gun.restock_timer + for(var/convoy in 1 to 6) + shop.convoy_restock() + TEST_ASSERT_EQUAL(gun.stock, 0, "A convoy bypassed the hourly refill") + TEST_ASSERT_EQUAL(gun.restock_timer, timer_id, "Convoys reset the gun clock") + gun.restock_unit() + TEST_ASSERT_EQUAL(gun.stock, 1, "One delivery must return one gun") + gun.restock_unit() + gun.restock_unit() + TEST_ASSERT_EQUAL(gun.stock, 2, "Hourly stock exceeded its cap") + gun.stock = 0 + gun.reserved_stock = 1 + gun.restock_unit() + gun.restock_unit() + TEST_ASSERT_EQUAL(gun.stock, 1, "Restocking duplicated reserved stock") + qdel(shop) + TEST_ASSERT_NULL(timeleft(timer_id), "Deleting the shop left a gun delivery alive") + + for(var/sku_type in list(/datum/shop_sku/outfitter/lethalshot, /datum/shop_sku/outfitter/smg_mag, /datum/shop_sku/ripperdoc/ronin_mag)) + var/datum/outpost_shop/ammo_shop = allocate(/datum/outpost_shop) + ammo_shop.add_sku(sku_type, "core") + var/datum/shop_sku/ammo = ammo_shop.skus[1] + ammo.stock = 0 + ammo_shop.convoy_restock() + TEST_ASSERT(ammo.stock > 0, "Ammunition lost ordinary convoy refills") + TEST_ASSERT_NULL(ammo.restock_timer, "Ammunition acquired a gun clock") + + for(var/sku_type in list(/datum/shop_sku/general/rotating/freight_crate, /datum/shop_sku/black_market/rare/energy_sword, /datum/shop_sku/general/surplus_rifle)) + for(var/weighted in list(FALSE, TRUE)) + var/datum/outpost_shop/rotating = allocate(/datum/outpost_shop) + rotating.rotating_pool = list(sku_type, /datum/shop_sku/general/soap) + if(weighted) + var/datum/shop_rotation/rotation = new + rotation.pool = list() + rotation.pool[sku_type] = 1 + rotation.pool[/datum/shop_sku/general/soap] = 1 + rotating.live_rotations += rotation + rotating.add_rotation_sku(rotation, sku_type) + else + rotating.add_sku(sku_type, "rotating") + var/datum/shop_sku/finite = rotating.skus[1] + finite.stock = 0 + for(var/convoy in 1 to 8) + rotating.convoy_restock() + TEST_ASSERT_EQUAL(length(rotating.skus), 1, "A rotation duplicated restricted stock") + TEST_ASSERT_EQUAL(rotating.skus[1], finite, "A rotation replaced the exhausted SKU and its clock") + TEST_ASSERT_EQUAL(finite.stock, 0, "A rotation refilled restricted stock") + + for(var/sku_type in list(/datum/shop_sku/general/hunting_knife, /datum/shop_sku/outfitter/fireaxe, /datum/shop_sku/black_market/boarding_axe)) + var/datum/outpost_shop/melee_shop = allocate(/datum/outpost_shop) + melee_shop.add_sku(sku_type, "core") + var/datum/shop_sku/melee = melee_shop.skus[1] + melee.stock = 0 + melee_shop.convoy_restock() + TEST_ASSERT(melee.stock > 0, "Green/yellow melee stopped replenishing") + +/// Actual favor and authored specials cannot discount restricted weapons. +/datum/unit_test/voidcrew_ladder_prices_and_contracts/Run() + var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human/consistent, run_loc_floor_bottom_left) + user.mind_initialize() + allocated += user.mind + var/obj/structure/overmap/ship/ship = allocate(/obj/structure/overmap/ship) + var/datum/team/voidcrew/team = allocate(/datum/team/voidcrew) + team.ship = ship + user.mind.ship_teams = list(team) + var/datum/outpost_shop/shop = allocate(/datum/outpost_shop) + ship.trader_favor = list() + ship.trader_favor[shop.favor_key()] = 6 // FAVOR_TIER_TRUSTED + TEST_ASSERT_EQUAL(shop.get_discount_pct(ship), 15, "Favor fixture did not reach the maximum discount") + var/list/restricted = list( + /datum/shop_sku/general/surplus_rifle, /datum/shop_sku/outfitter/disabler, + /datum/shop_sku/outfitter/laser_gun, /datum/shop_sku/outfitter/energy_gun, /datum/shop_sku/outfitter/riot_shotgun, + /datum/shop_sku/black_market/c20r, /datum/shop_sku/black_market/wt550, /datum/shop_sku/black_market/rotating/mateba, + /datum/shop_sku/black_market/cutlass, /datum/shop_sku/black_market/rare/energy_sword, + /datum/shop_sku/ripperdoc/monowire, /datum/shop_sku/ripperdoc/gorilla, /datum/shop_sku/ripperdoc/mantis, + /datum/shop_sku/general/rotating/freight_crate, /datum/shop_sku/black_market/mystery_cache, /datum/shop_sku/black_market/mystery_cache_rare, + ) + for(var/sku_type in restricted) + shop.add_sku(sku_type, "core") // Test the flag even if a shelf changes later. + var/datum/shop_sku/sku = shop.skus[length(shop.skus)] + shop.roll_special() + TEST_ASSERT_EQUAL(sku.discount_pct, 0, "A restricted weapon went on special") + sku.discount_pct = 30 + TEST_ASSERT_EQUAL(sku.get_credit_price(user), sku.price_credits, "A special/favor combination changed a fixed price") + for(var/attempt in 1 to 20) + var/datum/mission/mission = allocate(/datum/mission) + mission.difficulty = 3 // MISSION_DIFFICULTY_HARD + mission.contract_pay_mult = 100 // Every shelf price fits, so price cannot hide a leak. + TEST_ASSERT(shop.roll_contract_reward(mission), "Restricted-only shelves could not quote currency") + TEST_ASSERT_EQUAL(length(mission.get_reward_types()), 0, "A contract paid a gun, red melee/chrome or bought cache") + TEST_ASSERT_EQUAL(length(mission.contract_stock), 0, "A contract reserved restricted stock") + var/datum/bank_account/account = allocate(/datum/bank_account, "Ladder counter test", null, 1, FALSE) + account.account_balance = 2700 + var/obj/item/card/id/advanced/card = allocate(/obj/item/card/id/advanced) + qdel(card.registered_account) + card.registered_account = account + TEST_ASSERT(user.put_in_hands(card), "First buyer could not carry their ID") + var/mob/living/carbon/human/other_buyer = allocate(/mob/living/carbon/human/consistent, run_loc_floor_top_right) + var/obj/item/card/id/advanced/other_card = allocate(/obj/item/card/id/advanced) + qdel(other_card.registered_account) + other_card.registered_account = account + TEST_ASSERT(other_buyer.put_in_hands(other_card), "Second buyer could not carry their ID") + var/datum/shop_sku/rifle = shop.skus[1] + TEST_ASSERT(rifle.try_purchase(user, null), "The first shared-stock purchase failed") + TEST_ASSERT(rifle.try_purchase(other_buyer, null), "A second buyer could not buy the remaining rifle") + TEST_ASSERT_EQUAL(rifle.stock, 0, "Two buyers did not exhaust the same stock") + TEST_ASSERT_EQUAL(account.account_balance, 900, "Actual purchases bypassed the fixed price") + TEST_ASSERT(!rifle.try_purchase(other_buyer, null), "An exhausted SKU sold another gun") + TEST_ASSERT_EQUAL(account.account_balance, 900, "A refused purchase took money") + rifle.restock_unit() + TEST_ASSERT(rifle.try_purchase(other_buyer, null), "An hourly delivery could not be purchased") + TEST_ASSERT_EQUAL(account.account_balance, 0, "The returned rifle sold at a discount") + user.mind.ship_teams = list() + team.ship = null + +/// Bought and premium crates have exact freight odds and no extra weapon draws. +/datum/unit_test/voidcrew_ladder_bought_caches/Run() + var/list/gun_pools = list( + list(/obj/item/gun/ballistic/rifle/boltaction/surplus, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver/c38/detective, /obj/item/gun/ballistic/shotgun/doublebarrel), + list(/obj/item/gun/ballistic/shotgun/riot, /obj/item/gun/ballistic/automatic/tommygun, /obj/item/gun/ballistic/automatic/mini_uzi), + ) + var/list/gun_weights = list(list(940, 59, 1), list(45, 54, 1), list(15, 35, 50)) + var/list/melee_weights = list(list(900, 99, 1), list(35, 64, 1), list(10, 45, 45)) + var/list/chances = list(8, 19, 33) + var/list/classes = list("green", "yellow", "red") + var/list/caches = list( + list(/datum/shop_sku/general/rotating/freight_crate, 750, 0), + list(/datum/shop_sku/black_market/mystery_cache, 0, 2), + list(/datum/shop_sku/black_market/mystery_cache_rare, 0, 4), + ) + for(var/list/row as anything in caches) + var/datum/shop_sku/sku = allocate(row[1]) + TEST_ASSERT_EQUAL(sku.stock, 1, "Bought caches must have exactly one unit") + TEST_ASSERT_EQUAL(sku.price_credits, row[2], "Bought cache has the wrong credit price") + TEST_ASSERT_EQUAL(sku.price_vouchers, row[3], "Bought cache has the wrong voucher price") + TEST_ASSERT_EQUAL(sku.restock_interval, INFINITY, "Bought caches can refill") + for(var/zone in 1 to 3) // ZONE_GREEN/YELLOW/RED compile later. + var/obj/structure/closet/crate/zone_loot/syndicate/trader/cache = allocate(sku.item_path, run_loc_floor_bottom_left) + cache.on_zone_resolved(zone) + cache.forceMove(run_loc_floor_top_right) + TEST_ASSERT_EQUAL(cache.loot_zone, zone, "Moving bought cargo changed its origin zone") + TEST_ASSERT_EQUAL(cache.get_gun_chance(), chances[zone], "Bought cache has the wrong gun probability") + var/list/weapon_paths = list() + for(var/class_index in 1 to 3) + var/list/gun_class_weights = cache.get_weapon_class_weights(TRUE) + var/list/melee_class_weights = cache.get_weapon_class_weights(FALSE) + TEST_ASSERT_EQUAL(gun_class_weights[classes[class_index]], gun_weights[zone][class_index], "Bought cache has wrong gun class weights") + TEST_ASSERT_EQUAL(melee_class_weights[classes[class_index]], melee_weights[zone][class_index], "Bought cache has wrong melee class weights") + var/list/guns = cache.get_weapon_pool(TRUE, classes[class_index]) + TEST_ASSERT(compare_list(guns, gun_pools[min(2, class_index)]), "Freight gun class changed or gained advanced weapons") + weapon_paths |= guns + weapon_paths |= cache.get_weapon_pool(FALSE, classes[class_index]) + var/datum/loot_theme/theme = GLOB.loot_themes[cache.theme] + var/list/original_pools = list(theme.loot_common.Copy(), theme.loot_uncommon.Copy(), theme.loot_prime.Copy(), theme.loot_uniques.Copy()) + var/list/pools = cache.get_supply_pools() + for(var/tier in pools) + var/list/pool = pools[tier] + TEST_ASSERT(length(pool), "Filtering bought cargo emptied a supply tier") + for(var/item_path in pool) + TEST_ASSERT(!(item_path in weapon_paths) && !ispath(item_path, /obj/item/gun) && !ispath(item_path, /obj/item/knife), "Supplies can pay an extra weapon") + TEST_ASSERT(!ispath(item_path, /obj/item/organ/cyberimp), "Bought cargo can pay chrome") + pool.Cut() // A caller may consume every working pool safely. + var/weapon_count = 0 + cache.PopulateContents() + for(var/obj/item/item in cache.contents) + if(item.type in weapon_paths) + weapon_count++ + TEST_ASSERT_EQUAL(weapon_count, 1, "Bought/premium cache did not pay exactly one weapon") + var/contents_count = length(cache.contents) + var/spare_count = 0 + for(var/obj/item/gun/gun in cache.contents) + if(GLOB.loot_gun_spare_ammo[gun.type]) + spare_count++ + var/ammo_path = GLOB.loot_gun_spare_ammo[gun.type] + TEST_ASSERT(locate(ammo_path) in cache, "A freight gun arrived without its spare reload") + TEST_ASSERT(contents_count - spare_count >= 2 + (zone == 3 ? 2 : zone == 2 ? 1 : 0) + cache.bonus_draws, "Premium crate lost ordinary draws") + TEST_ASSERT(contents_count - spare_count <= 3 + (zone == 3 ? 2 : zone == 2 ? 1 : 0) + cache.bonus_draws, "Premium crate added unbudgeted draws") + cache.PopulateContents() + TEST_ASSERT_EQUAL(length(cache.contents), contents_count, "Reopening bought cargo paid twice") + TEST_ASSERT(deep_compare_list(list(theme.loot_common, theme.loot_uncommon, theme.loot_prime, theme.loot_uniques), original_pools), "Bought cargo mutated the shared theme") From 59cb3b67534ff8db759d95d82cbe0d58beeb9a7d Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:51:58 -0700 Subject: [PATCH 041/105] Reduce pirate bounty pay --- .../modules/npc_ships/code/bounty/bounty.dm | 6 +-- .../modules/unit_tests/voidcrew_missions.dm | 53 +++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/voidcrew/modules/npc_ships/code/bounty/bounty.dm b/voidcrew/modules/npc_ships/code/bounty/bounty.dm index 45fb8b86cf4..d85ce308e14 100644 --- a/voidcrew/modules/npc_ships/code/bounty/bounty.dm +++ b/voidcrew/modules/npc_ships/code/bounty/bounty.dm @@ -114,7 +114,7 @@ * Note: Ships are confined to their spawn zone (BB_NPC_SPAWN_ZONE), * so the zone at spawn time is the zone for the ship's lifetime. */ -/datum/pirate_bounty/proc/calculate_reward(obj/structure/overmap/ship/npc/ship) +/datum/pirate_bounty/proc/calculate_reward(obj/structure/overmap/ship/npc/ship, reward_roll = rand(80, 120)) // Base reward - yellow zone pirates var/base_reward = 5000 @@ -125,8 +125,8 @@ base_reward = 15000 is_heavy_bounty = TRUE - // Add some variance (80-120%) - return round(base_reward * rand(80, 120) / 100) + // Reduce pirate bounty cash to 80%, retaining the usual 80-120% variance. + return round(base_reward * 0.8 * reward_roll / 100) /** * Checks if the bounty is still valid (target exists and not resolved). diff --git a/voidcrew/modules/unit_tests/voidcrew_missions.dm b/voidcrew/modules/unit_tests/voidcrew_missions.dm index a9e4e806a84..375b243eab2 100644 --- a/voidcrew/modules/unit_tests/voidcrew_missions.dm +++ b/voidcrew/modules/unit_tests/voidcrew_missions.dm @@ -58,6 +58,59 @@ /datum/unit_test/voidcrew_mission_wiring +/// Pirate quotes retain their variance, loot tier and tracking deduction after the cash cut. +/datum/unit_test/voidcrew_pirate_bounty_pay + var/turf/open/overmap/overmap_tile + var/original_turf_type + var/metrics_were_accepting + +/datum/unit_test/voidcrew_pirate_bounty_pay/New() + . = ..() + metrics_were_accepting = SSmetrics.accepting + SSmetrics.accepting = FALSE + +/datum/unit_test/voidcrew_pirate_bounty_pay/Destroy() + if(overmap_tile) + overmap_tile.current_zone = null + overmap_tile.ChangeTurf(original_turf_type) + SSmetrics.accepting = metrics_were_accepting + return ..() + +/datum/unit_test/voidcrew_pirate_bounty_pay/Run() + original_turf_type = run_loc_floor_bottom_left.type + overmap_tile = run_loc_floor_bottom_left.ChangeTurf(/turf/open/overmap) + var/obj/structure/overmap/ship/winner = allocate(/obj/structure/overmap/ship) + winner.ship_account = allocate(/datum/bank_account) + // Zone (ZONE_YELLOW/RED), low/base/high quote, tracking fee, tracked payout. + var/list/cases = list(list(2, 3200, 4000, 4800, 1000, 3000), list(3, 9600, 12000, 14400, 3000, 9000)) + var/list/reward_rolls = list(80, 100, 120) + for(var/list/pay_case as anything in cases) + overmap_tile.current_zone = allocate(/datum/overmap_zone, pay_case[1]) + var/obj/structure/overmap/ship/npc/pirate = allocate(/obj/structure/overmap/ship/npc, overmap_tile) + // Teardown must not refill the live pirate pool. + pirate.spawner_resolved = TRUE + var/obj/item/ship_key/key = allocate(/obj/item/ship_key, run_loc_floor_top_right, pirate) + key.spawner_notified = TRUE + for(var/tracking in list(FALSE, TRUE)) + var/datum/pirate_bounty/bounty = allocate(/datum/pirate_bounty, pirate, key) + TEST_ASSERT(bounty.reward >= pay_case[2] && bounty.reward <= pay_case[4], "Generated pirate quote is outside the reduced band") + TEST_ASSERT_EQUAL(bounty.is_heavy_bounty, pay_case[1] == 3, "The cash cut changed the pirate loot tier") + for(var/index in 1 to length(reward_rolls)) + TEST_ASSERT_EQUAL(bounty.calculate_reward(pirate, reward_rolls[index]), pay_case[index + 1], "Wrong pirate bounty quote at [reward_rolls[index]]%") + bounty.reward = bounty.calculate_reward(pirate, 100) + TEST_ASSERT_EQUAL(bounty.get_tracking_cost(), pay_case[5], "Tracking cost did not follow the reduced quote") + TEST_ASSERT(bounty.add_claimant(winner), "Could not accept the pirate bounty") + TEST_ASSERT(bounty.can_turn_in(key, winner), "The matching pirate key was refused") + if(tracking) + TEST_ASSERT(bounty.enable_tracking(winner), "Could not enable pirate tracking") + var/expected_pay = tracking ? pay_case[6] : pay_case[3] + var/balance_before = winner.ship_account.account_balance + TEST_ASSERT_EQUAL(bounty.complete(winner, null), expected_pay, "Pirate completion returned the wrong payment") + TEST_ASSERT_EQUAL(winner.ship_account.account_balance - balance_before, expected_pay, "Pirate completion credited the wrong payment") + TEST_ASSERT(!bounty.can_turn_in(key, winner), "A completed pirate bounty accepted its key again") + TEST_ASSERT_EQUAL(bounty.complete(winner, null), 0, "A completed pirate bounty paid twice") + TEST_ASSERT_EQUAL(winner.ship_account.account_balance - balance_before, expected_pay, "Duplicate completion changed the ship balance") + /// Steal-objective guns exist at spawn; opening any gun cache yields one gun total. /datum/unit_test/voidcrew_pirate_reward_guns/Run() var/list/cache_guns = list( From db61f9af768fa93361279a6b89d8dc15d7cc873c Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:49:17 -0700 Subject: [PATCH 042/105] Mission reward screens and wiki --- .../voidcrew_tgui/interfaces/MissionBoard.tsx | 83 +++++--------- .../interfaces/OutpostMissionBoard.tsx | 101 +++++++---------- .../voidcrew_tgui/interfaces/TraderShop.tsx | 97 ++++------------ wiki/content/missions.md | 106 +++++++++--------- 4 files changed, 145 insertions(+), 242 deletions(-) diff --git a/tgui/packages/voidcrew_tgui/interfaces/MissionBoard.tsx b/tgui/packages/voidcrew_tgui/interfaces/MissionBoard.tsx index 8cfcac16912..a046ca2574e 100644 --- a/tgui/packages/voidcrew_tgui/interfaces/MissionBoard.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/MissionBoard.tsx @@ -9,7 +9,6 @@ import { LabeledList, NoticeBox, NumberInput, - ProgressBar, Section, Stack, Tabs, @@ -34,10 +33,7 @@ type Mission = { author: string; value: number; reward_items?: RewardItem[]; - reward_item: string | null; - reward_item_icon: string | null; duration: number; - time_remaining: number; time_remaining_text: string; progress: string; can_complete: BooleanLike; @@ -48,9 +44,6 @@ type Mission = { target_x?: number; target_y?: number; visited?: BooleanLike; - difficulty: number; - difficulty_name: string; - difficulty_color: string; zone_name: string | null; zone_color: string; }; @@ -339,11 +332,12 @@ const MissionBoardContent = () => { } @@ -368,7 +362,7 @@ const MissionBoardContent = () => {

jM8E^g!u^G5Olf|TsdFp>ga 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 z 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 QZ$(@@DB_1I$CwH2?qr diff --git a/voidcrew/modules/ship_upgrades/previews/ship_nano_phalanx_d.png b/voidcrew/modules/ship_upgrades/previews/ship_nano_phalanx_d.png index b4fa34b4e83b0f91fb858334bbce7ab8d0e57484..25dc550cade4cf19d34c887281378c78a54d576c 100644 GIT binary patch delta 46125 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 delta 46025 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

}Ec@#X~W7Ec#Wp-?*WcRwTh=WQkUA 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

- {posting && !has_created_bounty && ( + {!!posting && !has_created_bounty && ( { - const { mission, full } = props; +/** The quoted currency and named goods, without empty reward segments. */ +const RewardSummary = (props: { mission: Mission }) => { + const { mission } = props; const items = mission.reward_items ?? []; const segments: ReactNode[] = []; if (mission.value > 0) { segments.push( - {mission.value} - {full ? ' credits' : ' cr'} + {formatMoney(mission.value)} cr , ); } @@ -490,25 +478,31 @@ const RewardSummary = (props: { mission: Mission; full?: boolean }) => { , ); } - if (mission.research_reward) { + if ((mission.research_reward ?? 0) > 0) { segments.push( - {mission.research_reward} - {full ? ' research points' : ' RP'} + research notes , ); } - if (mission.voucher_count) { + const vouchers = mission.voucher_count ?? 0; + if (vouchers > 0) { segments.push( - {mission.voucher_count} trade voucher - {mission.voucher_count > 1 ? 's' : ''} + {vouchers} trade voucher{vouchers > 1 ? 's' : ''} , ); } + if (segments.length === 0) { + return null; + } + return ( - <> + + + Pays:{' '} + {segments.map((segment, index) => ( {index > 0 && ( @@ -519,7 +513,7 @@ const RewardSummary = (props: { mission: Mission; full?: boolean }) => { {segment} ))} - + ); }; @@ -531,8 +525,8 @@ const MissionCard = (props: MissionCardProps) => { const canAccept = !isActive && active_count < max_missions; // Format time remaining - const formatTime = (ms: number) => { - const totalSeconds = Math.floor(ms / 10); + const formatTime = (deciseconds: number) => { + const totalSeconds = Math.floor(deciseconds / 10); const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; return `${minutes}:${seconds.toString().padStart(2, '0')}`; @@ -549,10 +543,6 @@ const MissionCard = (props: MissionCardProps) => { [{mission.zone_name}] )} - - [{mission.difficulty_name}] - - } > @@ -561,30 +551,15 @@ const MissionCard = (props: MissionCardProps) => { {mission.desc} - {/* Rewards summary */} - - - Rewards:{' '} - - + + + {isActive ? 'Due in: ' : 'Time allowed: '} + {isActive ? mission.time_remaining_text : formatTime(mission.duration)} {!!isActive && ( <> - - - {mission.time_remaining_text} - - {!!mission.progress && ( {mission.progress} diff --git a/tgui/packages/voidcrew_tgui/interfaces/OutpostMissionBoard.tsx b/tgui/packages/voidcrew_tgui/interfaces/OutpostMissionBoard.tsx index 9492557274f..0efe17cb76c 100644 --- a/tgui/packages/voidcrew_tgui/interfaces/OutpostMissionBoard.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/OutpostMissionBoard.tsx @@ -9,6 +9,7 @@ import { Stack, Tooltip, } from 'tgui-core/components'; +import { formatMoney, formatTime } from 'tgui-core/format'; import type { BooleanLike } from 'tgui-core/react'; import { useBackend } from '../../tgui/backend'; @@ -28,25 +29,18 @@ type Offer = { value: number; reward_items?: RewardItem[]; voucher_count: number; - difficulty_name: string; - difficulty_color: string; + research_reward?: number; + duration: number; zone_name: string | null; zone_color: string; progress: string; - wanted_text: string; archetype: string; time_remaining_text: string; - favor_reward: number; - favor_trader: string | null; }; type FavorStanding = { - points: number; tier: number; tier_name: string; - discount_pct: number; - next_at: number; - trader: string; }; type ShipMission = Offer & { @@ -89,7 +83,7 @@ const RewardLine = (props: { offer: Offer }) => { if (offer.value > 0) { segments.push( - {offer.value} cr + {formatMoney(offer.value)} cr , ); } @@ -118,32 +112,34 @@ const RewardLine = (props: { offer: Offer }) => { , ); } - if (offer.favor_reward > 0) { + if ((offer.research_reward ?? 0) > 0) { segments.push( - - +{offer.favor_reward} standing + + research notes , ); } + if (segments.length === 0) { + return null; + } + return ( Pays:{' '} - {segments.length === 0 ? ( - - goods + {segments.map((segment, index) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: static, order-stable list + + {index > 0 && ( + + {' + '} + + )} + {segment} - ) : ( - segments.map((segment, index) => ( - // biome-ignore lint/suspicious/noArrayIndexKey: static, order-stable list - - {index > 0 && {' + '}} - {segment} - - )) - )} + ))} ); }; @@ -166,9 +162,6 @@ const OfferCard = (props: { offer: Offer; canAccept: boolean }) => { [{offer.zone_name}]{' '} )} - - [{offer.difficulty_name}] - {offer.desc} @@ -176,6 +169,9 @@ const OfferCard = (props: { offer: Offer; canAccept: boolean }) => { + + Time allowed: {formatTime(offer.duration, 'short')} + @@ -218,10 +214,16 @@ const ShipMissionRow = (props: { mission: ShipMission }) => { {mission.name} - {mission.progress} · {mission.time_remaining_text} left + {mission.desc} + + {!!mission.progress && ( + + {mission.progress} + + )} + + Due in: {mission.time_remaining_text} - - @@ -255,14 +257,11 @@ export const OutpostMissionBoard = (props) => { {!!barred && ( - TRADE EMBARGO IN EFFECT: {trader_name} is not posting work for - you. + {trader_name}: Service refused. )} {!ship_name && ( - - No crew registration found: you need a ship to take a contract. - + No crew registration found. )}
{ ship_name ? ( {!!favor && ( - = 3 ? 'orange' : 'good'} + mr={1} > - - = 3 ? 'orange' : 'good'} - > - {favor.tier_name} - - {favor.next_at > 0 && ( - - {' '} - ({favor.points}/{favor.next_at}) - - )} - {' · '} - - + {favor.tier_name} + )} {ship_name} · {ship_mission_slots_free} slot {ship_mission_slots_free === 1 ? '' : 's'} free @@ -309,10 +296,6 @@ export const OutpostMissionBoard = (props) => { {ship_missions.map((mission) => ( ))} - - Item contracts can be turned in right here. Hold the goods in - hand. Courier pods only unseal at their destination outpost. -
)}
diff --git a/tgui/packages/voidcrew_tgui/interfaces/TraderShop.tsx b/tgui/packages/voidcrew_tgui/interfaces/TraderShop.tsx index bd0b5e301f3..dbc45836f5e 100644 --- a/tgui/packages/voidcrew_tgui/interfaces/TraderShop.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/TraderShop.tsx @@ -2,16 +2,14 @@ import { useState } from 'react'; import { Box, Button, - Icon, Image, NoticeBox, Section, Stack, Tabs, - TimeDisplay, Tooltip, } from 'tgui-core/components'; -import { formatTime } from 'tgui-core/format'; +import { formatMoney } from 'tgui-core/format'; import type { BooleanLike } from 'tgui-core/react'; import { useBackend } from '../../tgui/backend'; @@ -30,7 +28,6 @@ type CatalogSku = { discount_pct: number; price_text: string; barter: BooleanLike; - favor_required: number; crew_limit: number; }; @@ -45,12 +42,8 @@ type StockState = { }; type FavorStanding = { - points: number; tier: number; tier_name: string; - discount_pct: number; - next_at: number; - trader: string; }; type LedgerEntry = { @@ -79,9 +72,7 @@ type Data = { categories: string[]; catalog: CatalogSku[]; ledger: LedgerEntry[]; - restock_interval: number; // dynamic - restock_remaining: number | null; barred: BooleanLike; held_vouchers: number; account_credits: number | null; @@ -105,18 +96,6 @@ const StandingHeader = (props: { favor: FavorStanding }) => { {favor.tier_name} - {favor.discount_pct > 0 && ( - - {' '} - −{favor.discount_pct}% - - )} - {favor.next_at > 0 && ( - - {' '} - ({favor.points}/{favor.next_at}) - - )} ); }; @@ -140,7 +119,7 @@ const WalletHeader = (props: { ) : ( - {account_credits} cr + {formatMoney(account_credits)} cr )} @@ -178,7 +157,7 @@ const PriceTag = (props: { sku: CatalogSku; finalCredits: number }) => { {sku.price_vouchers > 0 && ( - {sku.price_vouchers} vch + {sku.price_vouchers} voucher{sku.price_vouchers === 1 ? '' : 's'} )} {sku.price_vouchers > 0 && sku.price_credits > 0 && ( @@ -194,11 +173,11 @@ const PriceTag = (props: { sku: CatalogSku; finalCredits: number }) => { color="label" style={{ textDecoration: 'line-through' }} > - {sku.price_credits} + {formatMoney(sku.price_credits)} )}{' '} - {finalCredits} cr + {formatMoney(finalCredits)} cr )} @@ -252,20 +231,10 @@ const SkuRow = (props: { {sku.name}{' '} - {sku.discount_pct > 0 && ( - - −{sku.discount_pct}% - - )}{' '} {!!shelfTag && ( {shelfTag.label} - )}{' '} - {isFavor && sku.favor_required > 0 && ( - - needs {sku.favor_required} standing - )} @@ -278,15 +247,25 @@ const SkuRow = (props: { {isFavor ? ( - yours: {live?.crew_remaining ?? sku.crew_limit} + x{live?.crew_remaining ?? sku.crew_limit} ) : ( <>x{stock} )} - {live?.denial && !barred && !soldOut ? ( - {buyButton} + {live?.denial && !live.can_buy && !barred && !soldOut ? ( + + {buyButton} + ) : ( buyButton )} @@ -380,7 +359,6 @@ const LedgerRow = (props: {