diff --git a/index.html b/index.html index f5b6901..b839149 100644 --- a/index.html +++ b/index.html @@ -34,7 +34,11 @@
- + diff --git a/src/main.js b/src/main.js index 91dddcc..9f54bba 100644 --- a/src/main.js +++ b/src/main.js @@ -2,18 +2,76 @@ import { getCard, initCards } from "./cards.js"; import { checkCombatEnd, resolveEnemyTurn, startTurn } from "./combat.js"; import { initEnemies } from "./enemies.js"; import { render } from "./render.js"; -import { createCombatState, endTurn, playCard } from "./state.js"; +import { + createRunState, + 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()]); - state = createCombatState("ironclad", "jaw_worm"); - state = startTurn(state); - render(state); + startNewRun(); bindEvents(); } +function startNewRun() { + run = createRunState("ironclad"); + revealed = null; + startNextCombat(); +} + +function startNextCombat() { + run = { ...run, combatCount: run.combatCount + 1 }; + state = createCombatFromRun(run, "jaw_worm"); + state = startTurn(state); + revealed = null; + render(state, revealed); +} + +function syncRunHp() { + run = { ...run, hp: state.players[0].hp }; +} + +function handleVictory() { + syncRunHp(); + const result = revealRewards(run); + revealed = result.revealed; + run = result.run; + state = { + ...state, + combat: { ...state.combat, phase: "rewards" }, + }; + render(state, revealed); +} + +function handleDefeat() { + syncRunHp(); + 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"); @@ -22,7 +80,7 @@ function bindEvents() { if (state.combat.selectedCard === index) { state = { ...state, combat: { ...state.combat, selectedCard: null } }; - render(state); + render(state, revealed); return; } @@ -32,27 +90,18 @@ function bindEvents() { const card = getCard(cardId); if (card.type === "skill") { - // auto-play skills (they target self) const result = playCard(state, index); if (result === null) { - // not enough energy state = { ...state, combat: { ...state.combat, selectedCard: null } }; - render(state); + render(state, revealed); return; } state = { ...result, combat: { ...result.combat, selectedCard: null } }; - const end = checkCombatEnd(state); - if (end) { - state = { - ...state, - combat: { ...state.combat, phase: "ended", result: end }, - }; - } - render(state); + if (!checkEnd()) render(state, revealed); return; } - render(state); + render(state, revealed); }); document.getElementById("enemy-zone").addEventListener("click", () => { @@ -62,23 +111,12 @@ function bindEvents() { const result = playCard(state, state.combat.selectedCard); if (result === null) { state = { ...state, combat: { ...state.combat, selectedCard: null } }; - render(state); + render(state, revealed); return; } state = { ...result, combat: { ...result.combat, selectedCard: null } }; - - const end = checkCombatEnd(state); - if (end) { - state = { - ...state, - combat: { ...state.combat, phase: "ended", result: end }, - }; - render(state); - return; - } - - render(state); + if (!checkEnd()) render(state, revealed); }); document @@ -87,24 +125,41 @@ function bindEvents() { if (state.combat.phase !== "player_turn") return; state = endTurn(state); - render(state); + render(state, revealed); await delay(800); state = resolveEnemyTurn(state); - const end = checkCombatEnd(state); - if (end) { - state = { - ...state, - combat: { ...state.combat, phase: "ended", result: end }, - }; - render(state); - return; + if (!checkEnd()) { + state = startTurn(state); + render(state, revealed); } - - state = startTurn(state); - render(state); }); + + 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); + startNextCombat(); + }); + + document.getElementById("skip-btn").addEventListener("click", () => { + if (!revealed) return; + run = skipRewards(run, revealed); + startNextCombat(); + }); + + document.getElementById("overlay").addEventListener("click", (e) => { + // only restart on defeat overlay click (not reward cards or skip btn) + if (state.combat.phase !== "ended" || state.combat.result !== "defeat") + return; + if (e.target.closest("#reward-cards") || e.target.closest("#skip-btn")) + return; + startNewRun(); + }); } function delay(ms) { diff --git a/src/render.js b/src/render.js index 2d3b34d..ced2d4c 100644 --- a/src/render.js +++ b/src/render.js @@ -1,11 +1,11 @@ import { getCard } from "./cards.js"; import { resolveEnemyAction } from "./enemies.js"; -export function render(state) { +export function render(state, revealed) { renderEnemy(state); renderInfoBar(state); renderHand(state); - renderOverlay(state); + renderOverlay(state, revealed); } function renderEnemy(state) { @@ -103,16 +103,38 @@ function renderHand(state) { }); } -function renderOverlay(state) { +function renderOverlay(state, revealed) { const overlay = document.getElementById("overlay"); - const result = state.combat.phase === "ended" ? state.combat.result : null; - if (result === "victory") { + const overlayText = document.getElementById("overlay-text"); + const rewardCards = document.getElementById("reward-cards"); + const skipBtn = document.getElementById("skip-btn"); + + if (state.combat.phase === "rewards" && revealed) { overlay.hidden = false; - overlay.textContent = "victory"; - } else if (result === "defeat") { + overlayText.textContent = "card reward"; + rewardCards.innerHTML = ""; + for (const cardId of revealed) { + const card = getCard(cardId); + const img = document.createElement("img"); + img.src = card.image || ""; + img.alt = card.name; + img.title = `${card.name} (${card.cost}) - ${card.description}`; + img.dataset.cardId = cardId; + img.className = "reward-card"; + rewardCards.appendChild(img); + } + skipBtn.hidden = false; + } else if (state.combat.phase === "ended") { overlay.hidden = false; - overlay.textContent = "defeat"; + overlayText.textContent = + state.combat.result === "defeat" + ? "defeat — click to restart" + : "victory"; + rewardCards.innerHTML = ""; + skipBtn.hidden = true; } else { overlay.hidden = true; + rewardCards.innerHTML = ""; + skipBtn.hidden = true; } }