Boobytrap decoys die their own deaths

Stepping on a face-down token flips it: a blank leaves the board the
moment it is discovered, instead of all four indicators lingering
until the real one detonates. The trap itself still waits, the caster
still strolls over everything unharmed, and the chronicle narrates
the flip so the table learns which squares stopped being scary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
Eric Wagoner
2026-08-27 22:52:09 -04:00
co-authored by Claude Fable 5
parent e388691858
commit 5f1eda2731
3 changed files with 56 additions and 2 deletions
+9 -2
View File
@@ -662,6 +662,7 @@ export type GameEvent =
| { type: "stuckInSlime"; player: PlayerId; at: Cell }
| { type: "boobytrapPlaced"; caster: PlayerId; cells: Cell[] }
| { type: "boobytrapSprung"; player: PlayerId; at: Cell }
| { type: "boobytrapBlank"; player: PlayerId; at: Cell }
| { type: "boobytrapPlacedPrivate"; visibleTo: PlayerId; realCell: Cell }
| { type: "objectsGlued"; caster: PlayerId; at: Cell; turns: number }
| { type: "safeCreated"; caster: PlayerId; at: Cell }
@@ -4287,14 +4288,20 @@ function doMove(prev: GameState, direction: Side, over = false): CommandResult {
// Armed ambushes may spring on this step.
checkAmbushes(state, events, p, { movedFrom: from });
// BOOBYTRAP: the real token detonates under anyone but its caster.
// BOOBYTRAP: the real token detonates under anyone but its caster; a
// blank token is flipped by the step that finds it and leaves the board
// alone — each decoy dies its own death.
for (const trap of [...state.boobytraps]) {
if (trap.casterId === p.id) continue;
if (cellKey(p.position) === trap.realKey) {
const here = cellKey(p.position);
if (here === trap.realKey) {
state.boobytraps = state.boobytraps.filter((t) => t !== trap);
events.push({ type: "boobytrapSprung", player: p.id, at: p.position });
applyDamage(state, events, p, 4, "boobytrap", null, "physical");
checkVictory(state, events);
} else if (trap.cells.some((c) => cellKey(c) === here)) {
trap.cells = trap.cells.filter((c) => cellKey(c) !== here);
events.push({ type: "boobytrapBlank", player: p.id, at: p.position });
}
}