Rev 27: an ILLUSIONARY ATTACK is priced as the spell it fakes, so BLUNT and the rest meet it (UPJE)
The believed illusion was dealt after the counter trail had already spoken over a zero, so a BLUNT trailed for nothing and the full points landed. Now the fake carries its spell's points through the pipeline and the belief roll decides whether the weighed blow lands. Games dealt under rev 26 and before replay as they were. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
991a6a0443
commit
c3f63d4eb7
@@ -939,3 +939,55 @@ describe("the goat's ram is a physical blow like any other (rev 26)", () => {
|
||||
expect(state.players.find((p) => p.id === mark)!.life).toBe(15 - distance);
|
||||
});
|
||||
});
|
||||
|
||||
describe("an illusion is priced as the spell it fakes (rev 27)", () => {
|
||||
/** A faked FIREBALL met by the given counteraction, then both wizards pass. */
|
||||
function fakedFireball(counter: string | null, deckRev?: number) {
|
||||
let { state } = createGame({ playerIds: ["liar", "mark"], seed: 42, sets: ["basic", "expansion1"], ...(deckRev ? { deckRev } : {}) });
|
||||
state = toRound2(state);
|
||||
const { attacker, defender } = faceOff(state);
|
||||
const ill = giveCard(state, attacker, "illusionary-attack");
|
||||
if (counter) giveCard(state, defender, counter, "C", 0);
|
||||
state = must(state, attacker, {
|
||||
type: "cast", instanceId: ill.instanceId, target: { kind: "player", playerId: defender }, params: { cardId: "fireball" },
|
||||
});
|
||||
let done = applyCommand(state, defender, { type: "pass" });
|
||||
if (counter) {
|
||||
state = must(state, defender, { type: "counteract", instanceId: `${counter}#C` });
|
||||
// The attacker's pass settles a total stop at once; otherwise the
|
||||
// defender's pass closes the window.
|
||||
done = applyCommand(state, attacker, { type: "pass" });
|
||||
if (done.ok && done.state.stack) done = applyCommand(done.state, defender, { type: "pass" });
|
||||
}
|
||||
if (!done.ok) throw new Error(done.error);
|
||||
const belief = done.events.find((e) => e.type === "illusionBelieved");
|
||||
const believed = belief?.type === "illusionBelieved" ? belief.believed : null;
|
||||
return { events: done.events, believed, life: done.state.players.find((p) => p.id === defender)!.life };
|
||||
}
|
||||
|
||||
it("BLUNT halves a believed fake fireball to three, and disbelief costs nothing", () => {
|
||||
const { events, believed, life } = fakedFireball("blunt");
|
||||
expect(believed).not.toBeNull();
|
||||
expect(events).toContainEqual(expect.objectContaining({ type: "attackResolved", incoming: 5 }));
|
||||
expect(life).toBe(believed ? 12 : 15);
|
||||
});
|
||||
|
||||
it("FULL SHIELD stops the fake outright: nothing to believe in, no die rolled", () => {
|
||||
const { events, believed, life } = fakedFireball("full-shield");
|
||||
expect(believed).toBeNull();
|
||||
expect(events).toContainEqual(expect.objectContaining({ type: "attackResolved", fullyStopped: true }));
|
||||
expect(life).toBe(15);
|
||||
});
|
||||
|
||||
it("uncountered, a believed fake fireball still does its five", () => {
|
||||
const { believed, life } = fakedFireball(null);
|
||||
expect(believed).not.toBeNull();
|
||||
expect(life).toBe(believed ? 10 : 15);
|
||||
});
|
||||
|
||||
it("older games dealt a believed illusion's full points past a BLUNT", () => {
|
||||
const { believed, life } = fakedFireball("blunt", 26);
|
||||
expect(believed).not.toBeNull();
|
||||
expect(life).toBe(believed ? 10 : 15);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user