Add createCombatFromRun to create combat state from run

This commit is contained in:
Jared Miller 2026-02-24 22:37:23 -05:00
parent 46bd6e6d2b
commit 4e457b80af
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
2 changed files with 81 additions and 1 deletions

View file

@ -73,6 +73,48 @@ export function createCombatState(characterOrChars, enemyIdOrIds) {
return state; 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) { export function drawCards(state, playerIndexOrCount, count) {
// drawCards(state, count) — old single-player form // drawCards(state, count) — old single-player form
// drawCards(state, playerIndex, count) — new indexed form // drawCards(state, playerIndex, count) — new indexed form

View file

@ -1,7 +1,14 @@
import { beforeAll, describe, expect, test } from "bun:test"; import { beforeAll, describe, expect, test } from "bun:test";
import { initCards } from "./cards.js"; import { initCards } from "./cards.js";
import { initEnemies } from "./enemies.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 () => { beforeAll(async () => {
await Promise.all([initCards(), initEnemies()]); await Promise.all([initCards(), initEnemies()]);
@ -278,3 +285,34 @@ describe("backward compat - single string args", () => {
expect(next.player.hand).toHaveLength(0); 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]);
});
});