/** * Diablo II: Lord of Destruction v1.13c — Druid Milestone M25 Adversarial Challenger Suite * * Empirical verification and adversarial stress-testing across 6 core mechanical dimensions: * 1. Shapeshifted Casting Restrictions (Armageddon/Hurricane shift aura attachment; spell/summon fail-fast) * 2. Shapeshifting Form Exclusivity (Werewolf <-> Werebear mutual eviction; form-exclusive attack execution) * 3. Cyclone Armor Absorption Invariant (Fire/Cold/Ltng absorption; Physical & Poison complete bypass) * 4. Tornado NextHitDelay (25-frame NextDelay target immunity window) * 5. Feral Rage & Maul Orbs (Formula scaling, charge progression, runtime state application) * 6. Rabies Contagion Mechanics (Poison damage, contagion spread simulation, runtime state attachment) */ import { describe, expect, it } from 'vitest' import { getSharedDataRegistry } from '../../../src/baker/mpq-archive-source.ts' import { UnitStatList } from '../../../src/server/engine/stat-list.ts' import { StateBus } from '../../../src/server/engine/state-bus.ts' import { MissileEngine } from '../../../src/server/engine/missile-engine.ts' import { SummonManager } from '../../../src/server/ai/summon-manager.ts' import { AuraScanner } from '../../../src/server/engine/aura-scanner.ts' import { executeSUnitDmg, type CombatUnitContext } from '../../../src/server/engine/combat-pipeline.ts' import { executeSkill113c, evaluateSkill113c } from '../../../src/server/skills/registry.ts' import { canCastDruidSkill, calculateFeralRageStats, calculateMaulStats, calculateRabiesStats, advanceChargeOrb, simulateRabiesContagion, } from '../../../src/server/skills/druid-shapeshift.ts' import { simulateCycloneArmorAbsorption, } from '../../../src/server/skills/druid-elemental.ts' function createTestUnit( id: string, name: string, unitType: 'player' | 'monster', maxHp = 1000, ): CombatUnitContext { const statList = new UnitStatList() statList.addStat('maxhp', maxHp) statList.setHp256(maxHp << 8) const stateBus = new StateBus(statList) return { id, name, unitType, statList, stateBus, } } describe('Adversarial Stress Testing — Cohort 6: Druid Elemental & Shapeshifting Skills', () => { // ========================================================================= // Dimension 1: Shapeshifted Casting Restrictions // ========================================================================= describe('Dimension 1: Shapeshifted Casting Restrictions', () => { it('1.1 canCastDruidSkill predicate correctly permits Armageddon (249) and Hurricane (250) in all forms', () => { expect(canCastDruidSkill('human', 249)).toBe(true) expect(canCastDruidSkill('wolf', 249)).toBe(true) expect(canCastDruidSkill('bear', 249)).toBe(true) expect(canCastDruidSkill('human', 250)).toBe(true) expect(canCastDruidSkill('wolf', 250)).toBe(true) expect(canCastDruidSkill('bear', 250)).toBe(true) }) it('1.2 canCastDruidSkill predicate rejects elemental spells and summons in wolf or bear form', () => { const humanOnlySpells = [221, 222, 225, 226, 227, 229, 230, 231, 234, 235, 236, 237, 240, 241, 244, 245, 246, 247] for (const id of humanOnlySpells) { expect(canCastDruidSkill('human', id)).toBe(true) expect(canCastDruidSkill('wolf', id)).toBe(false) expect(canCastDruidSkill('bear', id)).toBe(false) } }) it('1.3 [FAILING / BUG REPRO] executeSkill113c runtime attaches armageddon and hurricane aura states to caster', async () => { const reg = await getSharedDataRegistry() const auraScanner = new AuraScanner(reg) const missileEngine = new MissileEngine(reg) // In Wolf form, cast Armageddon (249) const casterWolf = createTestUnit('dru_w', 'DruidWolf', 'player') casterWolf.stateBus.applyState({ stateNameOrId: 'wolf', slvl: 10, stats: {} }) const skill249 = reg.getSkillById(249)! const eval249 = evaluateSkill113c({ registry: reg, skill: skill249, slvl: 20, blvl: 20, statList: casterWolf.statList, stateBus: casterWolf.stateBus }) const out249 = executeSkill113c({ registry: reg, skill: skill249, evalResult: eval249, caster: casterWolf, targets: [], targetPositions: new Map(), corpses: [], missileEngine, auraScanner, summonManager: null as any, currentTick: 0, targetX: 0, targetY: 0, }) expect(out249.executed).toBe(true) // D2MOO SkillDruid.cpp:957 (SKILLS_SrvDo124_Armageddon_Hurricane) toggles state on caster expect(casterWolf.stateBus.hasState('armageddon')).toBe(true) // In Bear form, cast Hurricane (250) const casterBear = createTestUnit('dru_b', 'DruidBear', 'player') casterBear.stateBus.applyState({ stateNameOrId: 'bear', slvl: 10, stats: {} }) const skill250 = reg.getSkillById(250)! const eval250 = evaluateSkill113c({ registry: reg, skill: skill250, slvl: 20, blvl: 20, statList: casterBear.statList, stateBus: casterBear.stateBus }) const out250 = executeSkill113c({ registry: reg, skill: skill250, evalResult: eval250, caster: casterBear, targets: [], targetPositions: new Map(), corpses: [], missileEngine, auraScanner, summonManager: null as any, currentTick: 0, targetX: 0, targetY: 0, }) expect(out250.executed).toBe(true) expect(casterBear.stateBus.hasState('hurricane')).toBe(true) }) it('1.4 [FAILING / BUG REPRO] executeSkill113c runtime fails fast when casting prohibited elemental spells or summons while shapeshifted', async () => { const reg = await getSharedDataRegistry() const missileEngine = new MissileEngine(reg) const summonManager = new SummonManager(reg) const casterWolf = createTestUnit('dru_w', 'DruidWolf', 'player') casterWolf.stateBus.applyState({ stateNameOrId: 'wolf', slvl: 10, stats: {} }) // Firestorm (225) attempted in wolf form must fail fast (executed = false) const skill225 = reg.getSkillById(225)! const eval225 = evaluateSkill113c({ registry: reg, skill: skill225, slvl: 10, blvl: 10, statList: casterWolf.statList, stateBus: casterWolf.stateBus }) const out225 = executeSkill113c({ registry: reg, skill: skill225, evalResult: eval225, caster: casterWolf, targets: [], targetPositions: new Map(), corpses: [], missileEngine, auraScanner: null as any, summonManager, currentTick: 0, targetX: 100, targetY: 100, }) expect(out225.executed).toBe(false) // Raven (221) attempted in wolf form must fail fast (executed = false) const skill221 = reg.getSkillById(221)! const eval221 = evaluateSkill113c({ registry: reg, skill: skill221, slvl: 10, blvl: 10, statList: casterWolf.statList, stateBus: casterWolf.stateBus }) const out221 = executeSkill113c({ registry: reg, skill: skill221, evalResult: eval221, caster: casterWolf, targets: [], targetPositions: new Map(), corpses: [], missileEngine, auraScanner: null as any, summonManager, currentTick: 0, targetX: 100, targetY: 100, }) expect(out221.executed).toBe(false) }) }) // ========================================================================= // Dimension 2: Shapeshifting Form Exclusivity // ========================================================================= describe('Dimension 2: Shapeshifting Form Exclusivity', () => { it('2.1 Casting Werebear while Werewolf is active evicts Werewolf state and applies Werebear', async () => { const reg = await getSharedDataRegistry() const caster = createTestUnit('dru_1', 'DruidCaster', 'player') // 1. Cast Werewolf const skill223 = reg.getSkillById(223)! const eval223 = evaluateSkill113c({ registry: reg, skill: skill223, slvl: 10, blvl: 10, statList: caster.statList, stateBus: caster.stateBus }) executeSkill113c({ registry: reg, skill: skill223, evalResult: eval223, caster, targets: [], targetPositions: new Map(), corpses: [], missileEngine: null as any, auraScanner: null as any, summonManager: null as any, currentTick: 0, targetX: 0, targetY: 0, }) expect(caster.stateBus.hasState('wolf')).toBe(true) expect(caster.stateBus.hasState('bear')).toBe(false) // 2. Cast Werebear -> wolf must be evicted const skill228 = reg.getSkillById(228)! const eval228 = evaluateSkill113c({ registry: reg, skill: skill228, slvl: 10, blvl: 10, statList: caster.statList, stateBus: caster.stateBus }) executeSkill113c({ registry: reg, skill: skill228, evalResult: eval228, caster, targets: [], targetPositions: new Map(), corpses: [], missileEngine: null as any, auraScanner: null as any, summonManager: null as any, currentTick: 10, targetX: 0, targetY: 0, }) expect(caster.stateBus.hasState('wolf')).toBe(false) expect(caster.stateBus.hasState('bear')).toBe(true) }) it('2.2 [FAILING / BUG REPRO] executeSkill113c rejects Werewolf attacks in Bear or Human form, and Werebear attacks in Wolf or Human form', async () => { const reg = await getSharedDataRegistry() const missileEngine = new MissileEngine(reg) const target = createTestUnit('m1', 'Fallen', 'monster') // Human casting Feral Rage (232) must be rejected const casterHuman = createTestUnit('dru_h', 'DruidHuman', 'player') const skill232 = reg.getSkillById(232)! const eval232 = evaluateSkill113c({ registry: reg, skill: skill232, slvl: 10, blvl: 10, statList: casterHuman.statList, stateBus: casterHuman.stateBus }) const out232 = executeSkill113c({ registry: reg, skill: skill232, evalResult: eval232, caster: casterHuman, targets: [target], targetPositions: new Map(), corpses: [], missileEngine, auraScanner: null as any, summonManager: null as any, currentTick: 0, targetX: 0, targetY: 0, }) expect(out232.executed).toBe(false) // Wolf casting Maul (233) must be rejected const casterWolf = createTestUnit('dru_w', 'DruidWolf', 'player') casterWolf.stateBus.applyState({ stateNameOrId: 'wolf', slvl: 10, stats: {} }) const skill233 = reg.getSkillById(233)! const eval233 = evaluateSkill113c({ registry: reg, skill: skill233, slvl: 10, blvl: 10, statList: casterWolf.statList, stateBus: casterWolf.stateBus }) const out233 = executeSkill113c({ registry: reg, skill: skill233, evalResult: eval233, caster: casterWolf, targets: [target], targetPositions: new Map(), corpses: [], missileEngine, auraScanner: null as any, summonManager: null as any, currentTick: 0, targetX: 0, targetY: 0, }) expect(out233.executed).toBe(false) }) }) // ========================================================================= // Dimension 3: Cyclone Armor Absorption Invariant // ========================================================================= describe('Dimension 3: Cyclone Armor Absorption Invariant', () => { it('3.1 Pure simulator: absorbs Fire, Cold, Lightning, and allows Physical and Poison to bypass', () => { const cap = 300 const fRes = simulateCycloneArmorAbsorption(cap, 100, 'fire') expect(fRes.absorbed).toBe(100) expect(fRes.remainingArmor).toBe(200) const cRes = simulateCycloneArmorAbsorption(200, 100, 'cold') expect(cRes.absorbed).toBe(100) expect(cRes.remainingArmor).toBe(100) const lRes = simulateCycloneArmorAbsorption(100, 100, 'lightning') expect(lRes.absorbed).toBe(100) expect(lRes.remainingArmor).toBe(0) expect(lRes.didDissipate).toBe(true) const pRes = simulateCycloneArmorAbsorption(300, 100, 'physical') expect(pRes.absorbed).toBe(0) expect(pRes.penetrated).toBe(100) const psnRes = simulateCycloneArmorAbsorption(300, 100, 'poison') expect(psnRes.absorbed).toBe(0) expect(psnRes.penetrated).toBe(100) }) it('3.2 [FAILING / BUG REPRO] executeSUnitDmg: Poison damage completely bypasses Cyclone Armor and deals direct damage to defender HP', () => { const attacker = createTestUnit('attacker_1', 'PoisonCaster', 'monster') const defender = createTestUnit('defender_1', 'DruidDefender', 'player', 1000) defender.stateBus.applyState({ stateNameOrId: 'cyclonearmor', slvl: 10, stats: { magicarmor: 148 }, }) // 100 Poison damage incoming const poisHit = executeSUnitDmg(attacker, defender, { skillId: 92, // Poison Nova elemType: 'pois', elemMin256: 100 << 8, elemMax256: 100 << 8, isPoison: true, autoHit: true, }) // In authentic 1.13c, Poison damage bypasses Cyclone Armor: // - Cyclone Armor magicarmor remains untouched at 148 // - Defender HP takes full 100 damage (1000 -> 900) expect(defender.stateBus.getState('cyclonearmor')?.stats['magicarmor']).toBe(148) expect(defender.statList.getHp256() >> 8).toBe(900) expect(poisHit.totalDamage).toBe(100) }) it('3.3 executeSUnitDmg: Physical damage completely bypasses Cyclone Armor', () => { const attacker = createTestUnit('attacker_1', 'MeleeMonster', 'monster') const defender = createTestUnit('defender_1', 'DruidDefender', 'player', 1000) defender.stateBus.applyState({ stateNameOrId: 'cyclonearmor', slvl: 10, stats: { magicarmor: 148 }, }) // 100 Physical damage incoming const physHit = executeSUnitDmg(attacker, defender, { skillId: 0, flatPhysMin256: 100 << 8, flatPhysMax256: 100 << 8, autoHit: true, }) // Physical damage bypasses Cyclone Armor: expect(defender.stateBus.getState('cyclonearmor')?.stats['magicarmor']).toBe(148) expect(defender.statList.getHp256() >> 8).toBe(900) expect(physHit.totalDamage).toBe(100) }) }) // ========================================================================= // Dimension 4: Tornado NextHitDelay // ========================================================================= describe('Dimension 4: Tornado NextHitDelay', () => { it('4.1 Tornado missile has NextHit = 1 and NextDelay = 25 in DataRegistry', async () => { const reg = await getSharedDataRegistry() const mRec = reg.getMissileByName('tornado') expect(mRec).toBeDefined() expect(mRec!.nextHit).toBe(true) expect(mRec!.nextDelay).toBe(25) }) it('4.2 MissileEngine enforces 25-frame NextDelay window preventing multi-hits', async () => { const reg = await getSharedDataRegistry() const engine = new MissileEngine(reg) const caster = createTestUnit('dru_1', 'DruidCaster', 'player') const target = createTestUnit('target_1', 'MonsterTarget', 'monster', 1000) const targetPositions = new Map([['target_1', { x: 100, y: 100 }]]) // First tornado hits at tick 0 engine.spawnMissile({ missileNameOrId: 'tornado', sourceSkillId: 245, slvl: 1, owner: caster, startX: 100, startY: 100, targetX: 200, targetY: 100, dmgPacket: { skillId: 245, flatPhysMin256: 100 << 8, flatPhysMax256: 100 << 8 }, }) const hit1 = engine.tick(0, [target], targetPositions) expect(hit1.hits.length).toBe(1) expect(engine.isTargetInNextDelay('target_1', 0)).toBe(true) expect(engine.isTargetInNextDelay('target_1', 24)).toBe(true) expect(engine.isTargetInNextDelay('target_1', 25)).toBe(false) // Second tornado inside immunity window (tick 10) must be blocked engine.spawnMissile({ missileNameOrId: 'tornado', sourceSkillId: 245, slvl: 1, owner: caster, startX: 100, startY: 100, targetX: 200, targetY: 100, dmgPacket: { skillId: 245, flatPhysMin256: 100 << 8, flatPhysMax256: 100 << 8 }, }) const hit2 = engine.tick(10, [target], targetPositions) expect(hit2.hits.length).toBe(0) // Third tornado outside window (tick 26) must hit engine.spawnMissile({ missileNameOrId: 'tornado', sourceSkillId: 245, slvl: 1, owner: caster, startX: 100, startY: 100, targetX: 200, targetY: 100, dmgPacket: { skillId: 245, flatPhysMin256: 100 << 8, flatPhysMax256: 100 << 8 }, }) const hit3 = engine.tick(26, [target], targetPositions) expect(hit3.hits.length).toBe(1) }) }) // ========================================================================= // Dimension 5: Feral Rage & Maul Orbs // ========================================================================= describe('Dimension 5: Feral Rage & Maul Orbs', () => { it('5.1 Feral Rage formulas: 3 stages, 4*slvl% life leech, dm(10, 70, slvl) speed, 20.0s decay timer', () => { const fr1 = calculateFeralRageStats(1) expect(fr1.maxCharges).toBe(3) expect(fr1.lifeLeechPct).toBe(4) expect(fr1.velocityBonusPct).toBe(19) expect(fr1.durationFrames).toBe(500) expect(fr1.durationSeconds).toBe(20.0) const fr10 = calculateFeralRageStats(10) expect(fr10.lifeLeechPct).toBe(40) expect(fr10.velocityBonusPct).toBe(51) const fr20 = calculateFeralRageStats(20) expect(fr20.lifeLeechPct).toBe(80) expect(fr20.velocityBonusPct).toBe(60) // Charge progression caps at 3 let charges = 0 charges = advanceChargeOrb(charges, 3) expect(charges).toBe(1) charges = advanceChargeOrb(charges, 3) expect(charges).toBe(2) charges = advanceChargeOrb(charges, 3) expect(charges).toBe(3) charges = advanceChargeOrb(charges, 3) expect(charges).toBe(3) }) it('5.2 Maul formulas: 5 stages, slvl*20% damage/charge (slvl*100% max), dm(10, 100, slvl) stun, 20.0s decay timer', () => { const m1 = calculateMaulStats(1) expect(m1.maxCharges).toBe(5) expect(m1.damageBonusPerChargePct).toBe(20) expect(m1.maxDamageBonusPct).toBe(100) expect(m1.stunDurationFrames).toBe(24) expect(m1.durationFrames).toBe(500) expect(m1.durationSeconds).toBe(20.0) const m10 = calculateMaulStats(10) expect(m10.damageBonusPerChargePct).toBe(200) expect(m10.maxDamageBonusPct).toBe(1000) expect(m10.stunDurationFrames).toBe(71) const m20 = calculateMaulStats(20) expect(m20.damageBonusPerChargePct).toBe(400) expect(m20.maxDamageBonusPct).toBe(2000) expect(m20.stunDurationFrames).toBe(86) }) it('5.3 [FAILING / BUG REPRO] executeSkill113c runtime attaches feralrage and maul states to caster on hit', async () => { const reg = await getSharedDataRegistry() const caster = createTestUnit('dru_w', 'DruidWolf', 'player') caster.stateBus.applyState({ stateNameOrId: 'wolf', slvl: 10, stats: {} }) const target = createTestUnit('m1', 'TargetMonster', 'monster', 1000) const skill232 = reg.getSkillById(232)! const eval232 = evaluateSkill113c({ registry: reg, skill: skill232, slvl: 10, blvl: 10, statList: caster.statList, stateBus: caster.stateBus }) const out232 = executeSkill113c({ registry: reg, skill: skill232, evalResult: eval232, caster, targets: [target], targetPositions: new Map(), corpses: [], missileEngine: null as any, auraScanner: null as any, summonManager: null as any, currentTick: 0, targetX: 0, targetY: 0, }) // On successful hit, Feral Rage attaches feralrage charge state expect(out232.statesApplied).toContain('feralrage') expect(caster.stateBus.hasState('feralrage')).toBe(true) }) }) // ========================================================================= // Dimension 6: Rabies Contagion Mechanics // ========================================================================= describe('Dimension 6: Rabies Contagion Mechanics', () => { it('6.1 simulateRabiesContagion spreads infection to adjacent targets within 128px radius', () => { const infected = [{ id: 'target_0', x: 100, y: 100 }] const healthy = [ { id: 'target_close_1', x: 120, y: 105 }, { id: 'target_close_2', x: 80, y: 95 }, { id: 'target_far', x: 400, y: 400 }, ] const newlyInfected = simulateRabiesContagion(infected, healthy, 128) expect(newlyInfected).toContain('target_close_1') expect(newlyInfected).toContain('target_close_2') expect(newlyInfected).not.toContain('target_far') }) it('6.2 Rabies formulas: 5-band poison damage, +18%/blvl Poison Creeper synergy, 4..8s duration', () => { const r1 = calculateRabiesStats(1, 0) expect(r1.minPoisonDamage).toBe(6) expect(r1.maxPoisonDamage).toBe(14) expect(r1.poisonDurationFrames).toBe(100) expect(r1.poisonDurationSeconds).toBe(4.0) const r20 = calculateRabiesStats(20, 20) expect(r20.synergyBonusPct).toBe(360) expect(r20.poisonDurationFrames).toBe(290) // 100 + 19*10 expect(r20.poisonDurationSeconds).toBe(11.6) }) it('6.3 [FAILING / BUG REPRO] executeSkill113c runtime infects hit target with rabies state', async () => { const reg = await getSharedDataRegistry() const caster = createTestUnit('dru_w', 'DruidWolf', 'player') caster.stateBus.applyState({ stateNameOrId: 'wolf', slvl: 10, stats: {} }) const target = createTestUnit('m1', 'TargetMonster', 'monster', 1000) const skill238 = reg.getSkillById(238)! const eval238 = evaluateSkill113c({ registry: reg, skill: skill238, slvl: 10, blvl: 10, statList: caster.statList, stateBus: caster.stateBus }) const out238 = executeSkill113c({ registry: reg, skill: skill238, evalResult: eval238, caster, targets: [target], targetPositions: new Map(), corpses: [], missileEngine: null as any, auraScanner: null as any, summonManager: null as any, currentTick: 0, targetX: 0, targetY: 0, }) // Hit target must receive rabies infection state expect(target.stateBus.hasState('rabies')).toBe(true) }) }) })