diff --git a/src/run.js b/src/run.js index 84db902..a5d3542 100644 --- a/src/run.js +++ b/src/run.js @@ -1,4 +1,4 @@ -import { getAllCards, getStarterDeck } from "./cards.js"; +import { getAllCards, getCard, getStarterDeck } from "./cards.js"; import { createMap } from "./map.js"; import { shuffle } from "./state.js"; @@ -27,6 +27,29 @@ export function campfireRest(run) { return { ...run, hp: Math.min(run.hp + 3, run.maxHp) }; } +export function campfireSmith(run, cardId) { + const card = getCard(cardId); + if (!card?.upgraded) return run; + const idx = run.deck.indexOf(cardId); + if (idx === -1) return run; + const deck = [...run.deck]; + deck[idx] = card.upgraded; + return { ...run, deck }; +} + +export function getUpgradableCards(run) { + const seen = new Set(); + const result = []; + for (const id of run.deck) { + if (seen.has(id)) continue; + seen.add(id); + if (id.endsWith("+")) continue; + const card = getCard(id); + if (card?.upgraded) result.push(id); + } + return result; +} + export function revealRewards(run) { const count = Math.min(3, run.cardRewardsDeck.length); const revealed = run.cardRewardsDeck.slice(0, count); diff --git a/src/run.test.js b/src/run.test.js index a5bf0dd..e9d154b 100644 --- a/src/run.test.js +++ b/src/run.test.js @@ -3,8 +3,10 @@ import { getAllCards, initCards } from "./cards.js"; import { initEnemies } from "./enemies.js"; import { campfireRest, + campfireSmith, createRunState, endCombat, + getUpgradableCards, pickReward, revealRewards, skipRewards, @@ -104,6 +106,57 @@ describe("campfireRest", () => { }); }); +describe("campfireSmith", () => { + test("replaces first occurrence of base card with upgraded version", () => { + const run = { deck: ["strike_r", "strike_r", "defend_r"] }; + const result = campfireSmith(run, "strike_r"); + expect(result.deck).toEqual(["strike_r+", "strike_r", "defend_r"]); + }); + + test("does nothing if card not in deck", () => { + const run = { deck: ["defend_r", "bash"] }; + const result = campfireSmith(run, "strike_r"); + expect(result.deck).toEqual(["defend_r", "bash"]); + }); + + test("does nothing if card has no upgrade", () => { + const run = { deck: ["bash+", "strike_r"] }; + const result = campfireSmith(run, "bash+"); + expect(result.deck).toEqual(["bash+", "strike_r"]); + }); + + test("smiths strike_r from full ironclad starter deck", () => { + const run = createRunState("ironclad"); + const originalCount = run.deck.filter((id) => id === "strike_r").length; + const result = campfireSmith(run, "strike_r"); + expect(result.deck).toContain("strike_r+"); + expect(result.deck.filter((id) => id === "strike_r")).toHaveLength( + originalCount - 1, + ); + expect(result.deck).toHaveLength(run.deck.length); + }); +}); + +describe("getUpgradableCards", () => { + test("returns unique base cards that have upgrades", () => { + const run = { deck: ["strike_r", "strike_r", "bash", "defend_r"] }; + const result = getUpgradableCards(run); + expect(result).toContain("strike_r"); + expect(result).toContain("bash"); + expect(result).toContain("defend_r"); + // duplicates deduplicated + expect(result.filter((id) => id === "strike_r")).toHaveLength(1); + }); + + test("excludes already-upgraded cards", () => { + const run = { deck: ["strike_r+", "bash+", "defend_r"] }; + const result = getUpgradableCards(run); + expect(result).not.toContain("strike_r+"); + expect(result).not.toContain("bash+"); + expect(result).toContain("defend_r"); + }); +}); + describe("rewards", () => { test("revealRewards removes 3 from rewards deck and returns them", () => { const run = createRunState("ironclad");