Idiot enforces its card (rev 23) + attack sight-line tracing

Rules rev 23 — IDIOT, per the card and FAQ:
- No handling items: pick up / drop of treasures and objects refused
  (dropping was the exploit: capturing a stolen treasure on your own home,
  or dropping your own treasure underfoot for an instant cure)
- No punching, no thrown dagger / large rock (attacks on players)
- No effect on a victim already carrying one of their own treasures
Ungated (permissive): counteractions are now castable while idiotized (the
one thing the card expressly allows — the gate wrongly blocked them), and
goal-aiding spells (IDIOT_AIDS: destroy-wall, teleport, mad-dash, ...) per
the FAQ's 'you could, however, destroy a wall'.

Sight tracing: while an LOS attack sits on the stack, the board draws the
line it traveled — straight when direct, leg by leg through both warp
mouths (with pulsing rings) when the maze's wraparound carried it. Engine
traceSight/traceSightFor/stackSightTrace; overlay in Board.svelte; shown
live and in replays. Verified against H3PC's cross-board Idiot cast.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
This commit is contained in:
Eric Wagoner
2026-08-17 19:03:09 -04:00
co-authored by Claude Fable 5
parent 7372bfc5e8
commit cdeb3d5103
10 changed files with 290 additions and 24 deletions
+6 -1
View File
@@ -2,6 +2,7 @@
import Board from "./Board.svelte";
import { humanize } from "./net.svelte";
import { scheduleFx, type BoardFx } from "./fx";
import { stackSightTrace } from "@wizwar/engine";
import type { GameEvent, GameView } from "@wizwar/engine";
let {
@@ -21,6 +22,10 @@
);
const atEnd = $derived(idx >= steps.length - 1);
// The reel draws the same sight line the live table shows for an LOS
// attack in progress, so a replay-watcher can see how a spell reached them.
const sightTrace = $derived(stackSightTrace(step.view));
/** Each step's spells flare on the reel exactly as they did at the table. */
let boardFx = $state<BoardFx[]>([]);
$effect(() => {
@@ -61,7 +66,7 @@
<button class="replay-skip" onclick={onclose}>{atEnd ? "back to the game" : "skip to now"}</button>
</header>
<div class="replay-board">
<Board view={step.view} effects={boardFx} />
<Board view={step.view} effects={boardFx} {sightTrace} />
</div>
<div class="replay-caption">
<strong>{step.actor}</strong>