feat: implement sword/melee auto-attack system (spec §3.1, §4.3)
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m1s

- Add calcMeleeDamage() with elemental matchup for enchanted swords
- Add meleeSwordProgress per-instance accumulator to combat state
- Add melee branch in processCombatTick (no mana cost, no Executioner/Berserker)
- Add baseDamage/attackSpeed stats to all 5 sword types
- Wire equippedSwords through gameStore to combat tick pipeline
- 16 new regression tests, all 937 tests pass
This commit is contained in:
2026-06-03 21:59:30 +02:00
parent b506f0bcc3
commit 8dde423526
10 changed files with 564 additions and 183 deletions
+49
View File
@@ -273,6 +273,55 @@ export function deductSpellCost(
return { rawMana, elements: newElements };
}
// ─── Melee Damage Calculation (spec §4.3) ────────────────────────────────────
/**
* Map from sword enchantment specialId to element type for elemental matchup.
*/
const SWORD_ENCHANT_ELEMENT: Record<string, string> = {
fireBlade: 'fire',
frostBlade: 'frost',
lightningBlade: 'lightning',
voidBlade: 'void',
};
/**
* Calculate melee damage for a sword attack (spec §4.3).
*
* Formula: baseDmg = sword.baseDamage + sword.elementalEnchantDamage
* damage = baseDmg × getElementalBonus(sword.enchantElement, enemy.element)
*
* No crit, no discipline damage bonus for melee in v1.
* attackSpeedMult from equipment does apply to meleeProgress accumulation.
*/
export function calcMeleeDamage(
swordInstance: EquipmentInstance,
swordType: { stats?: { baseDamage?: number } },
enemyElement: string,
): number {
const baseDmg = swordType.stats?.baseDamage || 5;
// Determine enchant element from sword's enchantments
let enchantElement: string | null = null;
for (const ench of swordInstance.enchantments) {
const effectDef = ENCHANTMENT_EFFECTS[ench.effectId];
if (effectDef?.effect.type === 'special' && effectDef.effect.specialId) {
const elem = SWORD_ENCHANT_ELEMENT[effectDef.effect.specialId];
if (elem) {
enchantElement = elem;
break;
}
}
}
// Apply elemental bonus if sword has an elemental enchant
if (enchantElement) {
return baseDmg * getElementalBonus(enchantElement, enemyElement);
}
return baseDmg;
}
// ─── Equipment Spell Helpers ──────────────────────────────────────────────────
// Return type for active equipment spells with source equipment