From bfcde46c0f3a87d233a2edfdf3ed5d4791e0e0c2 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 18 Oct 2026 18:22:15 +0200 Subject: [PATCH] Delete GenerateBossLoadout, ShipLoadout and the boss fallback tests (does not build: ZoneGenerator and Program still call them until the next commit) Boss gear is never drawn (ruling boss-gear-is-a-loadout). GenerateShipLoadout gets its single body back. Co-Authored-By: Claude Sonnet 5.5 --- .../Scripts/ServerShared/LoadoutGenerator.cs | 29 +++-------------- tests/Aetheria.Shared.Tests/RunGoalTests.cs | 31 ------------------- tools/AetherDb/Program.cs | 7 +---- 3 files changed, 6 insertions(+), 61 deletions(-) diff --git a/Assets/Scripts/ServerShared/LoadoutGenerator.cs b/Assets/Scripts/ServerShared/LoadoutGenerator.cs index 34e1cd1c0..86b300931 100644 --- a/Assets/Scripts/ServerShared/LoadoutGenerator.cs +++ b/Assets/Scripts/ServerShared/LoadoutGenerator.cs @@ -48,13 +48,7 @@ public class LoadoutGenerator ItemManager.Log("Unable to generate ship loadout: no compatible hull found!"); return null; } - return ShipLoadout(hullProduct); - } - - // The ship a hull product becomes: outfit, pickup, consumables, packed. Callers choose the product; this is the one build. - public EntityPack ShipLoadout(FactionProductData product) - { - var hull = ItemManager.CreateInstance(product) as EquippableItem; + var hull = ItemManager.CreateInstance(hullProduct) as EquippableItem; if(hull==null) ItemManager.Log("WHAT???"); var entity = new Ship(ItemManager, null, hull, ItemManager.GameplaySettings.DefaultEntitySettings); @@ -191,8 +185,8 @@ public class LoadoutGenerator // The products this faction can be offered for a design kind (only gear needs a home), and whether manufacturer preference applies (it does // not once a required item has fallen back to any manufacturer). The one availability rule for every selection: a Boss - // hull is never on offer, so it is never station stock, ordinary traffic, a generated scenario fit or another faction's - // fallback boss, and only BossHullsOf reaches it. + // hull is never on offer, so it is never station stock, ordinary traffic or a generated scenario fit; a Boss hull + // reaches a ship only through its faction's boss Loadout (Loadouts.BossOf). private ((FactionProductData product, T design)[] available, bool preferManufacturers) AvailableProducts(Predicate filter, bool required) where T : CraftedItemData { var hulls = SoldHulls(ItemManager.ItemData); @@ -218,23 +212,10 @@ public class LoadoutGenerator return (available, preferManufacturers); } - // A faction's boss: the Boss hull it makes (BossHullsOf, dearest first), else the most expensive ordinary ship hull the - // faction can be offered, with the gap logged. Null only when no ship hull is on offer at all. - public EntityPack GenerateBossLoadout() - { - var made = BossHullsOf(ItemManager.ItemData, Faction); - if (made.Length > 0) return ShipLoadout(made[0].product); - ItemManager.Log($"{Faction?.Name ?? "This faction"} makes no boss hull; its boss flies the most expensive ship hull instead."); - - var (available, _) = AvailableProducts(hull => hull.HullType == HullType.Ship, required: true); - if (available.Length == 0) return null; - var priciest = available.OrderByDescending(entry => entry.design.Price).ThenBy(entry => entry.design.Name, StringComparer.Ordinal).First().design; - return GenerateShipLoadout(hull => hull == priciest); - } - // The one owner of which hull is a faction's boss: the Ship hulls flagged Boss among the designs of the products the // faction manufactures, dearest first then by name. The flag lives on the hull and the maker on the product, so a Boss - // hull several makers sell is a boss of each; nothing here reads a model, a prefab or a visual. + // hull several makers sell is a boss of each; nothing here reads a model, a prefab or a visual. Its readers are + // Loadouts.BossOf and AetherDb factions. public static (FactionProductData product, HullData hull)[] BossHullsOf(CultCache items, Faction faction) => faction == null ? Array.Empty<(FactionProductData, HullData)>() diff --git a/tests/Aetheria.Shared.Tests/RunGoalTests.cs b/tests/Aetheria.Shared.Tests/RunGoalTests.cs index 541ee64dd..460becc92 100644 --- a/tests/Aetheria.Shared.Tests/RunGoalTests.cs +++ b/tests/Aetheria.Shared.Tests/RunGoalTests.cs @@ -107,21 +107,6 @@ public sealed partial class RunStartTests Assert.Equal(new[] { "Boss A", "Boss B", "Boss C" }, LoadoutGenerator.BossHullsOf(_cache, antagonist).Select(entry => entry.hull.Name)); } - [Fact] - public void Boss_without_a_boss_hull_falls_back() - { - var galaxy = DemoGalaxy(1); - var priciest = PriciestSold(); - - var log = new List(); - var items = LoggingItems(log); - var boss = Assert.Single(BossZonePack(galaxy, items, galaxy.Exit).Entities, entity => entity.Boss); - Assert.Equal(priciest.Name, HullName(items, boss)); - Assert.Contains(log, line => line.Contains("Zhestokost") && line.Contains("makes no boss hull")); - Assert.Empty(LoadoutGenerator.BossHullsOf(_cache, Zhestokost(galaxy))); - Assert.Empty(LoadoutGenerator.BossHullsOf(_cache, null)); - } - [Fact] public void Another_factions_boss_hull_is_never_used() { @@ -354,22 +339,6 @@ public sealed partial class RunStartTests Assert.False(RunGoal.ExitOpen(zone)); } - // A boss that cannot be generated (no ship hull on offer at all) never marks the zone as having spawned one. - [Fact] - public void Exit_sealed_when_no_ship_hull_is_on_offer() - { - var galaxy = DemoGalaxy(1); - foreach (var product in _cache.GetAll().Where(product => _cache.Get(product.Design) is HullData { HullType: HullType.Ship }).ToArray()) - Assert.True(_cache.Remove(_cache.RefOf(product).Key)); - var log = new List(); - var items = LoggingItems(log); - var pack = BossZonePack(galaxy, items, galaxy.Exit, ambient: false); - Assert.False(pack.BossSpawned); - Assert.DoesNotContain(pack.Entities, entity => entity.Boss); - Assert.Contains(log, line => line.Contains("No boss could be generated for Zhestokost")); - Assert.False(RunGoal.ExitOpen(new Zone(items, _planetSettings, pack, galaxy.Exit, galaxy))); - } - // A boss killed before the save stays dead after it, and the gate stays open: the spawn fact travels with the zone. [Fact] public void Exit_open_after_save_of_a_slain_boss() diff --git a/tools/AetherDb/Program.cs b/tools/AetherDb/Program.cs index 583e811ad..5f2324471 100644 --- a/tools/AetherDb/Program.cs +++ b/tools/AetherDb/Program.cs @@ -806,18 +806,13 @@ public static class Program string outcome; try { - // Generation never offers a Boss hull, so one is built through its first product. - var bossProduct = hull.Boss && hull.HullType == HullType.Ship - ? db.Cache.GetAll().Where(p => db.Cache.Get(p.Design) == hull).OrderBy(p => p.Name, StringComparer.Ordinal).FirstOrDefault() - : null; var pack = hull.HullType switch { - HullType.Ship when hull.Boss => bossProduct == null ? null : generator.ShipLoadout(bossProduct), HullType.Ship => generator.GenerateShipLoadout(candidate => candidate == hull), HullType.Turret => generator.GenerateTurretLoadout(), _ => generator.GenerateStationLoadout() }; - outcome = pack != null ? "ok" : hull.Boss && hull.HullType == HullType.Ship ? "NO LOADOUT (boss hull with no product)" : "NO LOADOUT (nothing suitable found)"; + outcome = pack != null ? "ok" : "NO LOADOUT (nothing suitable found)"; if (pack == null) failures++; if (pack != null && log.Any(l => l.Contains("targeting system available", StringComparison.OrdinalIgnoreCase))) targetingGaps++; }