feat: spell book UI, iron skin spell, buffs system and devlog update

This commit is contained in:
2026-01-08 23:35:01 +01:00
parent f2f399c296
commit 0685c1249e
10 changed files with 387 additions and 47 deletions

View File

@@ -53,6 +53,11 @@ export class GameEngine {
this.resetHeroMoves();
}
});
// End of Turn Logic (Buffs, cooldowns, etc)
this.turnManager.on('turn_ended', (turn) => {
this.handleEndTurn();
});
}
resetHeroMoves() {
@@ -64,6 +69,49 @@ export class GameEngine {
console.log("Refilled Hero Moves");
}
handleEndTurn() {
console.log("[GameEngine] Handling End of Turn Effects...");
if (!this.heroes) return;
this.heroes.forEach(hero => {
if (hero.buffs && hero.buffs.length > 0) {
// Decrement duration
hero.buffs.forEach(buff => {
buff.duration--;
});
// Remove expired
const activeBuffs = [];
const expiredBuffs = [];
hero.buffs.forEach(buff => {
if (buff.duration > 0) {
activeBuffs.push(buff);
} else {
expiredBuffs.push(buff);
}
});
// Revert expired
expiredBuffs.forEach(buff => {
if (buff.stat === 'toughness') {
hero.stats.toughness -= buff.value;
if (hero.tempStats && hero.tempStats.toughnessBonus) {
hero.tempStats.toughnessBonus -= buff.value;
}
console.log(`[GameEngine] Buff expired: ${buff.id} on ${hero.name}. -${buff.value} ${buff.stat}`);
if (this.onShowMessage) {
this.onShowMessage("Efecto Finalizado", `La ${buff.id === 'iron_skin' ? 'Piel de Hierro' : 'Magia'} de ${hero.name} se desvanece.`);
}
}
});
hero.buffs = activeBuffs;
}
});
}
createParty() {
this.heroes = [];
this.monsters = []; // Initialize monsters array
@@ -204,17 +252,32 @@ export class GameEngine {
targetCells.push({ x: x, y: y });
}
// NEW: Enforce LOS Check before execution
const caster = this.selectedEntity;
if (caster) {
const targetObj = { x: x, y: y };
const los = this.checkLineOfSightStrict(caster, targetObj);
if (!los || !los.clear) {
if (this.onShowMessage) this.onShowMessage('Bloqueado', 'No tienes línea de visión.');
// Do NOT cancel targeting, let them try again
return;
}
}
// Execute Spell
const result = this.executeSpell(this.currentSpell, targetCells);
if (result.success) {
// Success
this.cancelTargeting();
if (window.RENDERER) window.RENDERER.hideAreaPreview();
} else {
if (this.onShowMessage) this.onShowMessage('Fallo', result.reason || 'No se pudo lanzar el hechizo.');
this.cancelTargeting(); // Cancel on error? maybe keep open? usually cancel.
if (window.RENDERER) window.RENDERER.hideAreaPreview();
}
this.cancelTargeting();
if (window.RENDERER) window.RENDERER.hideAreaPreview();
return;
}

View File

@@ -36,6 +36,8 @@ export class MagicSystem {
return this.resolveHeal(caster, spell);
} else if (spell.type === 'attack') {
return this.resolveAttack(caster, spell, targetCells);
} else if (spell.type === 'defense') {
return this.resolveDefense(caster, spell, targetCells);
}
return { success: false, reason: 'unknown_spell_type' };
@@ -156,4 +158,67 @@ export class MagicSystem {
return { success: true, type: 'attack', hits: 1 }; // Return success immediately
}
resolveDefense(caster, spell, targetCells) {
// Needs a target hero
let targetHero = null;
// Find hero in target cells
for (const cell of targetCells) {
const h = this.game.heroes.find(h => h.x === cell.x && h.y === cell.y);
if (h) {
targetHero = h;
break;
}
}
if (!targetHero) {
return { success: false, reason: 'no_target_hero' };
}
const effect = spell.effect;
if (!effect) return { success: false };
// Apply Buff
if (effect.stat === 'toughness') {
// Store original if not already stored (simple buffering)
if (!targetHero.tempStats) targetHero.tempStats = {};
// Stackable? Probably not for same spell.
// Check if already has this buff?
// For simplicity: Add modifier
if (!targetHero.tempStats.toughnessBonus) targetHero.tempStats.toughnessBonus = 0;
targetHero.tempStats.toughnessBonus += effect.value;
// Also modify actual stat for calculation access?
// Usually stats are accessed via getter or direct.
// If direct property, we modify it and store original?
// Let's modify the stat directly for now and trust Turn Manager to revert or track it.
// BETTER: modify 'toughness' in stats, store 'buff_iron_skin' in activeBuffs?
targetHero.stats.toughness += effect.value;
// Mark for cleanup (Pseudo-implementation for cleanup)
if (!targetHero.buffs) targetHero.buffs = [];
targetHero.buffs.push({
id: spell.id,
stat: 'toughness',
value: effect.value,
duration: effect.duration
});
if (this.game.onShowMessage) {
this.game.onShowMessage('Piel de Hierro', `Resistencia de ${targetHero.name} +${effect.value}`);
}
// Visual Effect
if (window.RENDERER) {
window.RENDERER.triggerVisualEffect('defense_buff', targetHero.x, targetHero.y);
// Highlight or keep aura?
}
console.log(`[MagicSystem] Applied ${spell.name} to ${targetHero.name}`);
}
return { success: true, type: 'defense', target: targetHero.name };
}
}

View File

@@ -230,9 +230,8 @@ export class MonsterAI {
// Step 2: Attack animation delay (500ms)
setTimeout(() => {
// Step 3: Trigger hit visual on defender (if hit succeeded)
if (result.hitSuccess && this.game.onEntityHit) {
this.game.onEntityHit(hero.id);
}
// Step 3: Trigger hit visual on defender REMOVED (Handled by onCombatResult)
// Step 4: Remove green ring after red ring appears (1200ms for red ring duration)
setTimeout(() => {

View File

@@ -88,6 +88,7 @@ export class TurnManager {
endTurn() {
console.log(`--- TURN ${this.currentTurn} END ---`);
this.emit('turn_ended', this.currentTurn);
this.currentTurn++;
this.startPowerPhase();
}