Blind reviews over d2b40ec..HEAD (engine / web / server+deploy). Orphaned doc comments rejoined their functions; the swap-meet tradables collapsed from four pasted deriveds to one (killing the "the's treasure" label); FEAR's aura and banner now share the engine's own dreadDistance; the long-press peek got one home; rulebook.ts stopped wearing JSON quotes; process-named tests and war-story comments now state the constraints they pin; the protocol doc caught up to its handlers; verify-ledgers.sh can actually count failures; the runbook learned about the determinism gate and the nightly backups. No behavior changes — 255 tests and all 48 production ledgers replay identically. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
72 lines
2.5 KiB
Svelte
72 lines
2.5 KiB
Svelte
<script lang="ts" module>
|
|
/** The color states a door can wear (a wall wears none). */
|
|
export type LockState = "removed" | "jammed" | "held" | "ajar";
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
import { holdToPeek } from "./peek";
|
|
// A wall or door on an edge, exactly as the board draws it. Wall-segment
|
|
// effects (locks picked, jammed, removed; doors held) are color states of
|
|
// this one glyph — the game has never used tokens for them.
|
|
let { x, y, kind, state, lock = null, title = null, damage = 0, onpeek }: {
|
|
x: number; y: number; kind: "V" | "H";
|
|
state: "wall" | "door";
|
|
lock?: LockState | null;
|
|
title?: string | null;
|
|
/** Battle damage taken so far (walls fall at 20, doors at 15). */
|
|
damage?: number;
|
|
/** Press-and-hold (touch has no hover): report the tooltip's text. */
|
|
onpeek?: (tip: string) => void;
|
|
} = $props();
|
|
const CELL = 48;
|
|
const WALL = 7;
|
|
const cls = $derived(state === "door" ? `door${lock ? ` ${lock}` : ""}` : "wall");
|
|
// Every segment tells its points — the game's own word: "A wall takes 20
|
|
// points of damage to destroy; a door takes 15."
|
|
const needed = $derived(state === "door" ? 15 : 20);
|
|
const hp = $derived(damage > 0
|
|
? `${Math.max(0, needed - damage)} of ${needed} points left`
|
|
: `${needed} points to destroy`);
|
|
const tip = $derived(`${title ?? (state === "door" ? "a locked door" : "a wall")} — ${hp}`);
|
|
|
|
const { press, release } = holdToPeek(() => onpeek?.(tip));
|
|
</script>
|
|
|
|
{#if kind === "V"}
|
|
<rect
|
|
x={(x + 1) * CELL - WALL / 2} y={y * CELL - WALL / 2}
|
|
width={WALL} height={CELL + WALL}
|
|
class={cls}
|
|
role="img" onpointerdown={press} onpointerup={release} onpointerleave={release}
|
|
><title>{tip}</title></rect>
|
|
{:else}
|
|
<rect
|
|
x={x * CELL - WALL / 2} y={(y + 1) * CELL - WALL / 2}
|
|
width={CELL + WALL} height={WALL}
|
|
class={cls}
|
|
role="img" onpointerdown={press} onpointerup={release} onpointerleave={release}
|
|
><title>{tip}</title></rect>
|
|
{/if}
|
|
|
|
<style>
|
|
.wall {
|
|
fill: #f2ecd8;
|
|
stroke: #2b2218;
|
|
stroke-width: 1.6;
|
|
}
|
|
.door {
|
|
fill: #8b5a2b;
|
|
stroke: #2b2218;
|
|
stroke-width: 1.4;
|
|
rx: 2;
|
|
}
|
|
/* Lock removed: pale, an open doorway forever. */
|
|
.door.removed { fill: #d4bd8e; }
|
|
/* Lock jammed: near-black, sealed. */
|
|
.door.jammed { fill: #3a2a18; stroke: #14100b; }
|
|
/* Picked or keyed open until end of turn. */
|
|
.door.ajar { fill: #d4bd8e; stroke-dasharray: 5 3; }
|
|
/* Held open: a wizard stands propping it. */
|
|
.door.held { fill: #d4bd8e; stroke: #2e7d32; }
|
|
</style>
|