Browse Source

Fix misc bugs

main
Stephanie Gredell 4 months ago
parent
commit
a007568d84
  1. 2
      src/data/cards.js
  2. 30
      src/engine/battle.js
  3. 93
      src/main.js

2
src/data/cards.js

@ -331,7 +331,7 @@ export const CARDS = { @@ -331,7 +331,7 @@ export const CARDS = {
ctx.draw(1);
ctx.log(`Clean code heals the soul! Heal ${healAmount} HP and draw 1.`);
}
},
}
};

30
src/engine/battle.js

@ -74,8 +74,14 @@ export function playCard(ctx, handIndex) { @@ -74,8 +74,14 @@ export function playCard(ctx, handIndex) {
return;
}
try {
card.effect(ctx);
card._used = true;
} catch (error) {
console.error('Card effect error:', error, 'Card:', card);
ctx.log(`Error playing ${card.name || 'Unknown card'}: ${error.message}`);
return;
}
if (card.type !== "power") {
@ -105,14 +111,29 @@ export function enemyTurn(ctx) { @@ -105,14 +111,29 @@ export function enemyTurn(ctx) {
if (e.weak > 0) dmg = Math.floor(dmg * 0.75);
applyDamage(ctx, ctx.player, dmg, `${e.name} attacks`);
} else if (e.intent.type === "block") {
try {
ENEMIES[e.id].onBlock?.(ctx, e.intent.value);
e.block += e.intent.value;
ctx.log(`${e.name} defends and gains ${e.intent.value} block.`);
} catch (error) {
console.error('Enemy block effect error:', error, 'Enemy:', e.id);
ctx.log(`${e.name} tries to defend but fumbles!`);
}
} else if (e.intent.type === "debuff") {
try {
ENEMIES[e.id].onDebuff?.(ctx, e.intent.value);
ctx.log(`${e.name} casts a debuffing spell.`);
} catch (error) {
console.error('Enemy debuff effect error:', error, 'Enemy:', e.id);
ctx.log(`${e.name} tries to cast a spell but it fizzles!`);
}
} else if (e.intent.type === "heal") {
try {
ENEMIES[e.id].onHeal?.(ctx, e.intent.value);
} catch (error) {
console.error('Enemy heal effect error:', error, 'Enemy:', e.id);
ctx.log(`${e.name} tries to heal but something goes wrong!`);
}
}
@ -123,7 +144,16 @@ export function enemyTurn(ctx) { @@ -123,7 +144,16 @@ export function enemyTurn(ctx) {
if (ctx.player.hp <= 0) { ctx.onLose(); return; }
e.turn++;
try {
e.intent = ENEMIES[e.id].ai(e.turn);
if (!e.intent || !e.intent.type) {
throw new Error('Invalid enemy intent returned');
}
} catch (error) {
console.error('Enemy AI error:', error, 'Enemy:', e.id);
ctx.log(`Enemy AI malfunction! ${e.name} does nothing this turn.`);
e.intent = { type: "block", value: 0 }; // Safe fallback
}
startPlayerTurn(ctx);
}

93
src/main.js

@ -18,7 +18,7 @@ const root = { @@ -18,7 +18,7 @@ const root = {
enemy: null,
log(m) { this.logs.push(m); this.logs = this.logs.slice(-200); },
render() { renderBattle(this); },
async render() { await renderBattle(this); },
play(i) { playCard(this, i); },
showDamageNumber: showDamageNumber,
end() { endTurn(this); },
@ -44,7 +44,7 @@ const root = { @@ -44,7 +44,7 @@ const root = {
} else if (node.kind === "event") {
renderEvent(this);
} else if (node.kind === "start") {
renderMap(this);
await renderMap(this);
}
}
},
@ -66,10 +66,10 @@ const root = { @@ -66,10 +66,10 @@ const root = {
await renderWin(this); return;
}
renderMap(this);
await renderMap(this);
},
takeReward(idx) {
async takeReward(idx) {
const card = this._pendingChoices[idx];
if (card) {
this.player.deck.push(card.id);
@ -77,12 +77,12 @@ const root = { @@ -77,12 +77,12 @@ const root = {
}
this._pendingChoices = null;
this.save();
renderMap(this);
await renderMap(this);
},
skipReward() {
async skipReward() {
this._pendingChoices = null;
this.save();
renderMap(this);
await renderMap(this);
},
async onWin() {
@ -107,7 +107,7 @@ const root = { @@ -107,7 +107,7 @@ const root = {
this.completedNodes = [];
this.log(`🎉 Act ${this.currentAct === "act2" ? "II" : "I"} Complete! Advancing to the next challenge...`);
this.save();
renderMap(this);
await renderMap(this);
} else {
// Final victory
this.save(); // Save progress before clearing on victory
@ -140,11 +140,11 @@ const root = { @@ -140,11 +140,11 @@ const root = {
renderRelicSelection(this);
},
selectStartingRelic(relicId) {
async selectStartingRelic(relicId) {
attachRelics(this, [relicId]);
this.log(`Selected starting relic: ${relicId}`);
this.save();
renderMap(this);
await renderMap(this);
},
save() {
@ -170,15 +170,56 @@ const root = { @@ -170,15 +170,56 @@ const root = {
const saveData = localStorage.getItem('birthday-spire-save');
if (saveData) {
const data = JSON.parse(saveData);
this.player = data.player;
this.nodeId = data.nodeId;
this.currentAct = data.currentAct || "act1";
// Validate essential save data
if (!data || typeof data !== 'object') {
throw new Error('Invalid save data format');
}
if (!data.player || typeof data.player !== 'object') {
throw new Error('Invalid player data');
}
if (!data.nodeId || typeof data.nodeId !== 'string') {
throw new Error('Invalid node ID');
}
// Validate current act and ensure map exists
const actId = data.currentAct || "act1";
if (!MAPS[actId]) {
console.warn(`Invalid act ${actId}, falling back to act1`);
this.currentAct = "act1";
} else {
this.currentAct = actId;
}
this.map = MAPS[this.currentAct];
this.relicStates = data.relicStates || [];
this.completedNodes = data.completedNodes || [];
this.logs = data.logs || [];
this._battleInProgress = data.battleInProgress || false;
// Validate that the nodeId exists in the current map
const nodeExists = this.map.nodes.some(n => n.id === data.nodeId);
if (!nodeExists) {
console.warn(`Node ${data.nodeId} not found in ${this.currentAct}, starting from beginning`);
this.nodeId = this.map.nodes.find(n => n.kind === "start").id;
} else {
this.nodeId = data.nodeId;
}
// Validate player data has required fields
if (typeof data.player.hp !== 'number' || data.player.hp < 0) {
throw new Error('Invalid player HP');
}
if (typeof data.player.maxHp !== 'number' || data.player.maxHp <= 0) {
throw new Error('Invalid player max HP');
}
if (!Array.isArray(data.player.deck)) {
throw new Error('Invalid player deck');
}
this.player = data.player;
this.relicStates = Array.isArray(data.relicStates) ? data.relicStates : [];
this.completedNodes = Array.isArray(data.completedNodes) ? data.completedNodes : [];
this.logs = Array.isArray(data.logs) ? data.logs : [];
this._battleInProgress = Boolean(data.battleInProgress);
this.restoreCardEffects();
@ -187,6 +228,8 @@ const root = { @@ -187,6 +228,8 @@ const root = {
}
} catch (e) {
console.warn('Failed to load game:', e);
console.warn('Clearing corrupted save data');
this.clearSave();
}
return false;
},
@ -227,8 +270,8 @@ function pickCards(n) { @@ -227,8 +270,8 @@ function pickCards(n) {
function shuffle(a) { for (let i = a.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1));[a[i], a[j]] = [a[j], a[i]] } return a; }
const _createBattle = root.go.bind(root);
root.go = function(nextId) {
_createBattle(nextId);
root.go = async function(nextId) {
await _createBattle(nextId);
const node = this.map.nodes.find(n => n.id === this.nodeId);
if (node && (node.kind === "battle" || node.kind === "elite" || node.kind === "boss")) {
const ctx = makeBattleContext(this);
@ -304,11 +347,11 @@ async function initializeGame() { @@ -304,11 +347,11 @@ async function initializeGame() {
return;
default:
console.warn(`Unknown screen: ${screenParam}. Loading normal game.`);
loadNormalGame();
await loadNormalGame();
return;
}
} else {
loadNormalGame();
await loadNormalGame();
}
}
@ -406,21 +449,21 @@ function showCountdown(birthday) { @@ -406,21 +449,21 @@ function showCountdown(birthday) {
}, 1000);
}
function loadNormalGame() {
async function loadNormalGame() {
const hasLoadedData = root.load();
if (hasLoadedData) {
// If we were in a battle, resume it
if (root._battleInProgress) {
const node = root.map.nodes.find(n => n.id === root.nodeId);
if (node && (node.kind === "battle" || node.kind === "elite" || node.kind === "boss")) {
root.go(root.nodeId);
await root.go(root.nodeId);
} else {
// Battle state inconsistent, go to map
root._battleInProgress = false;
renderMap(root);
await renderMap(root);
}
} else {
renderMap(root);
await renderMap(root);
}
} else {
root.reset();

Loading…
Cancel
Save