// screen-level effects + the 17 animation trigger dispatcher import { G } from "./state.js"; import { confettiBurst, heartFloat, moraleWave, revenueRain } from "./particles.js"; import { sfx } from "./audio.js"; export function dim(on) { G.els.dim.classList.toggle("hidden", !on); } export function redFlash() { const el = G.els.flash; el.classList.remove("on"); void el.offsetWidth; el.classList.add("on"); } export function edgePulse(on) { G.els["edge-pulse"].classList.toggle("on", on); } export function hrStamp() { const el = G.els.stamp; el.classList.remove("hidden"); el.style.animation = "none"; void el.offsetWidth; el.style.animation = ""; sfx.stamp(); setTimeout(() => el.classList.add("hidden"), 950); } export function wipe(midCallback) { const el = G.els.wipe; el.classList.remove("go"); void el.offsetWidth; el.classList.add("go"); setTimeout(midCallback, 350); // swap scenes while fully covered setTimeout(() => el.classList.remove("go"), 750); } export function fadeBlack(midCallback, hold = 1000) { const el = G.els.wipe; el.style.transition = "transform .01s"; el.style.transform = "translateX(0)"; el.style.opacity = 0; el.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 400, fill: "forwards" }); setTimeout(() => { midCallback(); el.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 400, fill: "forwards" }); setTimeout(() => { el.style.transform = "translateX(-100%)"; el.style.opacity = 1; el.style.transition = ""; }, 450); }, 400 + hold); } // the AI's animation enum → visual dispatch (ANIMATIONS.md) const NPC_ANIM_POSE = { npc_happy: "idle", npc_angry: "shake", npc_confused: "idle", npc_devastated: "headdown", npc_celebrating: "idle", npc_hiding: "slump", npc_smug: "lean", npc_suspicious: "lean", npc_crying: "slump", npc_grateful: "idle", }; export function playOutcome(trigger, npcId, world) { const npc = npcId && world.npcs[npcId]; switch (trigger) { case "disaster_flash": redFlash(); sfx.disaster(); break; case "revenue_rain": revenueRain(); sfx.moneyUp(); break; case "heart_float": if (npc) heartFloat(npc.x, npc.y - 44); sfx.gift(); break; case "bribery_envelope": sfx.click(); break; case "hr_stamp": hrStamp(); break; case "morale_drop_wave": moraleWave(world.npcs); sfx.moneyDown(); break; case "confetti_burst": confettiBurst(); sfx.win(); break; default: if (npc && NPC_ANIM_POSE[trigger]) { npc.setPose(NPC_ANIM_POSE[trigger]); if (trigger === "npc_celebrating" || trigger === "npc_happy") { npc.sprite.animate( [{ transform: "translateY(0)" }, { transform: "translateY(-6px)" }, { transform: "translateY(0)" }], { duration: 320, iterations: 2, easing: "steps(3)" }); } } } }