// Ways the term can end early. Checked once per day after the economy has moved. // // default debt above the limit: immediate // impeachment civil rights and opinion both very low for N days in a row: certain // coup army loyalty and stability both very low: a daily chance that grows each day in the zone // revolution unrest very high and opinion very low: same growing daily chance // // Entering a danger zone queues an urgent telegram (state.alerts) and pauses the game // until the player acknowledges it. state.risk counts the days spent in each zone. import { nextFloat } from "./rng.js"; function alert(state, kind) { state.alerts.push({ kind, day: state.day }); state.pending.alert = true; } // Returns the game-over type or null. Mutates state.risk, state.alerts and the RNG. export function checkGameOver(state, bal) { const g = bal.gameOver; const ind = state.indicators; const risk = state.risk; const debtRatio = (state.economy.debt / state.economy.gdp) * 100; // Zone bookkeeping: count consecutive days inside, fade (or reset) outside. const track = (name, inZone, fade) => { if (inZone) { risk[name] += 1; if (risk[name] === 1) alert(state, name); } else { risk[name] = fade === "reset" ? 0 : Math.max(0, risk[name] - fade); } }; const chance = (name, perDay) => risk[name] > 0 && nextFloat(state) < Math.min(1, perDay * risk[name]); if (debtRatio >= g.default.warnAbove) { if (!risk.defaultZone) { risk.defaultZone = true; alert(state, "default"); } } else if (debtRatio < g.default.warnAbove - 10) { risk.defaultZone = false; } const inImpeachment = ind.civilRights < g.impeachment.civilRightsBelow && ind.opinion < g.impeachment.opinionBelow; const inCoup = (ind.armyLoyalty < g.coup.armyBelow && ind.stability < g.coup.stabilityBelow) || ind.armyLoyalty < (g.coup.armyAlone ?? 0); const inRevolution = ind.unrest > g.revolution.unrestAbove && ind.opinion < g.revolution.opinionBelow; track("impeachment", inImpeachment, "reset"); track("coup", inCoup, 1); track("revolution", inRevolution, 1); if (debtRatio > g.default.debtAbove) return "default"; if (risk.impeachment >= g.impeachment.days) return "impeachment"; if (inCoup && chance("coup", g.coup.chancePerDay)) return "coup"; if (inRevolution && chance("revolution", g.revolution.chancePerDay)) return "revolution"; return null; } // The player has read the telegram at the front of the queue. export function dismissAlert(state) { state.alerts.shift(); state.pending.alert = state.alerts.length > 0; }