// 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); }