From 4e457b80afdef8914434c02732aef6b2614d4c6c Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Tue, 24 Feb 2026 22:37:23 -0500 Subject: [PATCH] Add createCombatFromRun to create combat state from run --- src/state.js | 42 ++++++++++++++++++++++++++++++++++++++++++ src/state.test.js | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/state.js b/src/state.js index c2019b1..a151fd1 100644 --- a/src/state.js +++ b/src/state.js @@ -73,6 +73,48 @@ export function createCombatState(characterOrChars, enemyIdOrIds) { return state; } +export function createCombatFromRun(run, enemyIdOrIds) { + const enemyIds = Array.isArray(enemyIdOrIds) ? enemyIdOrIds : [enemyIdOrIds]; + const enemies = enemyIds.map((id, i) => makeEnemy(id, i)); + + const player = { + id: "player_0", + character: run.character, + hp: run.hp, + maxHp: run.maxHp, + energy: 3, + maxEnergy: 3, + block: 0, + strength: 0, + vulnerable: 0, + weak: 0, + drawPile: shuffle([...run.deck]), + hand: [], + discardPile: [], + exhaustPile: [], + powers: [], + }; + + const state = { + players: [player], + enemies, + combat: { + turn: 1, + phase: "player_turn", + dieResult: null, + selectedCard: null, + log: [], + playerCount: 1, + activePlayerIndex: null, + playersReady: [], + }, + }; + + state.player = player; + state.enemy = enemies[0]; + return state; +} + export function drawCards(state, playerIndexOrCount, count) { // drawCards(state, count) — old single-player form // drawCards(state, playerIndex, count) — new indexed form diff --git a/src/state.test.js b/src/state.test.js index 41ad2e2..c361e92 100644 --- a/src/state.test.js +++ b/src/state.test.js @@ -1,7 +1,14 @@ import { beforeAll, describe, expect, test } from "bun:test"; import { initCards } from "./cards.js"; import { initEnemies } from "./enemies.js"; -import { createCombatState, drawCards, endTurn, playCard } from "./state.js"; +import { createRunState } from "./run.js"; +import { + createCombatFromRun, + createCombatState, + drawCards, + endTurn, + playCard, +} from "./state.js"; beforeAll(async () => { await Promise.all([initCards(), initEnemies()]); @@ -278,3 +285,34 @@ describe("backward compat - single string args", () => { expect(next.player.hand).toHaveLength(0); }); }); + +describe("createCombatFromRun", () => { + test("uses run deck for draw pile", () => { + const run = createRunState("ironclad"); + // simulate picking a reward card + const modified = { ...run, deck: [...run.deck, "pommel_strike"] }; + const state = createCombatFromRun(modified, "jaw_worm"); + const allCards = [ + ...state.players[0].drawPile, + ...state.players[0].hand, + ...state.players[0].discardPile, + ]; + expect(allCards).toHaveLength(11); + expect(allCards.filter((id) => id === "pommel_strike")).toHaveLength(1); + }); + + test("uses run HP instead of max", () => { + const run = createRunState("ironclad"); + run.hp = 7; + const state = createCombatFromRun(run, "jaw_worm"); + expect(state.players[0].hp).toBe(7); + expect(state.players[0].maxHp).toBe(11); + }); + + test("backward-compat aliases work", () => { + const run = createRunState("ironclad"); + const state = createCombatFromRun(run, "jaw_worm"); + expect(state.player).toBe(state.players[0]); + expect(state.enemy).toBe(state.enemies[0]); + }); +});