diablo2-web/tests/skills/sor/adv-cold-m2-aoe-stress.test.ts

820 lines
32 KiB
TypeScript

/**
* Adversarial Stress & Boundary Testing Suite — Milestone 2: Cold Projectiles & Cold Mastery
* Commit: 375f329
*
* Focus Areas:
* 1. Glacial Spike 64px (4 subtiles) Radial Burst Boundary Verification:
* - Distance boundary sweeps: 0px, 30px, 63px, 64px, 64.1px, 65px, 80px, 128px.
* - Strict inequality validation: units at <= 64px receive full cold damage & solid freeze;
* units at > 64px receive 0 splash damage and 0 freeze.
* - Multi-directional radial boundary test across 8 compass axes (0°, 45°, 90°, ..., 315°).
* 2. Obstacle & Wall Collision Detonation:
* - Collision against terrain obstacle (COLLIDE_WALL).
* - Immediate detonation at impact coordinates (hitWallX, hitWallY).
* - Submissile ejection verification: 'glacialspikeejecta' and explosion missile spawned.
* - 64px AoE burst applied to adjacent units from the wall impact point.
* 3. Freeze Application & Immunity:
* - Cannot Be Frozen (cannot_be_frozen > 0): receives cold damage, but freeze state is skipped.
* - Cold Immunity (coldresist >= 100): 0 damage, freeze state is skipped, immune flag set.
* - Standard targets: receive cold damage and 'freeze' state.
* 4. Cold Mastery Resistance Sweeps (-100% to +200% against slvl 1 to 50):
* - Systematic sweep of base cold resistance across [-100%, +200%] vs slvl 1..50.
* - Natural immunity rule: Cold Mastery alone NEVER pierces cold immune targets (res >= 100%).
* - Broken immunity rule: when Conviction/Lower Resist reduces res < 100%, Cold Mastery applies at full power.
* - Strict -100% floor clamp: effective resistance never drops below -100% (max 2.0x multiplier).
* - Differential fuzzing against brute-force mathematical oracle (1000 randomized iterations).
*/
import { describe, expect, it } from 'vitest'
import { getSharedDataRegistry } from '../../../src/game/engine/data-registry.ts'
import { UnitStatList } from '../../../src/game/engine/stat-list.ts'
import { StateBus } from '../../../src/game/engine/state-bus.ts'
import {
MissileEngine,
calculateGlacialSpikeDamage,
calculateGlacialSpikeFreezeLength,
calculateColdMasteryPierce,
} from '../../../src/game/engine/missile-engine.ts'
import {
computeEffectiveResistance,
executeSUnitDmg,
type CombatUnitContext,
} from '../../../src/game/engine/combat-pipeline.ts'
import { COLLIDE_WALL } from '../../../src/game/d2map.ts'
function createMockCombatUnit(
id: string,
options?: {
hp?: number
coldResist?: number
cannotBeFrozen?: boolean
coldMasterySlvl?: number
allSkills?: number
},
): CombatUnitContext {
const statList = new UnitStatList()
const hp = options?.hp ?? 500
statList.setBaseStat('hp', hp * 256)
statList.setBaseStat('maxhp', hp * 256)
statList.setBaseStat('hitpoints', hp * 256)
if (options?.coldResist !== undefined) {
statList.setBaseStat('coldresist', options.coldResist)
}
if (options?.cannotBeFrozen) {
statList.setBaseStat('cannot_be_frozen', 1)
}
if (options?.coldMasterySlvl !== undefined && options.coldMasterySlvl > 0) {
const pierce = calculateColdMasteryPierce(options.coldMasterySlvl)
statList.setBaseStat('passive_cold_pierce', pierce)
}
if (options?.allSkills) {
statList.setAllSkillsBonus(options.allSkills)
}
const stateBus = new StateBus(statList)
return {
id,
name: id,
statList,
stateBus,
}
}
describe('Adversarial Stress Suite — Glacial Spike AoE & Cold Mastery (Commit 375f329)', () => {
// =========================================================================
// Requirement 1: Glacial Spike 64px Radial Burst Verification
// =========================================================================
describe('Requirement 1: Glacial Spike 64px Radial Burst Boundary Verification', () => {
it('verifies exact distance boundaries: 0px, 30px, 63px, 64px receive hit/freeze; 64.1px, 65px, 80px, 128px receive 0 hit/freeze', async () => {
const registry = await getSharedDataRegistry()
const engine = new MissileEngine(registry)
const attacker = createMockCombatUnit('sorceress')
// Direct target at (0, 0)
const directTarget = createMockCombatUnit('target_0px')
// Distances to test
const testDistances = [
{ label: 'target_30px', dist: 30, shouldHit: true },
{ label: 'target_63px', dist: 63, shouldHit: true },
{ label: 'target_64px', dist: 64, shouldHit: true },
{ label: 'target_64_1px', dist: 64.1, shouldHit: false },
{ label: 'target_65px', dist: 65, shouldHit: false },
{ label: 'target_80px', dist: 80, shouldHit: false },
{ label: 'target_128px', dist: 128, shouldHit: false },
]
const splashTargets = testDistances.map(td => ({
...td,
unit: createMockCombatUnit(td.label),
}))
const allTargets = [directTarget, ...splashTargets.map(st => st.unit)]
// Target positions relative to impact point (0, 0)
const targetPositions = new Map<string, { x: number; y: number }>()
targetPositions.set('target_0px', { x: 0, y: 0 })
for (const st of splashTargets) {
targetPositions.set(st.label, { x: st.dist, y: 0 })
}
// Spawn missile flying from (-24, 0) straight towards (0, 0)
engine.spawnMissile({
missileNameOrId: 'glacialspike',
sourceSkillId: 55,
slvl: 10,
owner: attacker,
startX: -24,
startY: 0,
targetX: 0,
targetY: 0,
dmgPacket: {
skillId: 55,
elemType: 'cold',
elemMin256: 100 * 256,
elemMax256: 100 * 256,
elemDurationFrames: 77,
autoHit: true,
},
vx: 24,
vy: 0,
maxRangeTicks: 40,
})
// Tick engine to resolve collision with direct target at (0, 0)
const outcome = engine.tick(1, allTargets, targetPositions)
// Direct hit on target_0px
const directHit = outcome.hits.find(h => h.targetId === 'target_0px')
expect(directHit).toBeDefined()
expect(directHit!.damage).toBeGreaterThan(0)
expect(directTarget.stateBus.hasState('freeze')).toBe(true)
// Verify each splash target
for (const st of splashTargets) {
const hit = outcome.hits.find(h => h.targetId === st.label)
if (st.shouldHit) {
expect(hit, `Target at ${st.dist}px should receive splash hit`).toBeDefined()
expect(hit!.missileName).toContain('splash')
expect(hit!.damage, `Target at ${st.dist}px should receive cold damage`).toBeGreaterThan(0)
expect(
st.unit.stateBus.hasState('freeze'),
`Target at ${st.dist}px should have solid freeze state`,
).toBe(true)
} else {
expect(hit, `Target at ${st.dist}px should NOT receive splash hit`).toBeUndefined()
expect(
st.unit.stateBus.hasState('freeze'),
`Target at ${st.dist}px should NOT have solid freeze state`,
).toBe(false)
}
}
})
it('verifies 360-degree radial symmetry across 8 directional axes at r=63.9px (hit) vs r=64.1px (miss)', async () => {
const registry = await getSharedDataRegistry()
const engine = new MissileEngine(registry)
const attacker = createMockCombatUnit('sorceress')
// Direct target at (100, 100)
const center = { x: 100, y: 100 }
const directTarget = createMockCombatUnit('center_target')
const angles = [
{ name: 'E', rad: 0 },
{ name: 'NE', rad: Math.PI / 4 },
{ name: 'N', rad: Math.PI / 2 },
{ name: 'NW', rad: (3 * Math.PI) / 4 },
{ name: 'W', rad: Math.PI },
{ name: 'SW', rad: (5 * Math.PI) / 4 },
{ name: 'S', rad: (3 * Math.PI) / 2 },
{ name: 'SE', rad: (7 * Math.PI) / 4 },
]
const insideUnits: CombatUnitContext[] = []
const outsideUnits: CombatUnitContext[] = []
const targetPositions = new Map<string, { x: number; y: number }>()
targetPositions.set('center_target', center)
for (const dir of angles) {
// Inside boundary: r = 63.9 px
const inId = `inside_${dir.name}`
const inUnit = createMockCombatUnit(inId)
insideUnits.push(inUnit)
targetPositions.set(inId, {
x: center.x + 63.9 * Math.cos(dir.rad),
y: center.y + 63.9 * Math.sin(dir.rad),
})
// Outside boundary: r = 64.1 px
const outId = `outside_${dir.name}`
const outUnit = createMockCombatUnit(outId)
outsideUnits.push(outUnit)
targetPositions.set(outId, {
x: center.x + 64.1 * Math.cos(dir.rad),
y: center.y + 64.1 * Math.sin(dir.rad),
})
}
const allTargets = [directTarget, ...insideUnits, ...outsideUnits]
engine.spawnMissile({
missileNameOrId: 'glacialspike',
sourceSkillId: 55,
slvl: 10,
owner: attacker,
startX: center.x - 24,
startY: center.y,
targetX: center.x,
targetY: center.y,
dmgPacket: {
skillId: 55,
elemType: 'cold',
elemMin256: 100 * 256,
elemMax256: 100 * 256,
elemDurationFrames: 77,
autoHit: true,
},
vx: 24,
vy: 0,
maxRangeTicks: 40,
})
const outcome = engine.tick(1, allTargets, targetPositions)
// Direct hit passes
expect(outcome.hits.find(h => h.targetId === 'center_target')).toBeDefined()
// All 8 inside units receive splash hit and freeze
for (const inUnit of insideUnits) {
const hit = outcome.hits.find(h => h.targetId === inUnit.id)
expect(hit, `${inUnit.id} (r=63.9px) must be hit`).toBeDefined()
expect(hit!.damage).toBeGreaterThan(0)
expect(inUnit.stateBus.hasState('freeze'), `${inUnit.id} must be frozen`).toBe(true)
}
// All 8 outside units receive 0 hit and no freeze
for (const outUnit of outsideUnits) {
const hit = outcome.hits.find(h => h.targetId === outUnit.id)
expect(hit, `${outUnit.id} (r=64.1px) must NOT be hit`).toBeUndefined()
expect(outUnit.stateBus.hasState('freeze'), `${outUnit.id} must NOT be frozen`).toBe(false)
}
})
it('handles high-density multi-target clustering inside and outside 64px radius', async () => {
const registry = await getSharedDataRegistry()
const engine = new MissileEngine(registry)
const attacker = createMockCombatUnit('sorceress')
const center = { x: 50, y: 50 }
const directTarget = createMockCombatUnit('cluster_direct')
const targetPositions = new Map<string, { x: number; y: number }>()
targetPositions.set('cluster_direct', center)
// Generate 20 units inside (radius 10..60px) and 20 units outside (radius 70..150px)
const units: CombatUnitContext[] = [directTarget]
const insideIds = new Set<string>()
const outsideIds = new Set<string>()
for (let i = 0; i < 20; i++) {
const id = `dense_in_${i}`
const radius = 10 + (i / 19) * 53 // 10 to 63 px (strictly inside 64px boundary)
const theta = (i * 2.4)
targetPositions.set(id, {
x: center.x + radius * Math.cos(theta),
y: center.y + radius * Math.sin(theta),
})
units.push(createMockCombatUnit(id))
insideIds.add(id)
}
for (let i = 0; i < 20; i++) {
const id = `dense_out_${i}`
const radius = 64.5 + i * 4 // 64.5 to 140.5 px
const theta = (i * 1.7)
targetPositions.set(id, {
x: center.x + radius * Math.cos(theta),
y: center.y + radius * Math.sin(theta),
})
units.push(createMockCombatUnit(id))
outsideIds.add(id)
}
engine.spawnMissile({
missileNameOrId: 'glacialspike',
sourceSkillId: 55,
slvl: 20,
owner: attacker,
startX: center.x - 20,
startY: center.y,
targetX: center.x,
targetY: center.y,
dmgPacket: {
skillId: 55,
elemType: 'cold',
elemMin256: 200 * 256,
elemMax256: 200 * 256,
elemDurationFrames: 107,
autoHit: true,
},
vx: 20,
vy: 0,
maxRangeTicks: 40,
})
const outcome = engine.tick(1, units, targetPositions)
// Direct target hit
expect(outcome.hits.find(h => h.targetId === 'cluster_direct')).toBeDefined()
// Exactly all 20 inside units hit
for (const id of insideIds) {
const hit = outcome.hits.find(h => h.targetId === id)
expect(hit, `Inside cluster unit ${id} should be hit`).toBeDefined()
const unit = units.find(u => u.id === id)!
expect(unit.stateBus.hasState('freeze')).toBe(true)
}
// Exactly all 20 outside units NOT hit
for (const id of outsideIds) {
const hit = outcome.hits.find(h => h.targetId === id)
expect(hit, `Outside cluster unit ${id} should NOT be hit`).toBeUndefined()
const unit = units.find(u => u.id === id)!
expect(unit.stateBus.hasState('freeze')).toBe(false)
}
})
})
// =========================================================================
// Requirement 2: Obstacle & Wall Collision Detonation
// =========================================================================
describe('Requirement 2: Obstacle & Wall Collision Detonation', () => {
it('detonates immediately upon hitting a COLLIDE_WALL tile, spawning submissiles and bursting 64px', async () => {
const registry = await getSharedDataRegistry()
const engine = new MissileEngine(registry)
const attacker = createMockCombatUnit('sorceress')
// Wall at x >= 50
// Collision map using overlap returning COLLIDE_WALL (0x0001)
const wallTerrain = {
overlap: (x: number, _y: number) => (x >= 50 ? COLLIDE_WALL : 0),
}
// Adjacent monster placed along the wall at (50, 35):
// - Far enough from flight path y=0 that it avoids direct missile body collision (dist > hitRadius 28px)
// - Distance from wall impact point (50, 0) is 35px <= 64px (hit by splash explosion)
const nearMonster = createMockCombatUnit('near_wall_monster')
// Distant monster at (50, 100): distance from wall impact point (50, 0) is 100px > 64px
const farMonster = createMockCombatUnit('far_wall_monster')
const targets = [nearMonster, farMonster]
const targetPositions = new Map<string, { x: number; y: number }>([
['near_wall_monster', { x: 50, y: 35 }],
['far_wall_monster', { x: 50, y: 100 }],
])
// Spawn projectile starting at (0, 0) moving with vx = 24 towards wall
engine.spawnMissile({
missileNameOrId: 'glacialspike',
sourceSkillId: 55,
slvl: 10,
owner: attacker,
startX: 0,
startY: 0,
targetX: 100,
targetY: 0,
dmgPacket: {
skillId: 55,
elemType: 'cold',
elemMin256: 91 * 256,
elemMax256: 103 * 256,
elemDurationFrames: 77,
autoHit: true,
},
vx: 24,
vy: 0,
maxRangeTicks: 40,
})
// Tick 1: moves from 0 to 24 (not blocked)
const tick1 = engine.tick(1, targets, targetPositions, wallTerrain)
expect(tick1.hits.length).toBe(0)
expect(tick1.subMissilesSpawned.length).toBe(0)
// Tick 2: moves from 24 to 48 (not blocked)
const tick2 = engine.tick(1, targets, targetPositions, wallTerrain)
expect(tick2.hits.length).toBe(0)
expect(tick2.subMissilesSpawned.length).toBe(0)
// Tick 3: moves from 48 to 72. Crosses wall at x=50.
// Continuous collision stepping stops at wall impact point (50, 0)!
const tick3 = engine.tick(1, targets, targetPositions, wallTerrain)
// 1. Immediate AoE burst hit on nearMonster
expect(tick3.hits.length).toBe(1)
expect(tick3.hits[0]!.targetId).toBe('near_wall_monster')
expect(tick3.hits[0]!.missileName).toContain('splash')
expect(tick3.hits[0]!.damage).toBeGreaterThan(0)
expect(nearMonster.stateBus.hasState('freeze')).toBe(true)
// Far monster unaffected
expect(farMonster.stateBus.hasState('freeze')).toBe(false)
// 2. Submissile ejection: 'glacialspikeejecta' and explosion missile
expect(tick3.subMissilesSpawned).toContain('glacialspikeejecta')
expect(tick3.subMissilesSpawned).toContain('freezeexplode')
// 3. Projectile expires upon impact
const activeSpikes = engine.getActiveMissiles().filter(m => m.name === 'glacialspike')
expect(activeSpikes.length).toBe(0)
})
it('verifies continuous stepping prevents tunneling through thin (<24px) walls and detonates correctly', async () => {
const registry = await getSharedDataRegistry()
const engine = new MissileEngine(registry)
const attacker = createMockCombatUnit('sorceress')
// Thin wall only 8px wide between x=32 and x=40
const thinWallTerrain = {
overlap: (x: number, _y: number) => (x >= 32 && x <= 40 ? COLLIDE_WALL : 0),
}
// Unit stationed right next to the thin wall at (35, 15)
const adjacentUnit = createMockCombatUnit('thin_wall_unit')
const targetPositions = new Map<string, { x: number; y: number }>([
['thin_wall_unit', { x: 35, y: 15 }],
])
// Projectile moves 24px per tick, starting at x=20.
// Next step would land at x=44 (beyond the thin wall), but stepping catches x=32!
engine.spawnMissile({
missileNameOrId: 'glacialspike',
sourceSkillId: 55,
slvl: 10,
owner: attacker,
startX: 20,
startY: 0,
targetX: 100,
targetY: 0,
dmgPacket: {
skillId: 55,
elemType: 'cold',
elemMin256: 100 * 256,
elemMax256: 100 * 256,
elemDurationFrames: 77,
autoHit: true,
},
vx: 24,
vy: 0,
maxRangeTicks: 40,
})
const outcome = engine.tick(1, [adjacentUnit], targetPositions, thinWallTerrain)
expect(outcome.hits.length).toBe(1)
expect(outcome.hits[0]!.targetId).toBe('thin_wall_unit')
expect(adjacentUnit.stateBus.hasState('freeze')).toBe(true)
expect(outcome.subMissilesSpawned).toContain('glacialspikeejecta')
})
})
// =========================================================================
// Requirement 3: Freeze Application & Immunity
// =========================================================================
describe('Requirement 3: Freeze Application & Immunity Verification', () => {
it('damages targets with cannot_be_frozen but strictly skips solid freeze state on direct and splash hits', async () => {
const registry = await getSharedDataRegistry()
const engine = new MissileEngine(registry)
const attacker = createMockCombatUnit('sorceress')
// Direct target with cannot_be_frozen = 1
const cbfDirect = createMockCombatUnit('cbf_direct', { cannotBeFrozen: true })
// Splash target with cannot_be_frozen = 1
const cbfSplash = createMockCombatUnit('cbf_splash', { cannotBeFrozen: true })
// Normal splash target
const normalSplash = createMockCombatUnit('normal_splash', { cannotBeFrozen: false })
const targets = [cbfDirect, cbfSplash, normalSplash]
const targetPositions = new Map<string, { x: number; y: number }>([
['cbf_direct', { x: 0, y: 0 }],
['cbf_splash', { x: 25, y: 0 }],
['normal_splash', { x: 0, y: 25 }],
])
engine.spawnMissile({
missileNameOrId: 'glacialspike',
sourceSkillId: 55,
slvl: 20,
owner: attacker,
startX: -20,
startY: 0,
targetX: 0,
targetY: 0,
dmgPacket: {
skillId: 55,
elemType: 'cold',
elemMin256: 225 * 256,
elemMax256: 242 * 256,
elemDurationFrames: 107,
autoHit: true,
},
vx: 20,
vy: 0,
maxRangeTicks: 40,
})
const outcome = engine.tick(1, targets, targetPositions)
// Direct target receives damage, but NO freeze state
const directHit = outcome.hits.find(h => h.targetId === 'cbf_direct')
expect(directHit).toBeDefined()
expect(directHit!.damage).toBeGreaterThan(0)
expect(cbfDirect.stateBus.hasState('freeze')).toBe(false)
// Splash target with CBF receives splash damage, but NO freeze state
const splashHit = outcome.hits.find(h => h.targetId === 'cbf_splash')
expect(splashHit).toBeDefined()
expect(splashHit!.damage).toBeGreaterThan(0)
expect(cbfSplash.stateBus.hasState('freeze')).toBe(false)
// Normal splash target receives splash damage AND solid freeze state
const normalHit = outcome.hits.find(h => h.targetId === 'normal_splash')
expect(normalHit).toBeDefined()
expect(normalHit!.damage).toBeGreaterThan(0)
expect(normalSplash.stateBus.hasState('freeze')).toBe(true)
})
it('verifies cold immune target (res >= 100%) receives 0 damage, immune flag true, and NO freeze state', async () => {
const registry = await getSharedDataRegistry()
const engine = new MissileEngine(registry)
const attacker = createMockCombatUnit('sorceress')
// Direct target with 120% cold resistance (cold immune)
const immuneDirect = createMockCombatUnit('immune_direct', { coldResist: 120 })
// Splash target with 150% cold resistance (cold immune)
const immuneSplash = createMockCombatUnit('immune_splash', { coldResist: 150 })
// Splash target with 0% cold resistance (normal)
const normalSplash = createMockCombatUnit('normal_splash', { coldResist: 0 })
const targets = [immuneDirect, immuneSplash, normalSplash]
const targetPositions = new Map<string, { x: number; y: number }>([
['immune_direct', { x: 0, y: 0 }],
['immune_splash', { x: 20, y: 0 }],
['normal_splash', { x: 0, y: 20 }],
])
engine.spawnMissile({
missileNameOrId: 'glacialspike',
sourceSkillId: 55,
slvl: 20,
owner: attacker,
startX: -20,
startY: 0,
targetX: 0,
targetY: 0,
dmgPacket: {
skillId: 55,
elemType: 'cold',
elemMin256: 225 * 256,
elemMax256: 242 * 256,
elemDurationFrames: 107,
autoHit: true,
},
vx: 20,
vy: 0,
maxRangeTicks: 40,
})
const outcome = engine.tick(1, targets, targetPositions)
// Direct immune target
const directHit = outcome.hits.find(h => h.targetId === 'immune_direct')
expect(directHit).toBeDefined()
expect(directHit!.immune).toBe(true)
expect(directHit!.damage).toBe(0)
expect(immuneDirect.stateBus.hasState('freeze')).toBe(false)
// Splash immune target
const splashHit = outcome.hits.find(h => h.targetId === 'immune_splash')
expect(splashHit).toBeDefined()
expect(splashHit!.immune).toBe(true)
expect(splashHit!.damage).toBe(0)
expect(immuneSplash.stateBus.hasState('freeze')).toBe(false)
// Normal splash target receives full damage and solid freeze
const normalHit = outcome.hits.find(h => h.targetId === 'normal_splash')
expect(normalHit).toBeDefined()
expect(normalHit!.immune).toBe(false)
expect(normalHit!.damage).toBeGreaterThan(0)
expect(normalSplash.stateBus.hasState('freeze')).toBe(true)
})
})
// =========================================================================
// Requirement 4: Cold Mastery Resistance Sweeps (-100% to +200% vs slvl 1..50)
// =========================================================================
describe('Requirement 4: Cold Mastery Resistance Sweeps & Combat Calculations', () => {
it('verifies Cold Mastery linear formula across slvl 1 to 50: pierce = 20 + (slvl - 1) * 5', () => {
for (let slvl = 1; slvl <= 50; slvl++) {
const expected = 20 + (slvl - 1) * 5
expect(calculateColdMasteryPierce(slvl)).toBe(expected)
}
expect(calculateColdMasteryPierce(0)).toBe(0)
expect(calculateColdMasteryPierce(-1)).toBe(0)
})
it('adversarial sweep: verifies natural cold immune (res >= 100%) is NEVER pierced or reduced by Cold Mastery alone', () => {
// Test cold resistance from 100% to 200% across slvl 1 to 50
const testLevels = [1, 5, 10, 15, 20, 25, 30, 40, 50]
for (let baseRes = 100; baseRes <= 200; baseRes += 5) {
for (const slvl of testLevels) {
const pierce = calculateColdMasteryPierce(slvl)
const result = computeEffectiveResistance({
baseRes,
passiveEnemyPierce: pierce,
})
// Invariant: Cold Mastery alone cannot break immunity
expect(result.isImmune, `baseRes ${baseRes}% with slvl ${slvl} CM must remain immune`).toBe(true)
expect(result.effectiveRes, `baseRes ${baseRes}% with slvl ${slvl} CM must have effectiveRes 100`).toBe(100)
expect(result.convictionAndLRApplied).toBe(0)
}
}
})
it('adversarial sweep: verifies strict -100% effective resistance floor clamp for all non-immune resistances', () => {
// Sweep base resistance from -100% to 99% against slvl 1 to 50
const testLevels = [1, 5, 10, 15, 20, 25, 30, 40, 50]
for (let baseRes = -100; baseRes < 100; baseRes += 10) {
for (const slvl of testLevels) {
const pierce = calculateColdMasteryPierce(slvl)
const result = computeEffectiveResistance({
baseRes,
passiveEnemyPierce: pierce,
})
expect(result.isImmune).toBe(false)
const expected = Math.max(-100, Math.min(99, baseRes - pierce))
expect(result.effectiveRes, `baseRes ${baseRes} with pierce ${pierce}`).toBe(expected)
expect(result.effectiveRes, 'Effective resistance must never drop below -100%').toBeGreaterThanOrEqual(-100)
}
}
})
it('adversarial sweep: verifies broken immunity allows Cold Mastery to apply at full 100% effect without 1/5 penalty', () => {
// Test cases where Conviction breaks immunity (baseRes in 100..116, Conviction 85 -> 85/5 = 17 -> res becomes 83..99)
const convictionPierce = 85 // standard slvl 12 Conviction
const testLevels = [1, 5, 10, 20, 30, 50]
for (let baseRes = 100; baseRes <= 116; baseRes++) {
for (const slvl of testLevels) {
const cmPierce = calculateColdMasteryPierce(slvl)
const result = computeEffectiveResistance({
baseRes,
convictionPierce,
passiveEnemyPierce: cmPierce,
})
// 1. Conviction applied at 1/5th to immune: 85 / 5 = 17
expect(result.convictionAndLRApplied).toBe(17)
const resAfterConv = baseRes - 17
expect(result.resAfterConvictionLR).toBe(resAfterConv)
// 2. Since resAfterConv < 100, target is NO LONGER immune
expect(result.isImmune).toBe(false)
// 3. Cold Mastery applies at full effect without 1/5 penalty, clamped to -100%
const expectedEffective = Math.max(-100, Math.min(99, resAfterConv - cmPierce))
expect(result.effectiveRes).toBe(expectedEffective)
}
}
// Test case where Conviction is NOT enough to break immunity (e.g. baseRes = 120, 120 - 17 = 103 >= 100)
for (const slvl of testLevels) {
const cmPierce = calculateColdMasteryPierce(slvl)
const result = computeEffectiveResistance({
baseRes: 120,
convictionPierce: 85,
passiveEnemyPierce: cmPierce,
})
// Unbroken immunity: target stays immune, effectiveRes stays 100, CM pierce is 0
expect(result.isImmune).toBe(true)
expect(result.effectiveRes).toBe(100)
}
})
it('differential fuzzing: 1000 randomized iterations comparing engine against mathematical oracle', () => {
// Independent Mathematical Oracle
function oracleEffectiveResistance(
baseRes: number,
conviction: number,
lowerResist: number,
passivePierce: number,
): { isImmune: boolean; effectiveRes: number } {
const rawConvLR = Math.max(0, Math.trunc(conviction + lowerResist))
let convLRApplied = 0
if (baseRes >= 100) {
convLRApplied = Math.trunc(rawConvLR / 5)
} else {
convLRApplied = rawConvLR
}
const resAfter = baseRes - convLRApplied
if (resAfter >= 100) {
return { isImmune: true, effectiveRes: 100 }
}
const eff = Math.max(-100, Math.min(99, resAfter - Math.max(0, Math.trunc(passivePierce))))
return { isImmune: false, effectiveRes: eff }
}
// Seeded deterministic pseudo-random number generator for differential fuzzing
let seed = 0x1337c0de
function nextRand(): number {
seed = (seed * 1664525 + 1013904223) >>> 0
return seed / 4294967296
}
for (let iter = 1; iter <= 1000; iter++) {
// Random base resistance in [-100, 200]
const baseRes = Math.floor(nextRand() * 301) - 100
// Random Cold Mastery slvl in [0, 50]
const slvl = Math.floor(nextRand() * 51)
const cmPierce = calculateColdMasteryPierce(slvl)
// Random Conviction in [0, 150]
const conviction = Math.floor(nextRand() * 151)
// Random Lower Resist in [0, 75]
const lowerResist = Math.floor(nextRand() * 76)
const actual = computeEffectiveResistance({
baseRes,
convictionPierce: conviction,
lowerResistPierce: lowerResist,
passiveEnemyPierce: cmPierce,
})
const expected = oracleEffectiveResistance(baseRes, conviction, lowerResist, cmPierce)
expect(actual.isImmune, `Iter ${iter}: isImmune mismatch for baseRes=${baseRes}, slvl=${slvl}`).toBe(
expected.isImmune,
)
expect(actual.effectiveRes, `Iter ${iter}: effectiveRes mismatch for baseRes=${baseRes}, slvl=${slvl}`).toBe(
expected.effectiveRes,
)
}
})
it('SUnitDmg pipeline: validates exact damage multiplier clamping at 2.0x (effectiveRes = -100%)', () => {
const attacker = createMockCombatUnit('sorceress_cm', { coldMasterySlvl: 20 }) // 115% pierce
// Target A: 0% cold res -> with 115% pierce -> effectiveRes = -100% (takes 2.0x damage)
const targetA = createMockCombatUnit('target_0res', { coldResist: 0 })
const outA = executeSUnitDmg(attacker, targetA, {
skillId: 55,
attackKind: 'spell',
elemType: 'cold',
elemMin256: 100 * 256,
elemMax256: 100 * 256,
autoHit: true,
})
expect(outA.totalDamage).toBe(200) // 100 * (100 - (-100)) / 100 = 200
// Target B: -50% cold res with slvl 50 CM (265% pierce) -> clamped to -100% -> STILL takes 2.0x damage
const superAttacker = createMockCombatUnit('sorceress_super_cm', { coldMasterySlvl: 50 })
const targetB = createMockCombatUnit('target_neg_res', { coldResist: -50 })
const outB = executeSUnitDmg(superAttacker, targetB, {
skillId: 55,
attackKind: 'spell',
elemType: 'cold',
elemMin256: 100 * 256,
elemMax256: 100 * 256,
autoHit: true,
})
expect(outB.totalDamage, 'Damage multiplier must strictly clamp at 2.0x (200 damage)').toBe(200)
// Target C: 50% cold res -> with 115% pierce -> effectiveRes = -65% -> takes 1.65x damage
const targetC = createMockCombatUnit('target_50res', { coldResist: 50 })
const outC = executeSUnitDmg(attacker, targetC, {
skillId: 55,
attackKind: 'spell',
elemType: 'cold',
elemMin256: 100 * 256,
elemMax256: 100 * 256,
autoHit: true,
})
expect(outC.totalDamage).toBe(165) // 100 * (100 - (-65)) / 100 = 165
})
})
})