Files
Country-Game---The-Desk/web/js/engine/modifiers.js
T

85 lines
3.5 KiB
JavaScript

// Effects and timed modifiers. Card choices end up here.
//
// Effect shapes:
// { stat, delta } instant shift of an indicator or economy variable
// { stat, delta, days } shift spread evenly over `days` (then the value mean-reverts)
// { stat, delta, bias: true, days? } offset on the stat's *target* for `days` (permanent if omitted)
// { sector, delta[, days][, bias] } same, on a sector's quality
// { revenue: "income"|"corporate"|"vat", delta } change tax rate (rate points), permanent
// { revenue: "other", delta } change other revenue (% of GDP), permanent
// { oneOff: pct } one-time cost in % of GDP (negative = windfall)
// { extraSpending: delta } permanent extra spending in % of GDP
import { IND_IDS, VAR_IDS, TAX_IDS, clamp } from "./state.js";
function groupOf(effect, state) {
if (effect.sector !== undefined) return state.sectors[effect.sector] ? ["sector", effect.sector] : null;
if (IND_IDS.includes(effect.stat)) return ["ind", effect.stat];
if (VAR_IDS.includes(effect.stat)) return ["var", effect.stat];
return null;
}
function shift(state, bal, group, key, delta) {
if (group === "ind") state.indicators[key] = clamp(state.indicators[key] + delta, 0, 100);
else if (group === "sector") state.sectors[key].quality = clamp(state.sectors[key].quality + delta, 0, 100);
else {
const v = bal.vars[key];
state.economy[key] = clamp(state.economy[key] + delta, v.min, v.max);
}
}
export function applyEffect(state, bal, effect) {
if (effect.stat !== undefined || effect.sector !== undefined) {
const found = groupOf(effect, state);
if (!found) return false;
const [group, key] = found;
if (effect.bias) {
state.modifiers.push({ type: "bias", group, key, value: effect.delta, remaining: effect.days ?? null });
} else if (effect.days > 0) {
state.modifiers.push({ type: "shift", group, key, perDay: effect.delta / effect.days, remaining: effect.days });
} else {
shift(state, bal, group, key, effect.delta);
}
return true;
}
const e = state.economy;
if (effect.revenue !== undefined) {
if (TAX_IDS.includes(effect.revenue)) e.taxes[effect.revenue] = Math.max(0, e.taxes[effect.revenue] + effect.delta);
else if (effect.revenue === "other") e.otherRevenue = Math.max(0, e.otherRevenue + effect.delta);
else return false;
return true;
}
if (effect.oneOff !== undefined) {
e.debt = Math.max(0, e.debt + (effect.oneOff / 100) * e.gdp);
return true;
}
if (effect.extraSpending !== undefined) {
e.extraSpending += effect.extraSpending;
return true;
}
return false;
}
// Start of each day: apply the spread-out shifts.
export function applyShifts(state, bal) {
for (const m of state.modifiers) {
if (m.type !== "shift") continue;
shift(state, bal, m.group, m.key, m.perDay);
m.remaining -= 1;
}
state.modifiers = state.modifiers.filter((m) => m.type !== "shift" || m.remaining > 0);
}
// Sum of active target offsets for one stat.
export function biasFor(state, group, key) {
let sum = 0;
for (const m of state.modifiers) if (m.type === "bias" && m.group === group && m.key === key) sum += m.value;
return sum;
}
// End of each day: age timed biases.
export function ageBias(state) {
for (const m of state.modifiers) if (m.type === "bias" && m.remaining !== null) m.remaining -= 1;
state.modifiers = state.modifiers.filter((m) => m.type !== "bias" || m.remaining === null || m.remaining > 0);
}