From fe95c0352936bf3745f50d42f4e466ea5eeb27e0 Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Wed, 25 Feb 2026 09:19:59 -0500 Subject: [PATCH] Add exhaust keyword to playCard --- src/state.js | 12 ++++++++++-- src/state.test.js | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/state.js b/src/state.js index a151fd1..9b8ed8b 100644 --- a/src/state.js +++ b/src/state.js @@ -164,12 +164,20 @@ export function playCard(state, handIndex, opts = {}) { const card = getCard(cardId); if (player.energy < card.cost) return null; + if (card.keywords?.includes("unplayable")) return null; + const hand = [...player.hand]; hand.splice(handIndex, 1); - const discardPile = [...player.discardPile, cardId]; + const exhausted = card.keywords?.includes("exhaust"); + const discardPile = exhausted + ? [...player.discardPile] + : [...player.discardPile, cardId]; + const exhaustPile = exhausted + ? [...player.exhaustPile, cardId] + : [...player.exhaustPile]; const energy = player.energy - card.cost; - const updatedPlayer = { ...player, hand, discardPile, energy }; + const updatedPlayer = { ...player, hand, discardPile, exhaustPile, energy }; const players = state.players.map((p, i) => i === playerIndex ? updatedPlayer : p, ); diff --git a/src/state.test.js b/src/state.test.js index c361e92..4df948d 100644 --- a/src/state.test.js +++ b/src/state.test.js @@ -316,3 +316,41 @@ describe("createCombatFromRun", () => { expect(state.enemy).toBe(state.enemies[0]); }); }); + +describe("playCard - exhaust", () => { + test("exhaust card goes to exhaustPile instead of discardPile", () => { + let state = createCombatState("ironclad", "jaw_worm"); + state = drawCards(state, 5); + // manually put true_grit in hand + const player = { + ...state.player, + hand: [...state.player.hand, "true_grit"], + }; + state = { ...state, player, players: [player] }; + const handIndex = state.player.hand.indexOf("true_grit"); + const discardBefore = [...state.player.discardPile]; + const next = playCard(state, handIndex); + expect(next.player.hand).toHaveLength(state.player.hand.length - 1); + expect(next.player.exhaustPile).toContain("true_grit"); + expect(next.player.discardPile).toEqual(discardBefore); + expect(next.player.energy).toBe(state.player.energy - 1); + }); +}); + +describe("playCard - unplayable", () => { + test("unplayable card cannot be played", () => { + let state = createCombatState("ironclad", "jaw_worm"); + state = drawCards(state, 5); + // manually put tactician in hand + const player = { + ...state.player, + hand: [...state.player.hand, "tactician"], + }; + state = { ...state, player, players: [player] }; + const handIndex = state.player.hand.indexOf("tactician"); + const handBefore = [...state.player.hand]; + const result = playCard(state, handIndex); + expect(result).toBeNull(); + expect(state.player.hand).toEqual(handBefore); + }); +});