Correct 15 cards against photos of the actual 6e card faces

Eric spotted mismatches between the 5e-database-derived card data and
his physical 6e cards (photos IMG_4688-4690). All 15 texts are now
verbatim from the faces. Four were mechanical, now fixed in the
engine: BLIND's 6e text adds "engage in combat" — blinded punches
flail on a die roll; PICK LOCK's face states "This is not a spell" —
the lock cards and thrown weapons are physical actions NO SPELL cannot
silence; MIST-BODY passes doors and drifts through thornbushes but
does NOT pass the maze's stone walls (was backwards); WALL OF FIRE's
counteraction mode stops a Waterbolt (previously deferred). Metadata:
UGLY is L.O.S.-marked, MASTER KEY is NEUTRAL/ADJACENT, WIZARDBLADE
and PICK LOCK carry ADJACENT markings (new `adjacent` field), LARGE
ROCK is rethrowable by any player (already engine behavior),
BRAINSTONE's face has no corner type. 84 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-15 21:58:17 -04:00
co-authored by Claude Fable 5
parent 1924114b6d
commit 5a0003f4ce
8 changed files with 200 additions and 49 deletions
+92
View File
@@ -293,3 +293,95 @@ describe("sector manipulation", () => {
expect(refused.ok).toBe(false);
});
});
describe("6e card-face corrections", () => {
it("no spell does not block pick lock — 'This is not a spell'", () => {
let { state } = newGame();
state = toRound2(state);
const attacker = activePlayer(state);
const defender = state.players.find((p) => p.id !== attacker.id)!;
defender.position = { ...attacker.position };
const ns = giveCard(state, attacker.id, "no-spell");
giveCard(state, attacker.id, "number-3", "N", 1);
state = must(state, attacker.id, {
type: "cast", instanceId: ns.instanceId, numberInstanceIds: ["number-3#N"],
target: { kind: "player", playerId: defender.id },
});
state = must(state, defender.id, { type: "pass" });
state = must(state, attacker.id, { type: "endTurn", draw: 0 });
// The silenced defender cannot cast a spell...
const fb = giveCard(state, defender.id, "fireball", "F", 0);
expect(applyCommand(state, defender.id, {
type: "cast", instanceId: fb.instanceId, target: { kind: "player", playerId: attacker.id },
}).ok).toBe(false);
// ...but picking a lock is a physical action, not a spell.
const view = boardView(state);
const doorEntry = Object.entries(view.edges).find(([, st]) => st === "door")!;
const [kind, coords] = doorEntry[0].split(":") as [string, string];
const [dx, dy] = coords.split(",").map(Number) as [number, number];
const d = state.players.find((p) => p.id === defender.id)!;
d.position = { x: dx, y: dy };
const pl = giveCard(state, defender.id, "pick-lock", "PL", 1);
const result = applyCommand(state, defender.id, {
type: "cast", instanceId: pl.instanceId,
target: { kind: "edge", cell: { x: dx, y: dy }, side: kind === "V" ? "E" : "S" },
});
expect(result.ok).toBe(true);
});
it("blinded punches flail on the die — 'engage in combat'", () => {
let hits = 0, misses = 0;
for (let seed = 1; seed <= 10; seed++) {
let { state } = newGame(seed);
state = toRound2(state);
const attacker = activePlayer(state);
const defender = state.players.find((p) => p.id !== attacker.id)!;
defender.position = { ...attacker.position };
state.sustained.push({
id: "fx-test", cardId: "blind", casterId: defender.id,
targetId: attacker.id, remainingTurns: 3, data: {},
});
const result = applyCommand(state, attacker.id, { type: "punch", targetId: defender.id });
expect(result.ok).toBe(true);
if (!result.ok) continue;
if (result.state.stack) hits++;
else {
misses++;
expect(result.state.turn.attackUsed).toBe(true); // the flail spends the attack
}
}
expect(hits + misses).toBe(10);
expect(misses).toBeGreaterThan(0);
});
it("wall of fire, as a counteraction, stops a waterbolt cold", () => {
let { state } = newGame();
state = toRound2(state);
const attacker = activePlayer(state);
const defender = state.players.find((p) => p.id !== attacker.id)!;
defender.position = { ...attacker.position };
const wb = giveCard(state, attacker.id, "waterbolt");
giveCard(state, attacker.id, "number-4", "N", 1);
giveCard(state, defender.id, "wall-of-fire", "WOF", 0);
state = must(state, attacker.id, {
type: "cast", instanceId: wb.instanceId, numberInstanceIds: ["number-4#N"],
target: { kind: "player", playerId: defender.id },
params: { damage: 4, knockback: 0 },
});
state = must(state, defender.id, { type: "counteract", instanceId: "wall-of-fire#WOF" });
state = must(state, attacker.id, { type: "pass" });
state = must(state, defender.id, { type: "pass" });
expect(state.players.find((p) => p.id === defender.id)!.life).toBe(15);
// But it cannot counter a fireball.
state = must(state, attacker.id, { type: "endTurn", draw: 0 });
state = must(state, defender.id, { type: "endTurn", draw: 0 });
const fb = giveCard(state, attacker.id, "fireball", "F", 0);
giveCard(state, defender.id, "wall-of-fire", "WOF2", 0);
state = must(state, attacker.id, {
type: "cast", instanceId: fb.instanceId, target: { kind: "player", playerId: defender.id },
});
expect(applyCommand(state, defender.id, { type: "counteract", instanceId: "wall-of-fire#WOF2" }).ok).toBe(false);
});
});