From 4ee2a3e5d355ae9141c1dad8d20bbae77bab0702 Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Sun, 23 Aug 2026 20:50:06 -0400 Subject: [PATCH] Dropped treasure is seen falling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit treasureDropped and objectDropped played as nothing — the gold simply teleported from chest to floor between frames. A drop now glints (the spark blooming where it lands, a beat after the blow when combat knocked it loose), and a wizard dropping at their own feet takes the cutaway: a third-person shot of them setting the prize down — or spilling it. When the reel's wizard strikes the spill loose from someone else, the attack-facing already has the victim in frame, so the treasure falls on camera. Co-Authored-By: Claude Fable 5 --- packages/web/src/Replay.svelte | 5 ++++- packages/web/src/fpv/fx3d.ts | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/web/src/Replay.svelte b/packages/web/src/Replay.svelte index 7cec500..74ab34e 100644 --- a/packages/web/src/Replay.svelte +++ b/packages/web/src/Replay.svelte @@ -294,7 +294,10 @@ const to = (e as { to: { x: number; y: number } }).to; if (to.x !== me.position.x || to.y !== me.position.y) return to; } - if (e.type === "treasurePickedUp" && "player" in e && (e as { player: string }).player === povId) { + if ( + (e.type === "treasurePickedUp" || e.type === "treasureDropped" || e.type === "objectDropped") && + "player" in e && (e as { player: string }).player === povId + ) { const at = (e as { at: { x: number; y: number } }).at; return { ...at, self: at.x === me.position.x && at.y === me.position.y }; } diff --git a/packages/web/src/fpv/fx3d.ts b/packages/web/src/fpv/fx3d.ts index e1de799..4217c28 100644 --- a/packages/web/src/fpv/fx3d.ts +++ b/packages/web/src/fpv/fx3d.ts @@ -210,6 +210,16 @@ export function fpFxForEvents( out.push({ fx: { id: nextId++, kind: "flash", color: "#e0b34a", peak: 0.22, t0: 0, dur: 550 }, delay: i * 300 + 120 }); } } + if ((e.type === "treasureDropped" || e.type === "objectDropped") && "at" in e) { + // Gold hits the flags: a glint where it lands, a beat after the + // blow when one knocked it loose. + const at = (e as { at: { x: number; y: number } }).at; + const spilled = events.some((x) => x.type === "attackResolved" || x.type === "damaged"); + out.push({ + fx: { id: nextId++, kind: "impact", art: "spark", at: { x: at.x + 0.5, y: at.y + 0.5 }, t0: 0, dur: 500 }, + delay: spilled ? 400 : 0, + }); + } if (e.type === "wallDestroyed" && "edge" in e) { const at = edgeMid((e as { edge: { cell: { x: number; y: number }; side: "N" | "E" | "S" | "W" } }).edge.cell, (e as { edge: { side: "N" | "E" | "S" | "W" } }).edge.side);