The camera audit: wherever the fx will play, the eyes already are

Eric asked what else happens off-camera, and the audit found a family:
a wizard's creature marching or clawing, objects dragged from afar,
punches (always same-square, so also invisible), treasure grabbed at
one's own feet, the Thumb of God's landing. Rather than patch each,
one rule retires the class: when nothing else aims the reel's own
wizard's step, the camera aims wherever the fx layer is about to play
its first impact or projectile landing — so every effect that exists,
and every one added later, gets watched by construction. Creature
marches and treasure grabs (which play no fx) get explicit aim rungs;
own-square deeds keep taking the cutaway.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-23 20:44:29 -04:00
co-authored by Claude Fable 5
parent 698e975b6d
commit df20e35124
+23
View File
@@ -284,6 +284,29 @@
// cutaway: step outside yourself and watch. // cutaway: step outside yourself and watch.
if (cell) return { ...cell, self: true }; if (cell) return { ...cell, self: true };
} }
// Last resort, only for the reel's own wizard's step: wherever the
// fx layer is about to play something visible — an impact, a
// projectile's landing — the eyes should already be. This covers
// every effect that exists and every one added later.
if (step.actor === povId) {
for (const e of step.events) {
if (e.type === "creatureMoved" && "by" in e && e.by === povId) {
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) {
const at = (e as { at: { x: number; y: number } }).at;
return { ...at, self: at.x === me.position.x && at.y === me.position.y };
}
}
for (const { fx } of fpFxForEvents(step.events, v, povId)) {
const spot = fx.kind === "impact" ? fx.at : fx.kind === "projectile" ? fx.to : null;
if (!spot) continue;
const cx = Math.floor(spot.x), cy = Math.floor(spot.y);
if (cx === me.position.x && cy === me.position.y) return { x: cx, y: cy, self: true };
return { x: cx, y: cy };
}
}
return null; return null;
})() as ({ x: number; y: number; self?: boolean } | null); })() as ({ x: number; y: number; self?: boolean } | null);
// A leap the legs cannot explain (first frame, teleport, the return // A leap the legs cannot explain (first frame, teleport, the return