diff --git a/spec/System/TestDefence_spec.lua b/spec/System/TestDefence_spec.lua index 681713a45..762103f5b 100644 --- a/spec/System/TestDefence_spec.lua +++ b/spec/System/TestDefence_spec.lua @@ -527,7 +527,7 @@ describe("TestDefence", function() assert.are.equals(0, floor(poolsRemaining.Life)) assert.are.equals(0, floor(poolsRemaining.OverkillDamage)) end) - + it("uses block chance against projectile spells", function() build.configTab.input.enemyIsBoss = "None" build.configTab.input.enemyDamageType = "SpellProjectile" @@ -549,4 +549,44 @@ describe("TestDefence", function() assert.are.equals(15, build.calcsTab.calcsOutput.EffectiveAverageBlockChance) assert.are.equals(85, build.calcsTab.calcsOutput.ConfiguredDamageChance) end) + + it("limits EHP speedup when hit damage is delayed", function() + local function assertClose(actual, expected) + assert.is_true(math.abs(actual - expected) < 0.01) + end + + local function calcEHP(extraMods) + newBuild() + build.configTab.input.enemyPhysicalDamage = "500" + build.configTab.input.enemyFireDamage = "500" + build.configTab.input.enemyColdDamage = "500" + build.configTab.input.enemyLightningDamage = "500" + build.configTab.input.enemyChaosDamage = "0" + build.configTab.input.customMods = [[ + +4000 to maximum Life + 75% of Life Loss from Hits is prevented, then that much Life is lost over 4 seconds instead + +75% to all Elemental Resistances + +75% to Chaos Resistance + ]] .. (extraMods or "") + pob1and2Compat() + runCallback("OnFrame") + runCallback("OnFrame") + local calcsOutput = build.calcsTab.calcsOutput + return { + TotalEHP = calcsOutput.TotalEHP, + EffectiveBlockChance = calcsOutput.EffectiveBlockChance, + NumberOfMitigatedDamagingHits = calcsOutput.NumberOfMitigatedDamagingHits, + } + end + + local base = calcEHP() + local block = calcEHP("\n+10% to Block chance\n") + + newBuild() + + assertClose(base.TotalEHP, 17582.417582418) + assertClose(block.TotalEHP, 19008.019008019) + assertClose(block.EffectiveBlockChance, 10) + assert.is_true(block.TotalEHP > base.TotalEHP) + end) end) diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index d3366fcf7..0b4cc261d 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -3078,13 +3078,16 @@ function calcs.buildDefenceEstimations(env, actor) end iterationMultiplier = 1 -- to speed it up, run recursively but accelerated - local speedUp = data.misc.ehpCalcSpeedUp + -- MoM/life-loss-prevention mechanics can collapse too many hits into one + -- resulting in eHP jumps so we slow the acceleration. + local speedUp = DamageIn["LimitEHPSpeedup"] and 4 or data.misc.ehpCalcSpeedUp DamageIn["cyclesRan"] = DamageIn["cyclesRan"] or false if not DamageIn["cyclesRan"] and poolTable.Life > 0 and DamageIn["iterations"] < maxIterations then Damage = { } for _, damageType in ipairs(dmgTypeList) do Damage[damageType] = DamageIn[damageType] * speedUp end + Damage["LimitEHPSpeedup"] = DamageIn["LimitEHPSpeedup"] if DamageIn.GainWhenHit then Damage.GainWhenHit = true Damage.LifeWhenHit = DamageIn.LifeWhenHit @@ -3136,6 +3139,7 @@ function calcs.buildDefenceEstimations(env, actor) for _, damageType in ipairs(dmgTypeList) do DamageIn[damageType] = output[damageType.."TakenHit"] end + DamageIn["LimitEHPSpeedup"] = output["preventedLifeLossTotal"] > 0 output["NumberOfDamagingHits"] = numberOfHitsToDie(DamageIn) end @@ -3227,6 +3231,7 @@ function calcs.buildDefenceEstimations(env, actor) output["LifeLossLostOverTime"] = 0 output["LifeBelowHalfLossLostOverTime"] = 0 end + DamageIn["LimitEHPSpeedup"] = DamageIn["TrackRecoupable"] or DamageIn["TrackLifeLossOverTime"] or DamageIn.GainWhenHit averageAvoidChance = averageAvoidChance / 5 output["ConfiguredDamageChance"] = 100 * (blockEffect * suppressionEffect * effectiveDeflectMulti * (1 - averageAvoidChance / 100)) output["NumberOfMitigatedDamagingHits"] = (output["ConfiguredDamageChance"] ~= 100 or DamageIn["TrackRecoupable"] or DamageIn["TrackLifeLossOverTime"] or DamageIn.GainWhenHit) and numberOfHitsToDie(DamageIn) or output["NumberOfDamagingHits"]