[Critical] [Bug] Spire combat: 11 high-severity discrepancies including wrong dodge formula, missing guardian armor, broken elemental counters #333
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Spec:
docs/specs/spire-combat-spec.mdDiscrepancies found:
D-01 [HIGH] — Single global
castProgressinstead of per-weapon timersweaponCastProgress: Record<instanceId, number>)combat-actions.ts): Uses a single scalarcastProgressonCombatState. The multi-spell equipment path usesequipmentSpellStates[].castProgress, but the primary active spell uses one global counter.D-04 [HIGH] — Golem attacks trigger Executioner/Berserker (spec says golems ignore)
golem-combat-actions.ts): Golem damage flows throughonDamageDealtwhich applies Executioner and BerserkeronDamageDealtfor golem attacks or add a flag to skip discipline specialsD-09 [HIGH] — Elemental counter
lightning → earthcontradicts speclightning → waterlightning → water(lightning counters water),earth → lightning(earth counters lightning)elements.ts):lightning: 'earth'(lightning counters earth)D-10 [HIGH] — Composite element counters incomplete
ELEMENT_OPPOSITES): Only definesblackflame: 'light'andradiantflames: 'dark'— missing frost and water interactionsELEMENT_OPPOSITESD-15 [HIGH] — Executioner checks floor-level HP, not per-enemy HP
combat-tick.ts:183): Checksctx.combat.floorHP / ctx.combat.floorMaxHP < 0.25(floor aggregate)D-20 [HIGH] — Dodge formula differs massively from spec
dodgeChance = min(0.55, floor × 0.003)— starts at 0enemy-generator.ts):baseDodge = 0.20,dodgePerFloor = 0.004— starts at 0.20D-22 [HIGH] — Shield modifier sets percentage barrier, not flat one-time pool
barrier = 0.15(percentage reduction), identical to mage modifierD-23 [HIGH] —
applyMageBarrierRechargedefined but never called (dead code)combat-tick.ts:173-179buildCombatCallbacksormakeOnDamageDealtD-25 [HIGH] — Guardian regen fires per-damage-event, not per-tick
combat-tick.ts:194-198): Regen applied inside per-hitonDamageDealtcallback — fires multiple times per tick if multiple spells hitD-26 [HIGH] — Guardian armor never applied in pipeline
GuardianDef.armoris defined in data but never applied inmakeOnDamageDealtD-31 [HIGH] —
armor_corrodepermanently reduces armor with no restoredot-runtime.ts:115):enemyArmor = Math.max(0, enemyArmor - effect.magnitude)— permanently reduces with no restore on expireeffectiveArmorseparatelyD-38 [MEDIUM] — AoE spells damage all enemies fully;
aoeTargetsunusedcombat-damage.ts): Every enemy takes full damage.aoeTargetsfield stored but never used.aoeTargetsStarting work on issue #333. Reading spec and all affected source files to build a complete picture before implementing fixes.
All 12 fixes implemented and pushed to master (commit
098ec86):D-01 ✅ Per-weapon cast progress via
weaponCastProgress: Record<string, number>on CombatStateD-04 ✅ Added
skipSpecialsparameter toonDamageDealt; golem attacks passtrueto bypass Executioner/BerserkerD-09 ✅ Fixed
ELEMENT_OPPOSITESto use arrays; lightning now correctly counters water (not earth)D-10 ✅ Full composite counter table: blackflame↔frost/water/light, radiantflames↔frost/water/dark (all bidirectional)
D-15 ✅ Executioner now checks
defCtx.enemy.hp < enemy.maxHP * 0.25instead of floorHP ratioD-20 ✅ Dodge formula:
baseDodge: 0, dodgePerFloor: 0.003(starts at 0, not 0.20)D-22 ✅ Shield modifier sets
shieldPool(flat HP = 15% maxHP) instead ofbarrier(percentage)D-23 ✅ Mage barrier recharge wired into
onDamageDealtcallback (runs per damage event)D-25 ✅ Guardian shield/barrier regen moved to
applyGuardianRegen()called once per tickD-26 ✅ Guardian armor reduction added to the guardian defensive pipeline
D-31 ✅
armor_corrodenow accumulates magnitude and computeseffectiveArmorfrom base armor (temporary)D-38 ✅ AoE damage distributed across up to
aoeTargetsenemies (focus-fire: lowest HP first)All 1069 tests pass. No files exceed 400 lines.