Illusion walls shimmer until YOU test them (rules rev 29)
Per the owner's design — and truer to a real table, where the cast is public: every illusion wall's location is open knowledge, rendered as a shimmering wall to any player whose eyes have not yet ruled on it. Testing is an explicit act: tap the shimmer (or bump into it) and a modal explains the 50/50 and offers 'Roll to test your eyes' — the new testIllusion command rolls once, then the wall either hardens or dissolves for you alone. Nobody's verdict is moved by watching someone else stroll through (the Q3WZ mystery: an automaton walking through its own round-1 fake). Untested walls block movement and sight without consuming RNG; the pre-29 lazy belief roll is preserved for stored games. Automatons doubt free shimmers on their best crossing before spending any card on that wall. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
This commit is contained in:
co-authored by
Claude Fable 5
parent
500d9a7154
commit
d5b2b92f2c
@@ -500,3 +500,61 @@ describe("sight tracing", () => {
|
||||
expect(warped).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("illusions are tested by choice (rules rev 29)", () => {
|
||||
function shimmerRig() {
|
||||
let { state } = createGame({ playerIds: ["a", "b"], seed: 42, sets: ["basic"], deckRev: 29 });
|
||||
state = toRound2(state);
|
||||
const caster = activePlayer(state);
|
||||
const mark = state.players.find((p) => p.id !== caster.id)!;
|
||||
// Conjure the illusion on an OPEN edge beside the victim (state surgery
|
||||
// for a deterministic spot; the cast itself is tested elsewhere).
|
||||
const spot = emptyNeighborCell(state, mark.position);
|
||||
const key = edgeKey(mark.position, spot.side);
|
||||
state.illusionWalls[key] = { createdBy: caster.id, belief: {} };
|
||||
state = must(state, caster.id, { type: "endTurn", draw: 0 });
|
||||
return {
|
||||
state, caster: caster.id, victim: mark.id, side: spot.side,
|
||||
cell: { ...state.players.find((p) => p.id === mark.id)!.position },
|
||||
};
|
||||
}
|
||||
|
||||
it("an untested shimmer blocks the walker with its own message, no die rolled", () => {
|
||||
const { state, victim, side } = shimmerRig();
|
||||
const rngBefore = JSON.stringify(state.rng);
|
||||
const r = applyCommand(state, victim, { type: "move", direction: side });
|
||||
expect(r.ok).toBe(false);
|
||||
if (!r.ok) expect(r.error).toContain("shimmers");
|
||||
expect(JSON.stringify(state.rng)).toBe(rngBefore);
|
||||
});
|
||||
|
||||
it("the belief test is an explicit roll; the verdict then governs the wall", () => {
|
||||
let { state, victim, cell, side } = shimmerRig();
|
||||
state = must(state, victim, { type: "testIllusion", cell, side });
|
||||
const verdict = state.illusionWalls[edgeKey(cell, side)]!.belief[victim];
|
||||
expect(verdict === "believes" || verdict === "seesThrough").toBe(true);
|
||||
const r = applyCommand(state, victim, { type: "move", direction: side });
|
||||
if (verdict === "seesThrough") {
|
||||
expect(r.ok).toBe(true);
|
||||
} else {
|
||||
expect(r.ok).toBe(false);
|
||||
if (!r.ok) expect(r.error).toBe("blocked by wall");
|
||||
}
|
||||
// A second test is refused: eyes rule once.
|
||||
expect(applyCommand(state, victim, { type: "testIllusion", cell, side }).ok).toBe(false);
|
||||
});
|
||||
|
||||
it("the creator strolls through their own fake without any test", () => {
|
||||
let { state, caster } = shimmerRig();
|
||||
// Skip to the caster's turn; the wall never blocks its maker.
|
||||
while (activePlayer(state).id !== caster) {
|
||||
state = must(state, activePlayer(state).id, { type: "endTurn", draw: 0 });
|
||||
}
|
||||
const me = state.players.find((p) => p.id === caster)!;
|
||||
const other = state.players.find((p) => p.id !== caster)!;
|
||||
me.position = { ...other.position };
|
||||
const r = applyCommand(state, caster, { type: "move", direction: "E" });
|
||||
// Blocked only if some REAL edge stands there; the illusion itself never objects.
|
||||
if (!r.ok) expect(r.error).not.toContain("shimmers");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user