orbit/data/economy.json

63 lines
6.1 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"_comment": "ECONOMY TUNING (the knobs, not the data). goods.json is WHAT exists; this file is HOW it prices and stocks. MODEL v2 — ONE WORLD, ONE GOOD (full version in docs/ECONOMY.md §5): every tradeable good has exactly one ORIGIN system (seeded strict assignment, 'origin-assign' pass in Economy.buildEconomy) — the single world whose shop sells it, cheap, in a DAILY BATCH. Every other system's shop does NOT sell it. The catalog's remainder (goods with no origin, the HUB POOL) is resold by stations/capitals at standard price (distance measured to the nearest hub). SELL price = baseValue × distanceBand(hops to origin) × (1 + demandBonus if the class wants it), CAPPED at the shop's own sale price for the good (no shop may ever be a positive same-shop spread). The banded distance term is the DOMINANT factor in profit; planet type (demand) is a secondary modifier. Prices are fixed per (good, location), a pure function of the seed; the only state is the day's remaining batch (save: economyStock). Credits are the go-between — buying spends them, selling earns them, no barter.",
"shop": {
"_comment": "Floor size per settlement KIND (model v2). A WORLD's floor is exactly ONE product — its system's signature good (the strict 1:1 origin assignment; see economy.json → 'stock'). Stations and capitals (hubs) resell from the HUB POOL — wider floors (variety), standard price.",
"minStock": 1,
"maxStock": 3,
"stockByKind": {
"capital": { "min": 12, "max": 16 },
"deepSpaceStation": { "min": 10, "max": 16 }
}
},
"pricing": {
"_comment": "Multipliers are dimensionless and multiply baseValue. ORIGIN sale (the good's home world, batch-limited) = baseValue × (1 − originDiscount) × jitter — the only cheap source in the galaxy. HUB resale (station/capital, hub-pool goods only) = baseValue × hubPriceFactor × jitter — standard, never below origin. SELL price (the shop pays you) = baseValue × distanceBand(min(hops to origin, band)) × (1 + demandBonus if the class wants it) × jitter, CAPPED at the shop's own sale price for that good (anti-loop). `distanceBands` are ascending minHops → factor; the band with the largest minHops ≤ hops wins (no cap — the jump tree's diameter ~17 hops is the natural ceiling). The CURRENT factors are the HALVED-MARGIN curve (f′ = 0.25 + f/2 applied to the original ×1.0 / ×1.8 / ×3.2 / ×5.0 / ×7.0): with the origin buy at ×0.5, profit per unit ≈ (factor − 0.5) × base — ≈ 0.25× / 0.65× / 1.35× / 2.25× / 3.25× of base before the demand bonus — so every band nets exactly half the original margin while distance stays the dominant term. `jitter` is a per-good, per-place seeded wobble (±%) so no two shops feel formulated.",
"originDiscount": 0.50,
"hubPriceFactor": 1.00,
"demandBonus": 0.10,
"distanceBands": [
{ "minHops": 0, "factor": 0.75 },
{ "minHops": 2, "factor": 1.15 },
{ "minHops": 4, "factor": 1.85 },
{ "minHops": 7, "factor": 2.75 },
{ "minHops": 11, "factor": 3.75 }
],
"jitter": 0.10
},
"stock": {
"_comment": "THE TIME-GATED BATCH — the only stateful part of the economy (and the only bookkeeping a shop needs). Each ORIGIN world's signature good comes to market as a daily batch of `dailyBatch` units; a DAY is `dayMs` of wall-clock time past `epoch`, so the batch regenerates while the player is away (the local buy→sell loop in the origin system — buy at the world, sell to the same-system station — is a BOUNDED pocket change, never infinite money, while long-haul SELLs stay unlimited: the market is a sink). The sell-back side is NEVER stock-limited. Save state per system: { day, left } — tiny, save-clone-safe (js/economy/Stock.js).",
"dailyBatch": 6,
"dayMs": 3600000,
"epoch": "2026-01-01T00:00:00Z"
},
"cargo": {
"_comment": "The hold is a set of fixed BAYS — one good per bay (unitPerGood=1). `capacitySource` is the UNLOCKED-bay count (ship.stats.cargoHold). `maxSlots` is the fixed grid the shop UI always shows (16 slots) — locked bays are just capacity the ship hasn't unlocked yet. You CARRY goods between shops; that's the whole game loop.",
"capacitySource": "ship.stats.cargoHold",
"maxSlots": 16,
"unitPerGood": 1
},
"credits": {
"_comment": "The trade currency (the go-between). Displayed next to the minerals HUD (upper-right). Player starts at 0 (startingCredits). Earning credits = selling goods + mission/quest credit rewards + the bounded local batch loop. Spending = builds, upgrades, and buying goods. Buying spends credits; selling earns them.",
"startingCredits": 0,
"display": { "nextTo": "mineralHud", "anchor": "upper-right" },
"tradingLockedUntilQuest": 3,
"earning": ["sellGoods", "questRewards", "localBatchLoop", "miningLaserGems (later)"]
},
"restock": {
"_comment": "Prices + FLOOR are NON-persistent (re-derived from the seed — no per-player sold/bought counters, 'you bought out their stock' bookkeeping lives ONLY in the day's batch: stock.dailyBatch/remaining). A shop's stock and prices are a pure function of (seed, place, economy version) — the batch remainder is the one saved number per origin system.",
"policy": "deterministic-derivation + daily-batch",
"stockIsPureFunction": true,
"note": "Reopening a shop re-derives identical floor & prices; the origin's batch regenerates on the day clock."
},
"reputation": {
"_comment": "DEFERRED (decision #3 — wanted, later). Hook: standing with a place's owner faction nudges prices (good standing = better deal). `maxPriceShift` is the max +/- fraction of price. Wired to js/reputation/Reputation.js standingFor(place). OFF for v1.",
"enabled": false,
"maxPriceShift": 0.08
},
"faction": {
"_comment": "DEFERRED (decision #3). Hook: some factions may levy a tariff or patron a good class. `tariffRange` is the +/- fraction. `patronGoods` (a future map of factionId -> [goodId]) lets a faction pay premium for its favored goods. Left empty — populate when factions take an economic role.",
"tariffRange": 0.05,
"patronGoods": {}
},
"version": 2
}