Step 16.2: content: goods
CI / check (push) Has been cancelled
Details
CI / check (push) Has been cancelled
Details
Adds Atmospheric Data Cores, Refined Sulfur, Volcanic Isotopes and Subsurface Ocean Samples, and the new producers and destinations for existing goods at Venus, Io and Europa. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c0d3897d8d
commit
026947ebe9
|
|
@ -394,7 +394,7 @@ Spec: `memory-bank/change-requests/CR-015-fixed-map-fuel-tanks.md` (received as
|
||||||
Spec: `memory-bank/change-requests/CR-016-venus-io-europa-belt.md` (received as "CR-015 … Phase 15"). New decisions recorded as plan §0.5.100–0.5.105.
|
Spec: `memory-bank/change-requests/CR-016-venus-io-europa-belt.md` (received as "CR-015 … Phase 15"). New decisions recorded as plan §0.5.100–0.5.105.
|
||||||
|
|
||||||
- [x] **Step 16.1 — Content: new locations.** Venus Cloud City (cloud platform, atmospheric, 108M km at 110°, range factor 1.0, fuel × 1.3, bay 20,000), Io Sulfur Works (new type `orbital-station`, `vacuum` landing so any ship can land, 0.42M km out from Jupiter, factor 1.2, fuel × 1.0, bay 70,000) and Europa Ice Station (new type `surface-base`, `vacuum`, 0.67M km out from Jupiter, factor 1.3, fuel × 0.7, bay 70,000); all undiscovered, selling fuel, with the CR's shippers and class mixes. Pulled forward so the game keeps working: each new place's Standard good (Cloud-Grown Botanicals at Venus, a new good; Mail & Parcels also produced at Io and Europa), since boards can't be generated where nothing Standard is made; and the three body sprites in the art manifest, with their generated art (the belt is still 16.5). The balance check's first Market purchase moved from 64 to ~92 min (the Clipper's landings decide it, and Venus changed which first contacts boards offer); the user widened the window to 45–95. Tests: `packages/content/test/fixed-map.test.ts` (Earth/Moon–Venus ≈ 200, Venus–Mars ≈ 332, Venus–Ceres ≈ 520, Venus–Jupiter ≈ 885, Ceres–Io/Europa ≈ 393, all within 2 %; the Jupiter system within 1.1M km; Io and Europa ride with Jupiter at their offsets; the three undiscovered, selling fuel, not Hardened; only Earth and the Moon start discovered); `locations.test.ts` (eight locations; fuel prices ordered Jupiter < Europa < Ceres < Io < Moon < Venus < Mars < Earth). Updated: bundle count, first contacts may go to Mars or Venus, the CR-007 class-mix baseline measured on its original five places, orbit rings for every body but those riding a parent, the Market reach line now listing Venus.
|
- [x] **Step 16.1 — Content: new locations.** Venus Cloud City (cloud platform, atmospheric, 108M km at 110°, range factor 1.0, fuel × 1.3, bay 20,000), Io Sulfur Works (new type `orbital-station`, `vacuum` landing so any ship can land, 0.42M km out from Jupiter, factor 1.2, fuel × 1.0, bay 70,000) and Europa Ice Station (new type `surface-base`, `vacuum`, 0.67M km out from Jupiter, factor 1.3, fuel × 0.7, bay 70,000); all undiscovered, selling fuel, with the CR's shippers and class mixes. Pulled forward so the game keeps working: each new place's Standard good (Cloud-Grown Botanicals at Venus, a new good; Mail & Parcels also produced at Io and Europa), since boards can't be generated where nothing Standard is made; and the three body sprites in the art manifest, with their generated art (the belt is still 16.5). The balance check's first Market purchase moved from 64 to ~92 min (the Clipper's landings decide it, and Venus changed which first contacts boards offer); the user widened the window to 45–95. Tests: `packages/content/test/fixed-map.test.ts` (Earth/Moon–Venus ≈ 200, Venus–Mars ≈ 332, Venus–Ceres ≈ 520, Venus–Jupiter ≈ 885, Ceres–Io/Europa ≈ 393, all within 2 %; the Jupiter system within 1.1M km; Io and Europa ride with Jupiter at their offsets; the three undiscovered, selling fuel, not Hardened; only Earth and the Moon start discovered); `locations.test.ts` (eight locations; fuel prices ordered Jupiter < Europa < Ceres < Io < Moon < Venus < Mars < Earth). Updated: bundle count, first contacts may go to Mars or Venus, the CR-007 class-mix baseline measured on its original five places, orbit rings for every body but those riding a parent, the Market reach line now listing Venus.
|
||||||
- [ ] Step 16.2 — Content: goods
|
- [x] **Step 16.2 — Content: goods.** New goods: Atmospheric Data Cores (High-Value tier 2, Venus → Earth), Refined Sulfur (Heavy, Io → Earth, Mars, Venus), Volcanic Isotopes (High-Value tier 3, Io → Earth), Subsurface Ocean Samples (High-Value tier 3, Priority, Europa → Earth); Cloud-Grown Botanicals came in 16.1. Water Ice and Liquid Oxygen are also made at Europa, Industrial Chemicals at Venus; Water Ice goes to Io and Venus, Liquid Oxygen to Io, Habitat Prefabs to Io and Europa, and Packaged Food, Consumer Goods, Mail & Parcels, Medical Supplies, Electronics and Machine Parts to all three new places. Balance medians: first purchase 92.3, discovery 48.9, loan 160.5, four ships 147 vs 156. Tests (`packages/content/test/goods.test.ts`): the five new goods with their classes, tiers and routes (Sulfur has no tier of its own); every location makes a Standard good and wants at least one; each new place is a destination for at least five goods; the new producers on existing goods.
|
||||||
- [ ] Step 16.3 — Content tuning: reach
|
- [ ] Step 16.3 — Content tuning: reach
|
||||||
- [ ] Step 16.4 — Engine: save migration and boards
|
- [ ] Step 16.4 — Engine: save migration and boards
|
||||||
- [ ] Step 16.5 — Assets: sprites and belt rocks
|
- [ ] Step 16.5 — Assets: sprites and belt rocks
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export const goods: Good[] = [
|
||||||
payMultiplier: 1.2,
|
payMultiplier: 1.2,
|
||||||
priorityEligible: true,
|
priorityEligible: true,
|
||||||
producedAt: [EARTH, MARS, IO, EUROPA],
|
producedAt: [EARTH, MARS, IO, EUROPA],
|
||||||
demandedAt: [MOON, MARS, CERES, JUPITER, EARTH],
|
demandedAt: [MOON, MARS, CERES, JUPITER, EARTH, VENUS, IO, EUROPA],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "packaged-food",
|
id: "packaged-food",
|
||||||
|
|
@ -34,7 +34,7 @@ export const goods: Good[] = [
|
||||||
payMultiplier: 1,
|
payMultiplier: 1,
|
||||||
priorityEligible: false,
|
priorityEligible: false,
|
||||||
producedAt: [EARTH],
|
producedAt: [EARTH],
|
||||||
demandedAt: [MOON, MARS, CERES, JUPITER],
|
demandedAt: [MOON, MARS, CERES, JUPITER, VENUS, IO, EUROPA],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "consumer-goods",
|
id: "consumer-goods",
|
||||||
|
|
@ -44,7 +44,7 @@ export const goods: Good[] = [
|
||||||
payMultiplier: 1,
|
payMultiplier: 1,
|
||||||
priorityEligible: false,
|
priorityEligible: false,
|
||||||
producedAt: [EARTH],
|
producedAt: [EARTH],
|
||||||
demandedAt: [MOON, MARS, CERES, JUPITER],
|
demandedAt: [MOON, MARS, CERES, JUPITER, VENUS, IO, EUROPA],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "optical-glass",
|
id: "optical-glass",
|
||||||
|
|
@ -170,7 +170,7 @@ export const goods: Good[] = [
|
||||||
tier: 1,
|
tier: 1,
|
||||||
priorityEligible: true,
|
priorityEligible: true,
|
||||||
producedAt: [EARTH],
|
producedAt: [EARTH],
|
||||||
demandedAt: [MOON, MARS, CERES, JUPITER],
|
demandedAt: [MOON, MARS, CERES, JUPITER, VENUS, IO, EUROPA],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "electronics",
|
id: "electronics",
|
||||||
|
|
@ -181,7 +181,7 @@ export const goods: Good[] = [
|
||||||
tier: 1,
|
tier: 1,
|
||||||
priorityEligible: false,
|
priorityEligible: false,
|
||||||
producedAt: [EARTH],
|
producedAt: [EARTH],
|
||||||
demandedAt: [MOON, MARS, CERES, JUPITER],
|
demandedAt: [MOON, MARS, CERES, JUPITER, VENUS, IO, EUROPA],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "seed-stock",
|
id: "seed-stock",
|
||||||
|
|
@ -238,6 +238,39 @@ export const goods: Good[] = [
|
||||||
producedAt: [CERES],
|
producedAt: [CERES],
|
||||||
demandedAt: [EARTH],
|
demandedAt: [EARTH],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "atmo-data-cores",
|
||||||
|
name: "Atmospheric Data Cores",
|
||||||
|
cargoClassId: "high-value",
|
||||||
|
massTonnes: { min: 0.5, max: 4 },
|
||||||
|
payMultiplier: 1.4,
|
||||||
|
tier: 2,
|
||||||
|
priorityEligible: false,
|
||||||
|
producedAt: [VENUS],
|
||||||
|
demandedAt: [EARTH],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "volcanic-isotopes",
|
||||||
|
name: "Volcanic Isotopes",
|
||||||
|
cargoClassId: "high-value",
|
||||||
|
massTonnes: { min: 0.5, max: 5 },
|
||||||
|
payMultiplier: 1.7,
|
||||||
|
tier: 3,
|
||||||
|
priorityEligible: false,
|
||||||
|
producedAt: [IO],
|
||||||
|
demandedAt: [EARTH],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ocean-samples",
|
||||||
|
name: "Subsurface Ocean Samples",
|
||||||
|
cargoClassId: "high-value",
|
||||||
|
massTonnes: { min: 0.2, max: 2 },
|
||||||
|
payMultiplier: 1.8,
|
||||||
|
tier: 3,
|
||||||
|
priorityEligible: true,
|
||||||
|
producedAt: [EUROPA],
|
||||||
|
demandedAt: [EARTH],
|
||||||
|
},
|
||||||
|
|
||||||
// Heavy: Heavy Cargo skill; tier follows the generator's Heavy rule.
|
// Heavy: Heavy Cargo skill; tier follows the generator's Heavy rule.
|
||||||
{
|
{
|
||||||
|
|
@ -249,7 +282,7 @@ export const goods: Good[] = [
|
||||||
priorityEligible: true,
|
priorityEligible: true,
|
||||||
priorityName: "Emergency Parts",
|
priorityName: "Emergency Parts",
|
||||||
producedAt: [EARTH, MARS],
|
producedAt: [EARTH, MARS],
|
||||||
demandedAt: [MOON, MARS, CERES, JUPITER],
|
demandedAt: [MOON, MARS, CERES, JUPITER, VENUS, IO, EUROPA],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "habitat-prefabs",
|
id: "habitat-prefabs",
|
||||||
|
|
@ -259,7 +292,7 @@ export const goods: Good[] = [
|
||||||
payMultiplier: 1,
|
payMultiplier: 1,
|
||||||
priorityEligible: false,
|
priorityEligible: false,
|
||||||
producedAt: [EARTH],
|
producedAt: [EARTH],
|
||||||
demandedAt: [MOON, MARS, CERES],
|
demandedAt: [MOON, MARS, CERES, IO, EUROPA],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "lunar-titanium",
|
id: "lunar-titanium",
|
||||||
|
|
@ -291,6 +324,16 @@ export const goods: Good[] = [
|
||||||
producedAt: [CERES],
|
producedAt: [CERES],
|
||||||
demandedAt: [EARTH, MARS, MOON],
|
demandedAt: [EARTH, MARS, MOON],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "sulfur",
|
||||||
|
name: "Refined Sulfur",
|
||||||
|
cargoClassId: "heavy",
|
||||||
|
massTonnes: { min: 40, max: 200 },
|
||||||
|
payMultiplier: 0.9,
|
||||||
|
priorityEligible: false,
|
||||||
|
producedAt: [IO],
|
||||||
|
demandedAt: [EARTH, MARS, VENUS],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "water-ice",
|
id: "water-ice",
|
||||||
name: "Water Ice",
|
name: "Water Ice",
|
||||||
|
|
@ -298,8 +341,8 @@ export const goods: Good[] = [
|
||||||
massTonnes: { min: 60, max: 250 },
|
massTonnes: { min: 60, max: 250 },
|
||||||
payMultiplier: 0.8,
|
payMultiplier: 0.8,
|
||||||
priorityEligible: false,
|
priorityEligible: false,
|
||||||
producedAt: [CERES],
|
producedAt: [CERES, EUROPA],
|
||||||
demandedAt: [MARS, MOON, JUPITER],
|
demandedAt: [MARS, MOON, JUPITER, IO, VENUS],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Dangerous: Dangerous Cargo skill; tier is the hazard class.
|
// Dangerous: Dangerous Cargo skill; tier is the hazard class.
|
||||||
|
|
@ -311,7 +354,7 @@ export const goods: Good[] = [
|
||||||
payMultiplier: 1,
|
payMultiplier: 1,
|
||||||
tier: 1,
|
tier: 1,
|
||||||
priorityEligible: false,
|
priorityEligible: false,
|
||||||
producedAt: [EARTH],
|
producedAt: [EARTH, VENUS],
|
||||||
demandedAt: [MOON, MARS, CERES, JUPITER],
|
demandedAt: [MOON, MARS, CERES, JUPITER],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -322,8 +365,8 @@ export const goods: Good[] = [
|
||||||
payMultiplier: 1,
|
payMultiplier: 1,
|
||||||
tier: 1,
|
tier: 1,
|
||||||
priorityEligible: false,
|
priorityEligible: false,
|
||||||
producedAt: [MOON],
|
producedAt: [MOON, EUROPA],
|
||||||
demandedAt: [MARS, CERES, JUPITER],
|
demandedAt: [MARS, CERES, JUPITER, IO],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "mining-charges",
|
id: "mining-charges",
|
||||||
|
|
|
||||||
|
|
@ -77,3 +77,58 @@ describe("goods catalog (CR-007)", () => {
|
||||||
expect(goods.some((g) => g.priorityEligible)).toBe(true);
|
expect(goods.some((g) => g.priorityEligible)).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("goods for Venus, Io and Europa (Step 16.2, decision 0.5.103)", () => {
|
||||||
|
const newPlaces = ["venus-cloud-city", "io-sulfur-works", "europa-ice-station"];
|
||||||
|
|
||||||
|
it("adds the five new goods with the CR's classes, tiers and routes", () => {
|
||||||
|
const good = (id: string) => goods.find((g) => g.id === id)!;
|
||||||
|
expect(good("cloud-botanicals")).toMatchObject({
|
||||||
|
cargoClassId: "standard",
|
||||||
|
priorityEligible: true,
|
||||||
|
producedAt: ["venus-cloud-city"],
|
||||||
|
});
|
||||||
|
expect(good("atmo-data-cores")).toMatchObject({ cargoClassId: "high-value", tier: 2 });
|
||||||
|
expect(good("sulfur")).toMatchObject({
|
||||||
|
cargoClassId: "heavy",
|
||||||
|
producedAt: ["io-sulfur-works"],
|
||||||
|
});
|
||||||
|
expect(good("sulfur").tier).toBeUndefined();
|
||||||
|
expect(good("volcanic-isotopes")).toMatchObject({ cargoClassId: "high-value", tier: 3 });
|
||||||
|
expect(good("ocean-samples")).toMatchObject({
|
||||||
|
cargoClassId: "high-value",
|
||||||
|
tier: 3,
|
||||||
|
priorityEligible: true,
|
||||||
|
producedAt: ["europa-ice-station"],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has every location produce a Standard good and demand at least one good", () => {
|
||||||
|
for (const location of locations) {
|
||||||
|
const standard = goods.filter(
|
||||||
|
(g) => g.cargoClassId === "standard" && g.producedAt.includes(location.id),
|
||||||
|
);
|
||||||
|
expect(standard.length, location.id).toBeGreaterThan(0);
|
||||||
|
expect(
|
||||||
|
goods.some((g) => g.demandedAt.includes(location.id)),
|
||||||
|
location.id,
|
||||||
|
).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("makes each new place a destination for at least five goods", () => {
|
||||||
|
for (const id of newPlaces) {
|
||||||
|
expect(goods.filter((g) => g.demandedAt.includes(id)).length, id).toBeGreaterThanOrEqual(5);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adds the new producers to existing goods", () => {
|
||||||
|
const at = (id: string) => goods.find((g) => g.id === id)!;
|
||||||
|
expect(at("water-ice").producedAt).toContain("europa-ice-station");
|
||||||
|
expect(at("liquid-oxygen").producedAt).toContain("europa-ice-station");
|
||||||
|
expect(at("industrial-chemicals").producedAt).toContain("venus-cloud-city");
|
||||||
|
expect(at("mail").producedAt).toEqual(
|
||||||
|
expect.arrayContaining(["io-sulfur-works", "europa-ice-station"]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue