export class SkillProcessor { constructor() {} process(skill, attacker, defender, allies, enemies, context = {}) { const handler = this[skill.name]; if (handler) handler.call(this, skill, attacker, defender, allies, enemies, context); } strike(skill, attacker, defender, allies, enemies, context) { const target = defender || context?.enemyCommander; if (!target) return; const dmg = Math.max(0, skill.value - Math.max(0, target.currentArmor)); target.currentHP -= dmg; attacker._lastSkillDmg = (attacker._lastSkillDmg || 0) + dmg; if (context) { context.strikeTarget = target; context.strikeDamage = dmg; } } swipe(skill, attacker, defender, allies, enemies) { const baseDmg = attacker.currentAttack + skill.value; for (const enemy of enemies) { const dmg = Math.max(0, baseDmg - Math.max(0, enemy.currentArmor)); enemy.currentHP -= dmg; } } pierce(skill, attacker, defender, allies, enemies, context) { if (!defender) return; context.pierceBonus = (context.pierceBonus || 0) + skill.value; } rupture(skill, attacker, defender) { if (!defender) return; defender.ruptureStacks = (defender.ruptureStacks || 0) + skill.value; } berserk(skill, attacker, defender, allies, enemies, context) { if (context.trigger === 'on_attack' && context.damageDealt > 0) { attacker.currentAttack += skill.value; } } siege(skill, attacker, defender, allies, enemies, context) { if (context.enemyCommander) { const dmg = Math.max(0, skill.value - Math.max(0, context.enemyCommander.currentArmor)); context.enemyCommander.currentHP -= dmg; } } rally(skill, attacker, defender, allies, enemies, context) { const assaultAllies = allies.filter(a => a.type === 'assault' && a !== attacker && a.currentHP > 0); if (assaultAllies.length === 0) return; const rng = context?.rng; const idx = rng ? rng.nextInt(0, assaultAllies.length - 1) : Math.floor(Math.random() * assaultAllies.length); const target = assaultAllies[idx]; target.currentAttack += skill.value; // Track temp buff so postBattle can reverse it target._tempBuffs = target._tempBuffs || []; target._tempBuffs.push({ stat: 'currentAttack', amount: skill.value, source: 'rally' }); // Expose to caller for event / animation data context.rallyTarget = target; } heal(skill, attacker, defender, allies) { const damaged = allies .filter(a => a.currentHP > 0 && a.currentHP < a.health) .sort((a, b) => (a.currentHP / a.health) - (b.currentHP / b.health)); if (damaged.length === 0) return; damaged[0].currentHP = Math.min(damaged[0].health, damaged[0].currentHP + skill.value); } protect(skill, attacker, defender, allies) { const alive = allies.filter(a => a.currentHP > 0 && a !== attacker); if (alive.length === 0) return; const target = alive[Math.floor(Math.random() * alive.length)]; target.currentArmor += skill.value; } jam(skill, attacker, defender) { if (!defender) return; defender.jamTurns = (defender.jamTurns || 0) + skill.value; } enfeeble(skill, attacker, defender) { if (!defender) return; defender.currentAttack = Math.max(0, defender.currentAttack - skill.value); } weaken(skill, attacker, defender) { if (!defender) return; for (const s of defender.skills) { s.value = Math.max(0, (s.value || 0) - skill.value); } } tribute(skill, attacker, defender, allies, enemies, context) { // Destroy weakest ally for +3 attack to attacker const weakest = allies .filter(a => a !== attacker && a.type === 'assault' && a.currentHP > 0) .sort((a, b) => a.currentHP - b.currentHP)[0]; if (weakest) { weakest.currentHP = 0; attacker.currentAttack += 3; } } evolve(skill, attacker, defender, allies, enemies, context) { // Evolve to upgraded version — check for evolved card id convention: id + '_e' const evolvedId = attacker.id + '_e'; if (context.cardManager && context.cardManager.getCard(evolvedId)) { const evolved = context.cardManager.createInstance(evolvedId); evolved.currentHP = attacker.currentHP; evolved.instanceId = attacker.instanceId; Object.assign(attacker, evolved); } } mortar(skill, attacker, defender, allies, enemies, context) { if (enemies.length === 0) return; const rng = context?.rng; const idx = rng ? rng.nextInt(0, enemies.length - 1) : Math.floor(Math.random() * enemies.length); const target = enemies[idx]; const dmg = Math.max(0, skill.value - Math.max(0, target.currentArmor)); target.currentHP -= dmg; if (context) { context.mortarTarget = target; context.mortarDamage = dmg; } } flurry(skill, attacker, defender, allies, enemies, context) { context.extraAttacks = (context.extraAttacks || 0) + skill.value; } counter(skill, attacker, defender, allies, enemies, context) { // When defending — deal counter damage to attacker if (context.attackingCard) { const dmg = Math.max(0, skill.value - Math.max(0, context.attackingCard.currentArmor)); context.attackingCard.currentHP -= dmg; } } wall(skill, attacker, defender, allies, enemies, context) { context.damageAbsorb = (context.damageAbsorb || 0) + skill.value; } armored(skill, attacker, defender, allies, enemies, context) { // Passive: reduce incoming damage — handled in combat engine when applying damage context.armoredBonus = (context.armoredBonus || 0) + skill.value; } valor(skill, attacker, defender, allies, enemies) { if (enemies.length > allies.length) { attacker.currentAttack += skill.value; } } legion(skill, attacker, defender, allies) { const sameFaction = allies.filter(a => a.faction === attacker.faction && a !== attacker && a.currentHP > 0); attacker.currentAttack += skill.value * sameFaction.length; } }