fix: spire combat 11 high-severity discrepancies (issue #333)
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m19s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m19s
D-01: Implement per-weapon cast progress (weaponCastProgress record) D-04: Bypass Executioner/Berserker discipline specials for golem attacks D-09: Fix lightning counter direction (lightning→water, not lightning→earth) D-10: Add full composite element counters (blackflame/radiantflames ↔ frost/water/light/dark) D-15: Fix Executioner to check per-enemy HP < 25% instead of floorHP ratio D-20: Fix dodge formula to match spec (min(0.55, floor × 0.003), starts at 0) D-22: Fix shield modifier to use flat HP pool instead of percentage barrier D-23: Wire up applyMageBarrierRecharge in the damage pipeline D-25: Move guardian regen from per-damage-event to once-per-tick D-26: Add guardian armor reduction to the guardian defensive pipeline D-31: Fix armor_corrode to be temporary (restore armor on effect expiry) D-38: Implement AoE damage distribution across enemies All 1069 tests pass. No files exceed 400 lines.
This commit is contained in:
@@ -23,11 +23,12 @@ export function lowestHPEnemy(enemies: EnemyState[]): EnemyState | null {
|
||||
* Apply damage to enemies in the current room.
|
||||
*
|
||||
* Spec §3.2:
|
||||
* - AoE spells: each enemy takes full damage
|
||||
* - AoE spells: damage is distributed across up to aoeTargets enemies
|
||||
* - Single-target: target the enemy with lowest HP (focus-fire)
|
||||
* - Recalculates floorHP as sum of all enemy HP
|
||||
* - Triggers onRoomCleared when all enemies reach 0 HP
|
||||
*
|
||||
* @param aoeTargets — max number of enemies hit by AoE (spec §3.2, D-38 fix)
|
||||
* @returns { floorHP, floorMaxHP, roomCleared }
|
||||
*/
|
||||
export function applyDamageToRoom(
|
||||
@@ -35,6 +36,7 @@ export function applyDamageToRoom(
|
||||
set: (state: Partial<CombatState>) => void,
|
||||
dmg: number,
|
||||
isAoe: boolean,
|
||||
aoeTargets?: number,
|
||||
): { floorHP: number; floorMaxHP: number; roomCleared: boolean } {
|
||||
const state = get();
|
||||
const room = state.currentRoom;
|
||||
@@ -48,11 +50,23 @@ export function applyDamageToRoom(
|
||||
// For single-target, find the lowest HP enemy once (focus-fire)
|
||||
const singleTarget = isAoe ? null : lowestHPEnemy(room.enemies);
|
||||
|
||||
// For AoE, select up to aoeTargets living enemies (focus-fire: lowest HP first)
|
||||
let aoeTargetSet: Set<string> | null = null;
|
||||
if (isAoe && aoeTargets && aoeTargets > 0) {
|
||||
const livingEnemies = room.enemies
|
||||
.filter(e => e.hp > 0)
|
||||
.sort((a, b) => a.hp - b.hp);
|
||||
const targets = livingEnemies.slice(0, aoeTargets);
|
||||
aoeTargetSet = new Set(targets.map(e => e.id));
|
||||
}
|
||||
|
||||
const updatedEnemies = room.enemies.map((enemy) => {
|
||||
if (enemy.hp <= 0) return enemy;
|
||||
if (isAoe) {
|
||||
// AoE: each enemy takes full damage
|
||||
return { ...enemy, hp: Math.max(0, enemy.hp - dmg) };
|
||||
// AoE: distribute damage across up to aoeTargets enemies (spec §3.2, D-38 fix)
|
||||
if (aoeTargetSet && !aoeTargetSet.has(enemy.id)) return enemy;
|
||||
const dmgPerEnemy = aoeTargetSet ? dmg / aoeTargetSet.size : dmg;
|
||||
return { ...enemy, hp: Math.max(0, enemy.hp - dmgPerEnemy) };
|
||||
}
|
||||
// Single-target: only damage the lowest HP enemy
|
||||
if (singleTarget && enemy.id === singleTarget.id) {
|
||||
|
||||
Reference in New Issue
Block a user