64 lines
2.6 KiB
JavaScript
64 lines
2.6 KiB
JavaScript
// 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;
|
|
}
|