Change cargo bay builds to cost credits + minerals
- Rebalance the three cargo hold upgrades (8/12/16) from a credits-only sink to a mixed cost of credits and minerals, so expanding the hold draws on both trade income and the mining economy. - Update research descriptions, build data, tests, docs, and code comments to reflect the new two-resource costs.
This commit is contained in:
parent
138096cd2b
commit
15eaf26c03
|
|
@ -222,12 +222,13 @@
|
|||
},
|
||||
"cargo-bay-8": {
|
||||
"label": "Cargo Bay \u2014 8",
|
||||
"description": "Expands the ship's cargo hold from 4 to 8 bays \u2014 roughly 2\u00d7 the goods per run, and the trade income to match. A ship upgrade: built from any planet's console, paid in credits, counted wherever the ship lands (never re-bought).",
|
||||
"description": "Expands the ship's cargo hold from 4 to 8 bays \u2014 roughly 2\u00d7 the goods per run, and the trade income to match. A ship upgrade: built from any planet's console (500 credits + 200 minerals, 20 s), counted wherever the ship lands (never re-bought).",
|
||||
"icon": "storage",
|
||||
"category": "cargo",
|
||||
"targets": ["ship"],
|
||||
"cost": {
|
||||
"credits": 300
|
||||
"credits": 500,
|
||||
"minerals": 200
|
||||
},
|
||||
"duration": 20,
|
||||
"requires": ["cargo/cargo_bay_8"],
|
||||
|
|
@ -243,12 +244,13 @@
|
|||
},
|
||||
"cargo-bay-12": {
|
||||
"label": "Cargo Bay \u2014 12",
|
||||
"description": "Expands the ship's cargo hold to 12 bays \u2014 three quarters of a full hold in a single run. Supersedes the 8-bay bay (the biggest hold always wins). A ship upgrade, paid in credits.",
|
||||
"description": "Expands the ship's cargo hold to 12 bays \u2014 three quarters of a full hold in a single run. Supersedes the 8-bay bay (the biggest hold always wins). A ship upgrade, paid in credits + minerals (800 credits + 350 minerals, 30 s).",
|
||||
"icon": "storage",
|
||||
"category": "cargo",
|
||||
"targets": ["ship"],
|
||||
"cost": {
|
||||
"credits": 1200
|
||||
"credits": 800,
|
||||
"minerals": 350
|
||||
},
|
||||
"duration": 30,
|
||||
"requires": ["cargo/cargo_bay_12"],
|
||||
|
|
@ -264,12 +266,13 @@
|
|||
},
|
||||
"cargo-bay-16": {
|
||||
"label": "Cargo Bay \u2014 16",
|
||||
"description": "The full 16-bay cargo hold \u2014 a freighter's worth of goods in one run, the biggest the ship can carry. Supersedes every smaller bay. A ship upgrade, paid in credits.",
|
||||
"description": "The full 16-bay cargo hold \u2014 a freighter's worth of goods in one run, the biggest the ship can carry. Supersedes every smaller bay. A ship upgrade, paid in credits + minerals (1200 credits + 500 minerals, 40 s).",
|
||||
"icon": "storage",
|
||||
"category": "cargo",
|
||||
"targets": ["ship"],
|
||||
"cost": {
|
||||
"credits": 3000
|
||||
"credits": 1200,
|
||||
"minerals": 500
|
||||
},
|
||||
"duration": 40,
|
||||
"requires": ["cargo/cargo_bay_16"],
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"nodes": {
|
||||
"cargo_bay_8": {
|
||||
"label": "Cargo - 8 Bays",
|
||||
"description": "The blueprint for the ship's first trade upgrade: the 8-bay hold. Once researched, the 8-bay bay can be built from any planet's console (300 credits, 20 s) — roughly 2× the goods per run, and the trade income to match.",
|
||||
"description": "The blueprint for the ship's first trade upgrade: the 8-bay hold. Once researched, the 8-bay bay can be built from any planet's console (500 credits + 200 minerals, 20 s) — roughly 2× the goods per run, and the trade income to match.",
|
||||
"icon": "storage",
|
||||
"duration": 60,
|
||||
"requires": [],
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
},
|
||||
"cargo_bay_12": {
|
||||
"label": "Cargo - 12 Bays",
|
||||
"description": "The blueprint for the 12-bay hold. Once researched, the 12-bay bay can be built (1200 credits, 30 s) — three quarters of a full hold in a single run, supersedes the 8-bay bay.",
|
||||
"description": "The blueprint for the 12-bay hold. Once researched, the 12-bay bay can be built (800 credits + 350 minerals, 30 s) — three quarters of a full hold in a single run, supersedes the 8-bay bay.",
|
||||
"icon": "storage",
|
||||
"duration": 60,
|
||||
"requires": ["cargo_bay_8"],
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
},
|
||||
"cargo_bay_16": {
|
||||
"label": "Cargo - 16 Bays",
|
||||
"description": "The blueprint for the full 16-bay hold — a freighter's worth of goods in one run, the biggest the ship can carry. Once researched, the 16-bay bay can be built (3000 credits, 40 s), superseding every smaller bay.",
|
||||
"description": "The blueprint for the full 16-bay hold — a freighter's worth of goods in one run, the biggest the ship can carry. Once researched, the 16-bay bay can be built (1200 credits + 500 minerals, 40 s), superseding every smaller bay.",
|
||||
"icon": "storage",
|
||||
"duration": 60,
|
||||
"requires": ["cargo_bay_12"],
|
||||
|
|
|
|||
|
|
@ -79,13 +79,17 @@ const miningCat = loadBuilds('mining');
|
|||
check('model: loadBuilds("planet") holds the three tether builds', !!planet.builds['tether-l1'] && !!planet.builds['tether-l2'] && !!planet.builds['tether-l3']);
|
||||
check('model: loadBuilds("planet") keeps registry entry (label/accent)', planet.label === 'Planet' && typeof planet.accent === 'string');
|
||||
check('model: loadBuilds("cargo") holds the three ship-hold bays (8/12/16)', !!cargo.builds['cargo-bay-8'] && !!cargo.builds['cargo-bay-12'] && !!cargo.builds['cargo-bay-16']);
|
||||
// The cargo bays are a CREDIT sink (the trade income buys the hold) — so the
|
||||
// affordability wallet must cover credits, not just minerals.
|
||||
check('model: cargo bays are credit-costed (the first credit sink)', cargo.builds['cargo-bay-8'].cost.credits === 300 && cargo.builds['cargo-bay-12'].cost.credits === 1200 && cargo.builds['cargo-bay-16'].cost.credits === 3000);
|
||||
check('model: cargo bays cost CREDITS (not minerals)', costLines(cargo.builds['cargo-bay-8']).every((l) => l.res === 'credits'));
|
||||
check('model: a credits wallet affords the 8-bay (300 cr) build', canAfford(cargo.builds['cargo-bay-8'], { minerals: 0, credits: 300 }));
|
||||
check('model: a credits wallet BELOW the cost does not afford it', !canAfford(cargo.builds['cargo-bay-8'], { minerals: 100000, credits: 299 }));
|
||||
check('model: a minerals-only wallet (old economy) does NOT afford a credit build', !canAfford(cargo.builds['cargo-bay-8'], 100000));
|
||||
// The cargo bays cost BOTH resources — trade income (credits) + the mining
|
||||
// hold (minerals) — so the affordability wallet must cover both lines.
|
||||
check('model: cargo bays cost credits + minerals (8: 500 cr / 200 min, 12: 800 cr / 350 min, 16: 1200 cr / 500 min)',
|
||||
cargo.builds['cargo-bay-8'].cost.credits === 500 && cargo.builds['cargo-bay-8'].cost.minerals === 200 &&
|
||||
cargo.builds['cargo-bay-12'].cost.credits === 800 && cargo.builds['cargo-bay-12'].cost.minerals === 350 &&
|
||||
cargo.builds['cargo-bay-16'].cost.credits === 1200 && cargo.builds['cargo-bay-16'].cost.minerals === 500);
|
||||
check('model: cargo bays cost BOTH lines (credits AND minerals)', costLines(cargo.builds['cargo-bay-8']).some((l) => l.res === 'credits') && costLines(cargo.builds['cargo-bay-8']).some((l) => l.res === 'minerals'));
|
||||
check('model: a full wallet affords the 8-bay build (500 cr + 200 min)', canAfford(cargo.builds['cargo-bay-8'], { minerals: 200, credits: 500 }));
|
||||
check('model: a credits wallet BELOW the cost does not afford it', !canAfford(cargo.builds['cargo-bay-8'], { minerals: 100000, credits: 499 }));
|
||||
check('model: a minerals wallet BELOW the cost does not afford it', !canAfford(cargo.builds['cargo-bay-8'], { minerals: 199, credits: 100000 }));
|
||||
check('model: a minerals-only wallet (old economy) does NOT afford a credits+minerals build', !canAfford(cargo.builds['cargo-bay-8'], 100000));
|
||||
check('model: loadBuilds("mining") holds the five ship-upgrade builds', !!miningCat.builds['mining-arm-improved'] && !!miningCat.builds['mining-arm-advanced'] && !!miningCat.builds['mining-arm-premium'] && !!miningCat.builds['mining-storage-improved'] && !!miningCat.builds['mining-storage-advanced']);
|
||||
check('model: loadBuilds("mining") keeps registry entry (label/accent)', miningCat.label === 'Mining' && typeof miningCat.accent === 'string');
|
||||
check('model: an unknown category falls back to the default', loadBuilds('nope').id === builds.defaultCategory);
|
||||
|
|
|
|||
|
|
@ -267,7 +267,9 @@ goods, and the batch remainders, never the shops).
|
|||
- **Earning credits** = selling goods + mission/quest credit rewards + the
|
||||
bounded local batch loop. **Spending** = builds, upgrades, and buying goods.
|
||||
- **The cargo bays are the first credit sink** — the hold expands 4 → 8 → 12 → 16
|
||||
through three credit-costed ship builds (`data/builds.json → cargo-bay-8/12/16`).
|
||||
through three ship builds paid in credits + minerals
|
||||
(`data/builds.json → cargo-bay-8/12/16`: 500 cr + 200 min / 800 cr + 350 min /
|
||||
1200 cr + 500 min).
|
||||
- **Trading is LOCKED until the third story quest.** Until then the economy
|
||||
exists in the world (shops, prices, batches) but the buy/sell UI is gated.
|
||||
|
||||
|
|
@ -306,7 +308,7 @@ memory — and it only ever *refills* in the player's favor.
|
|||
| `js/save/SaveData.js` | Credits + cargo + **`economyStock`** (the batch remainders) captured/restored; `cleanEconomyStock` normalizes the shape; a new run clears it. |
|
||||
| `js/scenes/GameScene.js` | Owns `economyStock` (registry-backed), `spendStock()` (the reference swap), the credits HUD, quest payouts. |
|
||||
| `js/scenes/SurfaceScene.js` | Opens the `ShopView` over the shop clip; the SET DESTINATION offer from a scout exit. |
|
||||
| `data/builds.json` | The **cargo bays** (`cargo-bay-8/12/16`) — the first credit sink. |
|
||||
| `data/builds.json` | The **cargo bays** (`cargo-bay-8/12/16`) — the first credit sink (credits + minerals). |
|
||||
| `dev/economy.test.mjs` | The engine's invariants: the strict 1:1 assignment, hub-pool completeness, determinism, origin-only sales, the loop, the distance bands, the shop floors, and the **anti-loop sweep** (zero positive same-shop spreads, every system × class). |
|
||||
| `dev/cargo.test.mjs` | The hold's rules + the `tradePreview` caps (credits/cargo/**stock**, sell→buy in one confirm, the buyback exemption from the batch). |
|
||||
| `dev/shop-ui.test.mjs` | The shop screen's LOGIC headlessly: sell, buy, the **daily batch** ("N left" → clamp → SOLD OUT → engine backstop), scroll/clip, the two caps, the buyback, the scout panel + set-destination. |
|
||||
|
|
|
|||
|
|
@ -5175,9 +5175,9 @@ export class GameScene extends Phaser.Scene {
|
|||
}
|
||||
// cost — the full amount, paid up front. The cost is a { res: amount }
|
||||
// map (data/builds.json → cost): the planet builds pay MINERALS, the
|
||||
// cargo bays pay CREDITS (the trade income buys the hold expansion).
|
||||
// Each line is checked + debited from its own wallet (ship.minerals /
|
||||
// ship.credits).
|
||||
// cargo bays pay CREDITS + MINERALS (trade income + the mining hold buy
|
||||
// the expansion). Each line is checked + debited from its own wallet
|
||||
// (ship.minerals / ship.credits).
|
||||
const cost = def.cost ?? null;
|
||||
if (cost && typeof cost === 'object') {
|
||||
const mineralsCost = Number(cost.minerals ?? 0);
|
||||
|
|
|
|||
|
|
@ -167,8 +167,8 @@ export class BuildWindow extends Phaser.GameObjects.Container {
|
|||
this.credits = typeof o.credits === 'function' ? o.credits : () => 0;
|
||||
// Affordability wallet: the build's cost is a { res: amount } map
|
||||
// (data/builds.json → cost) — the planet builds pay MINERALS, the cargo
|
||||
// bays pay CREDITS (the trade income). canAfford() checks every line
|
||||
// against this wallet, so both currencies are covered.
|
||||
// bays pay CREDITS + MINERALS. canAfford() checks every line against
|
||||
// this wallet, so both currencies are covered.
|
||||
this._wallet = () => ({ minerals: this.minerals(), credits: this.credits() });
|
||||
this.tetherLevel = typeof o.tetherLevel === 'function' ? o.tetherLevel : () => 0;
|
||||
this.researchUnlocked = typeof o.researchUnlocked === 'function' ? o.researchUnlocked : () => false;
|
||||
|
|
|
|||
Loading…
Reference in New Issue