Every wall card learns the rim (rules rev 40)
The full audit Wall of Fire started: WATERWALL crashes on a warp mouth, washing both rims inward; ILLUSION WALL hangs its scrim on a mouth (the create-wall bluff); STONE TO WATER melts a brick over a warp at both ends and breaches a plain rim wall exactly as DESTROY WALL does — far side washes out, a warp opens, the wave floods the fresh tunnel; the WARP WAND bores a temporary wraparound that closes when its wall returns; and CREATE DOOR stops hanging dead doors onto the void. Older ledgers keep their refusals and danglings, and replay so. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
f82e4625af
commit
e8df6efcde
@@ -191,6 +191,119 @@ describe("expansion terrain", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("waterwall takes a rim warp from rev 40 — the collapse washes both rims", () => {
|
||||
for (const deckRev of [39, 40]) {
|
||||
let { state } = createGame({
|
||||
playerIds: ["alice", "bob"], seed: 42, sets: ["basic", "expansion1"], deckRev,
|
||||
});
|
||||
const me = activePlayer(state);
|
||||
const other = state.players.find((p) => p.id !== me.id)!;
|
||||
const warp = state.board.warps[0]!;
|
||||
me.position = { ...warp.from.cell };
|
||||
other.position = { ...warp.to.cell };
|
||||
const ww = giveCard(state, me.id, "waterwall", "WW", 0);
|
||||
const r = applyCommand(state, me.id, {
|
||||
type: "cast", instanceId: ww.instanceId,
|
||||
target: { kind: "edge", cell: warp.from.cell, side: warp.from.side },
|
||||
});
|
||||
expect(r.ok).toBe(deckRev >= 40);
|
||||
if (!r.ok) continue;
|
||||
// Both wizards stood in the mouths; the collapse washed both inward.
|
||||
const meAfter = r.state.players.find((p) => p.id === me.id)!;
|
||||
const otherAfter = r.state.players.find((p) => p.id === other.id)!;
|
||||
expect(cellKey(meAfter.position)).not.toBe(cellKey(warp.from.cell));
|
||||
expect(cellKey(otherAfter.position)).not.toBe(cellKey(warp.to.cell));
|
||||
}
|
||||
});
|
||||
|
||||
it("illusion wall hangs on a rim warp mouth from rev 40", () => {
|
||||
for (const deckRev of [39, 40]) {
|
||||
const { state } = createGame({
|
||||
playerIds: ["alice", "bob"], seed: 42, sets: ["basic", "expansion1"], deckRev,
|
||||
});
|
||||
const me = activePlayer(state);
|
||||
const warp = state.board.warps[0]!;
|
||||
me.position = { ...warp.from.cell };
|
||||
const il = giveCard(state, me.id, "illusion-wall", "IL", 0);
|
||||
const r = applyCommand(state, me.id, {
|
||||
type: "cast", instanceId: il.instanceId,
|
||||
target: { kind: "edge", cell: warp.from.cell, side: warp.from.side },
|
||||
});
|
||||
expect(r.ok).toBe(deckRev >= 40);
|
||||
if (r.ok) {
|
||||
expect(r.state.illusionWalls[edgeKey(warp.from.cell, warp.from.side)]).toBeDefined();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("stone to water breaches the outer rim from rev 40, opening a warp", () => {
|
||||
for (const deckRev of [39, 40]) {
|
||||
let { state } = createGame({
|
||||
playerIds: ["alice", "bob"], seed: 42, sets: ["basic", "expansion1"], deckRev,
|
||||
});
|
||||
const me = activePlayer(state);
|
||||
const board = boardView(state);
|
||||
// Stand at a plain rim wall (an off-board edge that is no warp mouth).
|
||||
let rim: { cell: Cell; side: Side } | null = null;
|
||||
outer: for (const k of Object.keys(board.cells)) {
|
||||
const [x, y] = k.split(",").map(Number) as [number, number];
|
||||
for (const side of SIDES) {
|
||||
const n = { x: x + (side === "E" ? 1 : side === "W" ? -1 : 0), y: y + (side === "S" ? 1 : side === "N" ? -1 : 0) };
|
||||
if (board.cells[cellKey(n)]) continue;
|
||||
if (board.edges[edgeKey({ x, y }, side)] !== "wall") continue;
|
||||
if (state.board.warps.some((w) => cellKey(w.from.cell) === k && w.from.side === side)) continue;
|
||||
rim = { cell: { x, y }, side };
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
if (!rim) throw new Error("setup: no plain rim wall found");
|
||||
me.position = { ...rim.cell };
|
||||
const warpsBefore = state.board.warps.length;
|
||||
const stw = giveCard(state, me.id, "stone-to-water", "SW", 0);
|
||||
state = must(state, me.id, {
|
||||
type: "cast", instanceId: stw.instanceId,
|
||||
target: { kind: "edge", cell: rim.cell, side: rim.side },
|
||||
});
|
||||
if (deckRev >= 40) {
|
||||
// The far rim melted with it and the wraparound now runs.
|
||||
expect(state.board.warps.length).toBe(warpsBefore + 2);
|
||||
} else {
|
||||
// Older vintages left a dangling opening and replay so.
|
||||
expect(state.board.warps.length).toBe(warpsBefore);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("no doors through the rim from rev 40", () => {
|
||||
for (const deckRev of [39, 40]) {
|
||||
const { state } = createGame({
|
||||
playerIds: ["alice", "bob"], seed: 42, sets: ["basic", "expansion1"], deckRev,
|
||||
});
|
||||
const me = activePlayer(state);
|
||||
const board = boardView(state);
|
||||
let rim: { cell: Cell; side: Side } | null = null;
|
||||
outer: for (const k of Object.keys(board.cells)) {
|
||||
const [x, y] = k.split(",").map(Number) as [number, number];
|
||||
for (const side of SIDES) {
|
||||
const n = { x: x + (side === "E" ? 1 : side === "W" ? -1 : 0), y: y + (side === "S" ? 1 : side === "N" ? -1 : 0) };
|
||||
if (!board.cells[cellKey(n)] && board.edges[edgeKey({ x, y }, side)] === "wall") {
|
||||
rim = { cell: { x, y }, side };
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!rim) throw new Error("setup: no rim wall found");
|
||||
me.position = { ...rim.cell };
|
||||
const cd = giveCard(state, me.id, "create-door", "CD", 0);
|
||||
const r = applyCommand(state, me.id, {
|
||||
type: "cast", instanceId: cd.instanceId,
|
||||
target: { kind: "edge", cell: rim.cell, side: rim.side },
|
||||
});
|
||||
// Rev 39 hung a dead door there (and replays so); rev 40 refuses.
|
||||
expect(r.ok).toBe(deckRev < 40);
|
||||
}
|
||||
});
|
||||
|
||||
it("stone to water melts a door from rev 38 — a small entryway in a stone wall", () => {
|
||||
for (const deckRev of [37, 38]) {
|
||||
const { state } = createGame({
|
||||
|
||||
Reference in New Issue
Block a user