The fallen drop what they carry, however they fall (rev 30)
A wizard eliminated by treasuresLost took any carried treasure into the void with them — the killed path drops it, but checkVictory's branch never did. At rev 30 the treasure lands where they stood, with the usual treasureDropped event (onHomeOf included, so a capture completed by the falling is honored in the same breath). Stored games replay the vanishing unchanged. 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
f1743e6fe5
commit
62c4680d1f
@@ -5821,6 +5821,22 @@ function checkVictory(state: GameState, events: GameEvent[]): void {
|
||||
state.discard.push(...p.hand.splice(0));
|
||||
p.displayed = [];
|
||||
events.push({ type: "playerEliminated", player: p.id, reason: "treasuresLost" });
|
||||
// A treasure in the fallen wizard's arms lands where they stood, as
|
||||
// it does when a wizard is killed (rules rev 30; earlier games let
|
||||
// it vanish with them and replay so).
|
||||
if ((state.config.deckRev ?? 1) >= 30 && p.carriedTreasureId) {
|
||||
const t = state.treasures.find((t) => t.id === p.carriedTreasureId)!;
|
||||
t.carriedBy = null;
|
||||
t.position = p.position;
|
||||
p.carriedTreasureId = null;
|
||||
events.push({
|
||||
type: "treasureDropped",
|
||||
player: p.id,
|
||||
treasureId: t.id,
|
||||
at: p.position,
|
||||
onHomeOf: homeOwnerAt(state, p.position),
|
||||
});
|
||||
}
|
||||
if ((state.config.deckRev ?? 1) >= 14) sweepEliminated(state, p.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,3 +224,41 @@ describe("treasures and victory", () => {
|
||||
expect(result.ok).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("elimination by lost treasures drops what the fallen carried (rev 30)", () => {
|
||||
it("the carried treasure lands where the wizard stood", () => {
|
||||
let { state } = createGame({ playerIds: ["a", "b", "c"], seed: 42, sets: ["basic"], deckRev: 30 });
|
||||
const A = state.players.find((p) => p.id === "a")!;
|
||||
const B = state.players.find((p) => p.id === "b")!;
|
||||
const C = state.players.find((p) => p.id === "c")!;
|
||||
// C's first treasure already sits captured on B's home...
|
||||
const c1 = state.treasures.filter((t) => t.owner === "c")[0]!;
|
||||
c1.position = { ...B.home };
|
||||
// ...C carries one of B's treasures...
|
||||
const bt = state.treasures.filter((t) => t.owner === "b")[0]!;
|
||||
bt.position = null;
|
||||
bt.carriedBy = "c";
|
||||
C.carriedTreasureId = bt.id;
|
||||
// ...and A, standing on their own home, drops C's second treasure there.
|
||||
const c2 = state.treasures.filter((t) => t.owner === "c")[1]!;
|
||||
c2.position = null;
|
||||
c2.carriedBy = "a";
|
||||
A.carriedTreasureId = c2.id;
|
||||
A.position = { ...A.home };
|
||||
while (state.players[state.turn.activeIndex]!.id !== "a") {
|
||||
const r = applyCommand(state, state.players[state.turn.activeIndex]!.id, { type: "endTurn", draw: 0 });
|
||||
if (!r.ok) throw new Error(r.error);
|
||||
state = r.state;
|
||||
}
|
||||
const r = applyCommand(state, "a", { type: "dropTreasure" });
|
||||
if (!r.ok) throw new Error(r.error);
|
||||
state = r.state;
|
||||
// C is eliminated by lost treasures — and B's treasure lies where C stood.
|
||||
const cAfter = state.players.find((p) => p.id === "c")!;
|
||||
expect(cAfter.alive).toBe(false);
|
||||
expect(cAfter.carriedTreasureId).toBeNull();
|
||||
const btAfter = state.treasures.find((t) => t.id === bt.id)!;
|
||||
expect(btAfter.carriedBy).toBeNull();
|
||||
expect(btAfter.position).toEqual(cAfter.position);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -54,7 +54,7 @@ export interface Room {
|
||||
const rooms = new Map<string, Room>();
|
||||
|
||||
/** Rules revision new games are dealt under (stored games keep their own). */
|
||||
const RULES_REV = 29;
|
||||
const RULES_REV = 30;
|
||||
|
||||
const ROOM_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ class LocalGame {
|
||||
seed,
|
||||
sets: expansion ? ["basic", "expansion1"] : ["basic"],
|
||||
...(colors ? { colors } : {}),
|
||||
deckRev: 29,
|
||||
deckRev: 30,
|
||||
};
|
||||
const { state, events } = createGame(config);
|
||||
for (const e of events) {
|
||||
|
||||
Reference in New Issue
Block a user