Wire map into game loop with node-driven combat

This commit is contained in:
Jared Miller 2026-02-25 09:54:55 -05:00
parent 4d0692cf44
commit febb05764b
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
3 changed files with 61 additions and 14 deletions

View file

@ -1,7 +1,8 @@
import { getCard, initCards } from "./cards.js";
import { checkCombatEnd, resolveEnemyTurn, startTurn } from "./combat.js";
import { initEnemies } from "./enemies.js";
import { render } from "./render.js";
import { advanceMap, getCurrentNode, getNodeEnemy } from "./map.js";
import { render, renderMap, showGame } from "./render.js";
import {
createRunState,
endCombat,
@ -24,18 +25,47 @@ async function init() {
function startNewRun() {
run = createRunState("ironclad");
revealed = null;
startNextCombat();
showMapScreen();
}
function startNextCombat() {
state = createCombatFromRun(run, "jaw_worm");
function showMapScreen() {
renderMap(run.map);
}
function proceedFromMap() {
const node = getCurrentNode(run.map);
if (node.type === "campfire") {
console.debug("campfire — rest not yet implemented");
run = { ...run, map: advanceMap(run.map) };
showMapScreen();
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;
@ -139,22 +169,34 @@ function bindEvents() {
const index = revealed.indexOf(cardId);
if (index === -1) return;
run = pickReward(run, revealed, index);
startNextCombat();
showMapScreen();
});
document.getElementById("skip-btn").addEventListener("click", () => {
if (!revealed) return;
run = skipRewards(run, revealed);
startNextCombat();
showMapScreen();
});
document
.getElementById("map-proceed-btn")
.addEventListener("click", proceedFromMap);
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;
// 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();
}
});
}

View file

@ -156,10 +156,13 @@ function renderOverlay(state, revealed) {
skipBtn.hidden = false;
} else if (state.combat.phase === "ended") {
overlay.hidden = false;
overlayText.textContent =
state.combat.result === "defeat"
? "defeat — click to restart"
: "victory";
if (state.combat.result === "defeat") {
overlayText.textContent = "defeat — click to restart";
} else if (state.combat.result === "act_complete") {
overlayText.textContent = "act 1 complete! — click to start new run";
} else {
overlayText.textContent = "victory";
}
rewardCards.innerHTML = "";
skipBtn.hidden = true;
} else {

View file

@ -1,4 +1,5 @@
import { getAllCards, getStarterDeck } from "./cards.js";
import { createMap } from "./map.js";
import { shuffle } from "./state.js";
export function createRunState(character) {
@ -10,6 +11,7 @@ export function createRunState(character) {
cardRewardsDeck: buildRewardsDeck(character),
potions: [],
combatCount: 0,
map: createMap(),
};
}