Files
Battle-for-Tismo/client/js/currency.js
T
adrien d5305da449 Gave the world a simple economy: one pool per nation and a global market
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.
2026-09-25 14:58:49 +02:00

80 lines
3.1 KiB
JavaScript
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.
// 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})`;
}