A waterwall tapped onto a slime washes it: the tap picks the face across the caster's approach (B8G9)

The flash for a corridor-line card no longer names wizards, bushes and
slimes as its targets; it gives the card's own line hint.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
Eric Wagoner
2026-09-23 22:59:14 -04:00
co-authored by Claude Fable 5.1
parent 0244cffb4b
commit 6c29f750fc
+28 -2
View File
@@ -512,7 +512,7 @@
"destroy-wall": "click a wall or door to destroy it", "destroy-wall": "click a wall or door to destroy it",
"illusion-wall": "click an open corridor line for the false wall", "illusion-wall": "click an open corridor line for the false wall",
"wall-of-fire": "click a corridor line for the fire", "wall-of-fire": "click a corridor line for the fire",
"waterwall": "click a corridor line — the wave collapses at once", "waterwall": "click a corridor line, or a slime to wash it away — the wave collapses at once",
"pick-lock": "click a locked door", "pick-lock": "click a locked door",
"master-key": "click a locked door — or Display it once and walk through every lock", "master-key": "click a locked door — or Display it once and walk through every lock",
"jam-lock": "click a door to jam its lock solid", "jam-lock": "click a door to jam its lock solid",
@@ -1050,10 +1050,25 @@
clearSelection(); clearSelection();
return; return;
} }
// "A WATERWALL ... will wash the slime away": the card wants a corridor
// line, so a tap on the slime itself picks the square's face nearest the
// caster and the wave breaks against the gel. Sight is still the engine's
// to judge.
if (selectedCard?.cardId === "waterwall" && filled === "slime") {
dispatch(withMods({
type: "cast", instanceId: selectedCard.instanceId,
target: { kind: "edge", cell, side: slimeFace(view.board, cell, me.position) },
}));
clearSelection();
return;
}
// A card in hand is aimed, not walked with: a tap on a bare square // A card in hand is aimed, not walked with: a tap on a bare square
// while holding one is a miss, never a stride into whatever is there. // while holding one is a miss, never a stride into whatever is there.
if (selectedCard) { if (selectedCard) {
net.flash(`${cardDef(selectedCard.cardId).name} is aimed by tapping a wizard, a creature, a bush, or a slime — put the card down to walk`); const name = cardDef(selectedCard.cardId).name;
net.flash(EDGE_CARDS.has(selectedCard.cardId)
? `${name} is aimed at a line between squares: ${EDGE_HINTS[selectedCard.cardId] ?? "tap a lit line"}`
: `${name} is aimed by tapping a wizard, a creature, a bush, or a slime — put the card down to walk`);
return; return;
} }
// A cell click is a move if the cell is one legal step away (the server // A cell click is a move if the cell is one legal step away (the server
@@ -1191,6 +1206,17 @@
} }
} }
/** The face of a slime square a waterwall breaks against when the square
* itself is tapped. The wave washes two squares out from both sides of
* its line, so the line runs across the caster's approach rather than
* along it: a tap means "wash the slime", not "wash me". Walls and the
* board's rim are never chosen while another face is free. */
function slimeFace(board: GameView["board"], slime: { x: number; y: number }, from: { x: number; y: number }): Side {
const across: Side[] = Math.abs(from.x - slime.x) >= Math.abs(from.y - slime.y) ? ["N", "S", "W", "E"] : ["W", "E", "N", "S"];
const free = across.filter((side) => { const t = stepTarget(board, slime, side); return t.kind !== "blocked" || t.by !== "wall"; });
return free[0] ?? across[0]!;
}
function clickEdge(cell: { x: number; y: number }, side: Side) { function clickEdge(cell: { x: number; y: number }, side: Side) {
if (punchWallMode) { if (punchWallMode) {
dispatch({ type: "punchWall", cell, side }); dispatch({ type: "punchWall", cell, side });