Add signature gemstone as guaranteed local buy in every shop

- Ensure each class's gemstone (tier 3–4 producer good) always appears on the shop floor, swapping into the least-important slot when at max stock to preserve size and avoid duplicates.
- Add a test sweeping every system/class to verify the world's "jewel" is present, produced, and premium in all shops.
This commit is contained in:
Brian Fertig 2026-09-11 21:58:05 -06:00
parent 36ef43119d
commit 05b6f573c3
2 changed files with 35 additions and 0 deletions

View File

@ -189,6 +189,25 @@ const classFor = (sysId, good, list) => (list ?? []).find((c) => g.economy.class
const cshop = E.shopFor('capital', capSys, g);
check('a capital buys back EVERYTHING (universal sink)', cshop.sell.length === goods.length);
check('a capital floor is 8–16 goods', cshop.buy.length >= 8 && cshop.buy.length <= 16);
// THE WORLD'S JEWEL (§4/§6): every shop carries ITS class's signature gem —
// a guaranteed premium good + a guaranteed local buy in every shop. Sweep
// every system of every class (a gem that's only present by catalog luck
// would fail here: the floor must always include the class's gemstone).
let gemWorlds = 0;
let gemMissing = 0;
for (const [id, set] of g.economy.classBySystem) {
for (const cls of set) {
const gem = goods.find((x) => x.category === 'gemstone' && Array.isArray(x.producer) && x.producer.includes(cls));
if (!gem) continue;
gemWorlds++;
const shop = E.shopFor(cls, id, g);
const row = shop.buy.find((b) => b.id === gem.id);
// the jewel is a premium good (tier 3–4) + a local buy (produced).
if (!row || row.produced !== true || (Number(gem.tier) || 0) < 3) gemMissing++;
}
}
check(`every shop carries its class's signature gem (${gemWorlds - gemMissing}/${gemWorlds} worlds)`, gemWorlds > 0 && gemMissing === 0);
}
// ---------------------------------------------------------------------------

View File

@ -184,6 +184,8 @@ function seededSelect(items, n, seed, cls, systemId) {
* · plain world: its produced goods (abundant, cheap)
* · station: produced (≤ half) + a seeded selection of resold goods (variety)
* · capital: produced (≤ half) + a seeded selection of premium goods (tier 3–4)
* · the class's SIGNATURE GEM is ALWAYS on the floor (the world's
* "jewel" — a guaranteed premium good + a guaranteed local buy)
* sell — goods the shop BUYS BACK (what you can sell), each { id, price }
* · plain world / station: the goods the class wants
* · capital: EVERYTHING (the universal sink)
@ -227,6 +229,20 @@ export function shopFor(cls, systemId, galaxy) {
}
}
// THE WORLD'S JEWEL (goods.json gemstones, §4/§6): the class's signature
// gem is ALWAYS on the shelf — a guaranteed premium good (tier 3–4) and a
// guaranteed local buy in every shop, whatever the seeded floor picked.
// It's a produced good of `cls`, so it prices at the producer discount;
// swap it into the least-important slot (a hub's resold filler, or an
// extra local good on a plain world) keeping the 8–16 floor size + no dups.
const gem = goods.find(
(g) => g.category === 'gemstone' && Array.isArray(g.producer) && g.producer.includes(cls),
);
if (gem && !buyIds.includes(gem.id)) {
if (buyIds.length < maxStock) buyIds.push(gem.id);
else buyIds[buyIds.length - 1] = gem.id;
}
const buy = buyIds.map((id) => ({
id,
name: goodById(id)?.name ?? id,