The simple economy is now the default and the old simulation is frozen as the hard model, selectable per game. A nation keeps one resource pool available in every region, fed by public production works rather than private per-region stores, and construction and training begin at once, paced by the region's spare power instead of gathering materials over days. Money is euro only: a per-inhabitant daily tax funds a treasury spent in a global market, where buy and sell lots trade against the world stock and move its price. The hard economy keeps its per-nation currencies, central banks and exchange rates. Simple games skip the price-settling warmup and economic migration; the snapshot carries the economy model, the market and the pool figures the client draws. Added the matching test suites and the design briefs under docs/simple_economy.
80 lines
3.1 KiB
JavaScript
80 lines
3.1 KiB
JavaScript
// The viewer's currency. Money is quoted in whatever nation the player runs, so
|
||
// every money string reads in the right unit. The symbol is set from the
|
||
// snapshot; until then a neutral mark stands in.
|
||
|
||
import { groupDigits } from "../../shared/text_format.js";
|
||
|
||
let symbol = "¤";
|
||
// Every nation's currency and the instant rate from ours, indexed by civ, so a
|
||
// foreign figure can be shown in its own money with our equivalent beside it.
|
||
let currencies = [];
|
||
let rates = [];
|
||
let viewer = -1;
|
||
// True when the snapshot's nations all share one currency (the simple economy's
|
||
// euro). There is then nothing to convert: every figure is already in the same
|
||
// money, so foreign figures carry no parenthetical equivalent.
|
||
let singleCurrency = false;
|
||
|
||
export function setCurrency(currency) {
|
||
if (currency && currency.symbol) symbol = currency.symbol;
|
||
}
|
||
|
||
// The per-nation currency list and the snapshot's instant exchange rates, so
|
||
// any figure can be re-quoted in the nation it belongs to.
|
||
export function setCurrencyBook(list, exchangeRates, viewerCiv) {
|
||
currencies = Array.isArray(list) ? list : [];
|
||
rates = Array.isArray(exchangeRates) ? exchangeRates : [];
|
||
viewer = Number.isInteger(viewerCiv) ? viewerCiv : -1;
|
||
const codes = new Set(currencies.map((entry) => entry && entry.code).filter(Boolean));
|
||
singleCurrency = currencies.length > 0 && codes.size === 1;
|
||
}
|
||
|
||
export function currencySymbol() {
|
||
return symbol;
|
||
}
|
||
|
||
// A money amount in the viewer's currency, with the digits grouped by
|
||
// non-breaking spaces. Every panel quotes currency through here, so the figures
|
||
// read the same everywhere.
|
||
export function formatMoney(value) {
|
||
return `${symbol}${groupDigits(Math.round(value))}`;
|
||
}
|
||
|
||
// A signed money amount, for budget lines that show a movement.
|
||
export function formatMoneySigned(value) {
|
||
return `${value < 0 ? "−" : "+"}${formatMoney(Math.abs(value))}`;
|
||
}
|
||
|
||
export function viewerCurrencyCiv() {
|
||
return viewer;
|
||
}
|
||
|
||
export function currencyFor(civ) {
|
||
// One shared currency (the euro) means there is nothing to re-quote: callers
|
||
// treat every nation as already in the viewer's money.
|
||
if (singleCurrency) return null;
|
||
return currencies[civ] || null;
|
||
}
|
||
|
||
// How many units of `civ`'s currency one unit of the viewer's buys, at the
|
||
// snapshot's instant rate. One for our own currency, or when it is unknown.
|
||
export function rateToNational(civ) {
|
||
if (singleCurrency || civ === viewer) return 1;
|
||
const entry = rates[civ];
|
||
if (entry && Number.isFinite(entry.rate)) return entry.rate;
|
||
const mine = currencies[viewer];
|
||
const theirs = currencies[civ];
|
||
if (mine && theirs && theirs.value > 0) return (mine.value || 1) / theirs.value;
|
||
return 1;
|
||
}
|
||
|
||
// A money amount belonging to `civ` as plain text: their money first, then ours
|
||
// in parentheses when they differ. `format` renders a bare number, so callers
|
||
// keep their own rounding and compacting.
|
||
export function moneyText(value, civ, format = (v) => groupDigits(Math.round(v))) {
|
||
const ours = `${currencySymbol()}${format(value)}`;
|
||
const info = currencyFor(civ);
|
||
if (!info || civ === viewer) return ours;
|
||
return `${info.symbol}${format(value * rateToNational(civ))} (${ours})`;
|
||
}
|