import { getCard, initCards } from "./cards.js"; import { checkCombatEnd, resolveEnemyTurn, startTurn } from "./combat.js"; import { initEnemies } from "./enemies.js"; import { advanceMap, getCurrentNode, getNodeEnemy } from "./map.js"; import { hideCampfire, render, renderCampfire, renderMap, showGame, } from "./render.js"; import { campfireRest, campfireSmith, createRunState, endCombat, getUpgradableCards, pickReward, revealRewards, skipRewards, } from "./run.js"; import { createCombatFromRun, endTurn, playCard } from "./state.js"; let state = null; let run = null; let revealed = null; async function init() { await Promise.all([initCards(), initEnemies()]); startNewRun(); bindEvents(); } function startNewRun() { run = createRunState("ironclad"); revealed = null; showMapScreen(); } function showMapScreen() { renderMap(run.map); } function showCampfire() { renderCampfire(run); } function proceedFromMap() { const node = getCurrentNode(run.map); if (node.type === "campfire") { showCampfire(); return; } const enemyId = getNodeEnemy(node.type); startNextCombat(enemyId); } function startNextCombat(enemyId) { showGame(); state = createCombatFromRun(run, enemyId); state = startTurn(state); revealed = null; render(state, revealed); } function handleVictory() { const clearedNode = getCurrentNode(run.map); run = endCombat(run, state.players[0].hp); run = { ...run, map: advanceMap(run.map) }; if (clearedNode.type === "boss") { state = { ...state, combat: { ...state.combat, phase: "ended", result: "act_complete" }, }; render(state, revealed); return; } const result = revealRewards(run); revealed = result.revealed; run = result.run; state = { ...state, combat: { ...state.combat, phase: "rewards" }, }; render(state, revealed); } function handleDefeat() { run = { ...run, hp: state.players[0].hp }; state = { ...state, combat: { ...state.combat, phase: "ended", result: "defeat" }, }; render(state, revealed); } function checkEnd() { const end = checkCombatEnd(state); if (end === "victory") { handleVictory(); return true; } if (end === "defeat") { handleDefeat(); return true; } return false; } function bindEvents() { document.getElementById("hand").addEventListener("click", (e) => { const cardEl = e.target.closest(".card"); if (!cardEl || state.combat.phase !== "player_turn") return; const index = Number(cardEl.dataset.index); if (state.combat.selectedCard === index) { state = { ...state, combat: { ...state.combat, selectedCard: null } }; render(state, revealed); return; } state = { ...state, combat: { ...state.combat, selectedCard: index } }; const cardId = state.player.hand[index]; const card = getCard(cardId); if (card.type === "skill") { const result = playCard(state, index); if (result === null) { state = { ...state, combat: { ...state.combat, selectedCard: null } }; render(state, revealed); return; } state = { ...result, combat: { ...result.combat, selectedCard: null } }; if (!checkEnd()) render(state, revealed); return; } render(state, revealed); }); document.getElementById("enemy-zone").addEventListener("click", () => { if (state.combat.selectedCard === null) return; if (state.combat.phase !== "player_turn") return; const result = playCard(state, state.combat.selectedCard); if (result === null) { state = { ...state, combat: { ...state.combat, selectedCard: null } }; render(state, revealed); return; } state = { ...result, combat: { ...result.combat, selectedCard: null } }; if (!checkEnd()) render(state, revealed); }); document .getElementById("end-turn-btn") .addEventListener("click", async () => { if (state.combat.phase !== "player_turn") return; state = endTurn(state); render(state, revealed); await delay(800); state = resolveEnemyTurn(state); if (!checkEnd()) { state = startTurn(state); render(state, revealed); } }); document.getElementById("reward-cards").addEventListener("click", (e) => { const img = e.target.closest(".reward-card"); if (!img || !revealed) return; const cardId = img.dataset.cardId; const index = revealed.indexOf(cardId); if (index === -1) return; run = pickReward(run, revealed, index); showMapScreen(); }); document.getElementById("skip-btn").addEventListener("click", () => { if (!revealed) return; run = skipRewards(run, revealed); showMapScreen(); }); document .getElementById("map-proceed-btn") .addEventListener("click", proceedFromMap); document.getElementById("campfire-rest-btn").addEventListener("click", () => { run = campfireRest(run); run = { ...run, map: advanceMap(run.map) }; hideCampfire(); showMapScreen(); }); document .getElementById("campfire-smith-btn") .addEventListener("click", () => { const upgradable = getUpgradableCards(run); renderCampfire(run, upgradable); }); document.getElementById("smith-cards").addEventListener("click", (e) => { const btn = e.target.closest(".smith-card-btn"); if (!btn) return; const cardId = btn.dataset.cardId; run = campfireSmith(run, cardId); run = { ...run, map: advanceMap(run.map) }; hideCampfire(); showMapScreen(); }); document.getElementById("overlay").addEventListener("click", (e) => { if (e.target.closest("#reward-cards") || e.target.closest("#skip-btn")) return; // restart on defeat overlay click if (state.combat.phase === "ended" && state.combat.result === "defeat") { startNewRun(); return; } // restart on act complete overlay click if ( state.combat.phase === "ended" && state.combat.result === "act_complete" ) { startNewRun(); } }); } function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } init();