Add Swap Home Bases — the audit's one escapee

Neutral, LOS to the other player, legal only when both home bases hold
an equal number of treasures. With this, every card in the 6th edition
game is implemented except Thumb Of God, which awaits its digital
redesign. 118 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-15 23:02:43 -04:00
co-authored by Claude Fable 5
parent 06eea72ded
commit 21dcd532a3
2 changed files with 40 additions and 0 deletions
+23
View File
@@ -2062,6 +2062,29 @@ const CARD_EFFECTS: Record<string, AttackEffect | NeutralEffect | CounterEffect>
kind: "neutral",
resolve: () => "played out of turn — use it during another player's turn",
},
"swap-home-bases": {
kind: "neutral",
// "Swap your home base with any other player, as long as you both have an
// equal number of treasures on your home bases. You must be within L.O.S."
resolve: (state, events, caster, cmd) => {
if (!cmd.target || cmd.target.kind !== "player") return "choose whose home to take";
const other = state.players.find((p) => p.id === (cmd.target as { playerId: PlayerId }).playerId);
if (!other || !other.alive) return "no such living player";
if (other.id === caster.id) return "that is already your home";
if (!gameLos(state, caster.position, other.position)) return "no line of sight to them";
const onHome = (home: Cell) =>
state.treasures.filter((t) => t.position && cellKey(t.position) === cellKey(home)).length;
if (onHome(caster.home) !== onHome(other.home)) {
return "your home bases must hold an equal number of treasures";
}
const mine = caster.home;
caster.home = other.home;
other.home = mine;
events.push({ type: "positionsSwapped", a: caster.id, b: other.id, aTo: caster.home, bTo: other.home });
checkVictory(state, events);
return null;
},
},
"reuse-spell": {
kind: "neutral",
// "You may retrieve any spell you use immediately after you use it (but
@@ -209,3 +209,20 @@ describe("expansion combat cards", () => {
}
});
});
describe("swap home bases", () => {
it("trades homes when both bases hold equal treasures", () => {
let { state } = newGame();
const me = activePlayer(state);
const other = state.players.find((p) => p.id !== me.id)!;
other.position = { ...me.position }; // LOS guaranteed
const myHome = { ...me.home };
const theirHome = { ...other.home };
const shb = giveCard(state, me.id, "swap-home-bases");
state = must(state, me.id, {
type: "cast", instanceId: shb.instanceId, target: { kind: "player", playerId: other.id },
});
expect(cellKey(state.players.find((p) => p.id === me.id)!.home)).toBe(cellKey(theirHome));
expect(cellKey(state.players.find((p) => p.id === other.id)!.home)).toBe(cellKey(myHome));
});
});