Generation never offers gear no hull can mount
Operator ruling, 2026-09-30, on the Autocannon: "Leave the autocannon unsold, we'll need to author a bunch more hulls before all the gear variety in the game has a home." The fit rule gets one owner, HardpointData.Takes (the gear's type, laid in at the hardpoint's rotation, filling every cell); LoadoutGenerator's hardpoint picks, its reuse of a previous product and `AetherDb hardpoint-fit` all read it. RandomProducts, which both station stock and NPC loadouts draw through, offers only gear with a home: Tool gear, hulls, or hardpoint gear some hull in the catalog takes. The Autocannon keeps its product and price. Test: the Autocannon is never drawn in 2000 draws of its hardpoint type; after a scratch hull whose hardpoint takes it is authored, it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5c3cd599ac
commit
d91ab8daf9
4 changed files with 42 additions and 9 deletions
|
|
@ -141,12 +141,14 @@ public class LoadoutGenerator
|
|||
// lacks variety, so it is logged rather than hidden.
|
||||
public (FactionProductData product, T design)[] RandomProducts<T>(int count, float sizeExponent, Predicate<T> filter = null, bool required = false) where T : EquippableItemData
|
||||
{
|
||||
var hulls = ItemManager.ItemData.GetAll<HullData>().ToArray();
|
||||
var candidates = ItemManager.ItemData.GetAll<FactionProductData>()
|
||||
.Select(product => (product, design: ItemManager.ItemData.Get(product.Design) as T))
|
||||
.Where(entry =>
|
||||
entry.design != null &&
|
||||
entry.design.Price > 0 &&
|
||||
entry.product.Manufacturer.IsSet() &&
|
||||
HasHome(entry.design, hulls) &&
|
||||
(filter?.Invoke(entry.design) ?? true))
|
||||
.ToArray();
|
||||
var available = candidates.Where(entry => IsAvailable(entry.product)).ToArray();
|
||||
|
|
@ -165,6 +167,13 @@ public class LoadoutGenerator
|
|||
count);
|
||||
}
|
||||
|
||||
// Hardpoint gear that no hull in the catalog can mount has no home (operator, 2026-09-30: "we'll need to author a
|
||||
// bunch more hulls before all the gear variety in the game has a home"): generation never offers it, so no station
|
||||
// stocks it. It gains one the moment a hull with a hardpoint that takes it exists. Tool gear goes in any interior.
|
||||
private static bool HasHome(EquippableItemData design, HullData[] hulls) =>
|
||||
design.HardpointType == HardpointType.Tool || design.HardpointType == HardpointType.Hull ||
|
||||
hulls.Any(hull => hull.Hardpoints.Any(hardpoint => hardpoint.Takes(design)));
|
||||
|
||||
// No galaxy means no availability to filter by: every product is on offer. A fixture generates loadouts that
|
||||
// way, so a test can exercise placement and products without standing up a whole galaxy; no game path does.
|
||||
// Loadouts.Materialize takes availability as a predicate; RunStart, the game's one preset spawner, passes this, so
|
||||
|
|
@ -192,10 +201,7 @@ public class LoadoutGenerator
|
|||
|
||||
public (FactionProductData product, T design) RandomProduct<T>(HardpointData hardpoint, float sizeExponent, Predicate<T> filter = null, bool required = false) where T : EquippableItemData
|
||||
{
|
||||
return RandomProduct<T>(sizeExponent, item => item.HardpointType == hardpoint.Type &&
|
||||
(filter?.Invoke(item) ?? true) &&
|
||||
item.Shape.FitsWithin(hardpoint.Shape, hardpoint.Rotation, out _) &&
|
||||
item.Shape.Coordinates.Length==hardpoint.Shape.Coordinates.Length, required);
|
||||
return RandomProduct<T>(sizeExponent, item => hardpoint.Takes(item) && (filter?.Invoke(item) ?? true), required);
|
||||
}
|
||||
|
||||
private void OutfitEntity(Entity entity)
|
||||
|
|
@ -227,7 +233,7 @@ public class LoadoutGenerator
|
|||
{
|
||||
// If a previously selected product fits, use that one (this is why we must process larger hardpoints first)
|
||||
var entry = previousProducts
|
||||
.FirstOrDefault(e => e.design.HardpointType == hardpoint.Type && e.design.Shape.FitsWithin(hardpoint.Shape, hardpoint.Rotation, out _));
|
||||
.FirstOrDefault(e => hardpoint.Takes(e.design));
|
||||
var previousItem = entity.Equipment.FirstOrDefault(item => item.Data == entry.design);
|
||||
if (entry.design == null) entry = RandomProduct<GearData>(hardpoint, 2);
|
||||
if (entry.design == null) ItemManager.Log($"No compatible item found for entity {Enum.GetName(typeof(HardpointType), hardpoint.Type)} hardpoint!");
|
||||
|
|
|
|||
Loading…
Reference in a new issue