From 8b99c68de31882e6df4eeac2eda4c86b715e24ea Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Fri, 22 May 2026 03:29:59 -0500 Subject: [PATCH 1/3] add leech instance cap from 0.5 add enemy leech resistance into max leech calcs --- src/Data/Misc.lua | 1 + src/Export/Scripts/miscdata.lua | 3 +++ src/Modules/CalcDefence.lua | 17 +++++++++++------ src/Modules/Data.lua | 1 + 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Data/Misc.lua b/src/Data/Misc.lua index ca328dec97..c8d8f1c3a5 100644 --- a/src/Data/Misc.lua +++ b/src/Data/Misc.lua @@ -11,6 +11,7 @@ data.monsterAllyDamageTable = { 3.1099998950958, 4.4200000762939, 5.820000171661 data.monsterArmourTable = { 3, 6, 8, 10, 13, 16, 19, 22, 26, 30, 34, 39, 43, 49, 54, 60, 67, 73, 81, 89, 97, 106, 116, 126, 137, 149, 161, 174, 189, 204, 220, 237, 255, 274, 295, 317, 340, 364, 391, 418, 448, 479, 512, 547, 585, 624, 666, 711, 758, 808, 861, 917, 976, 1039, 1105, 1176, 1250, 1329, 1412, 1500, 1594, 1692, 1796, 1906, 2023, 2146, 2276, 2413, 2558, 2712, 2874, 3044, 3225, 3416, 3617, 3829, 4053, 4290, 4540, 4803, 5081, 5375, 5684, 6011, 6355, 6718, 7101, 7505, 7930, 8379, 8852, 9351, 9877, 10431, 11015, 11630, 12279, 12962, 13682, 14441, } data.monsterAilmentThresholdTable = { 15, 20, 24, 28, 34, 39, 46, 52, 60, 70, 81, 95, 110, 126, 144, 171, 193, 218, 245, 275, 306, 340, 376, 413, 455, 497, 543, 590, 641, 695, 752, 812, 874, 950, 1033, 1123, 1220, 1326, 1442, 1568, 1705, 1854, 2015, 2192, 2384, 2564, 2757, 2966, 3188, 3426, 3681, 3955, 4247, 4560, 4895, 5254, 5638, 6049, 6489, 6959, 7462, 8001, 8576, 9193, 9723, 10382, 11085, 11837, 12639, 13497, 14413, 15390, 16435, 17549, 18742, 20013, 21372, 22824, 24373, 26029, 27796, 29684, 31700, 33852, 36153, 38608, 41230, 44033, 47023, 50219, 53630, 57272, 61164, 65318, 69757, 74494, 79554, 84958, 90729, 96892, } data.monsterPoiseThresholdTable = { 30, 40, 48, 57, 67, 79, 93, 106, 122, 142, 165, 192, 220, 254, 290, 344, 390, 437, 488, 542, 599, 659, 724, 791, 862, 937, 1015, 1097, 1183, 1273, 1367, 1464, 1567, 1660, 1758, 1864, 1976, 2093, 2219, 2352, 2494, 2644, 2804, 2971, 3150, 3369, 3598, 3846, 4109, 4387, 4685, 5002, 5338, 5697, 6078, 6485, 6915, 7377, 7866, 8386, 8940, 9528, 10153, 10819, 11376, 12648, 14061, 15634, 17382, 19326, 21492, 23897, 26573, 29553, 32864, 36550, 40649, 45211, 50282, 55927, 62209, 69197, 76969, 85615, 95241, 105954, 117866, 131122, 145878, 162291, 180568, 200887, 223518, 248690, 276705, 307880, 342574, 381187, 424158, 471974, } +data.monsterLeechResistanceTable = { 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6099, 6255, 6395, 6566, 6734, 6898, 7054, 7205, 7354, 7497, 7631, 7762, 7887, 8009, 8123, 8181, 8240, 8300, 8357, 8415, 8471, 8526, 8581, 8634, 8687, 8739, 8789, 8839, 8887, 8935, 8981, 9026, 9070, 9112, 9153, 9201, 9247, 9291, 9333, 9373, 9411, 9448, 9483, 9516, 9547, 9577, 9605, 9632, 9657, 9681, 9705, 9726, 9747, 9766, 9784, 9801, 9817, 9831, 9845, 9858, 9870, 9881, 9891, 9901, 9910, 9918, 9925, 9932, 9939, 9945, } -- From MinionGemLevelScaling.dat data.minionLevelTable = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, } diff --git a/src/Export/Scripts/miscdata.lua b/src/Export/Scripts/miscdata.lua index 995d2fe327..7791c9406f 100644 --- a/src/Export/Scripts/miscdata.lua +++ b/src/Export/Scripts/miscdata.lua @@ -10,6 +10,7 @@ local damage = "" local armour = "" local ailmentThreshold = "" local poiseThreshold = "" +local leechResistance = "" local minionLevel = "" for stats in dat("DefaultMonsterStats"):Rows() do evasion = evasion .. stats.Evasion .. ", " @@ -21,6 +22,7 @@ for stats in dat("DefaultMonsterStats"):Rows() do armour = armour .. stats.Armour .. ", " ailmentThreshold = ailmentThreshold .. stats.AilmentThreshold .. ", " poiseThreshold = poiseThreshold .. stats.PoiseThreshold .. ", " + leechResistance = leechResistance .. stats.LeechResistance .. ", " end -- Table was incorrect is PoE 1 but seems to be correct for PoE 2. Keeping here just in case --for i = 1, 100 do @@ -36,6 +38,7 @@ out:write('data.monsterAllyDamageTable = { '..allyDamage..'}\n') out:write('data.monsterArmourTable = { '..armour..'}\n') out:write('data.monsterAilmentThresholdTable = { '..ailmentThreshold..'}\n') out:write('data.monsterPoiseThresholdTable = { '..poiseThreshold..'}\n') +out:write('data.monsterLeechResistanceTable = { '..leechResistance..'}\n') out:write('\n') out:write('-- From MinionGemLevelScaling.dat\n') diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index d3366fcf7c..76ecc99a85 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -1594,37 +1594,42 @@ function calcs.defence(env, actor) output.ManaRecoveryRateMod = calcLib.mod(modDB, nil, "ManaRecoveryRate") output.EnergyShieldRecoveryRateMod = calcLib.mod(modDB, nil, "EnergyShieldRecoveryRate") + local enemyLeechResistance = data.monsterLeechResistanceTable[env.enemyLevel] / 100 + local enemyLeechResMod = ((100 - enemyLeechResistance) / 100) -- Leech caps - output.MaxLifeLeechInstance = output.Life * calcLib.val(modDB, "MaxLifeLeechInstance") / 100 + output.MaxLifeLeechInstance = m_min(output.Life * calcLib.val(modDB, "MaxLifeLeechInstance") / 100, data.misc.LeechMaxInstance) output.MaxLifeLeechRatePercent = calcLib.val(modDB, "MaxLifeLeechRate") if modDB:Flag(nil, "MaximumLifeLeechIsEqualToParent") then output.MaxLifeLeechRatePercent = actor.parent.output.MaxLifeLeechRatePercent elseif modDB:Flag(nil, "MaximumLifeLeechIsEqualToPartyMember") then output.MaxLifeLeechRatePercent = actor.partyMembers.output.MaxLifeLeechRatePercent end - output.MaxLifeLeechRate = output.Life * output.MaxLifeLeechRatePercent / 100 + output.MaxLifeLeechRate = output.Life * (output.MaxLifeLeechRatePercent / 100) * enemyLeechResMod if breakdown then breakdown.MaxLifeLeechRate = { s_format("%d ^8(maximum life)", output.Life), s_format("x %d%% ^8(percentage of life to maximum leech rate)", output.MaxLifeLeechRatePercent), + s_format("x %d%% ^8(enemy leech resistance mod)", 100 - enemyLeechResistance), s_format("= %.1f", output.MaxLifeLeechRate) } end - output.MaxEnergyShieldLeechInstance = output.EnergyShield * calcLib.val(modDB, "MaxEnergyShieldLeechInstance") / 100 - output.MaxEnergyShieldLeechRate = output.EnergyShield * calcLib.val(modDB, "MaxEnergyShieldLeechRate") / 100 + output.MaxEnergyShieldLeechInstance = m_min(output.EnergyShield * calcLib.val(modDB, "MaxEnergyShieldLeechInstance") / 100, data.misc.LeechMaxInstance) + output.MaxEnergyShieldLeechRate = output.EnergyShield * (calcLib.val(modDB, "MaxEnergyShieldLeechRate") / 100) * enemyLeechResMod if breakdown then breakdown.MaxEnergyShieldLeechRate = { s_format("%d ^8(maximum energy shield)", output.EnergyShield), s_format("x %d%% ^8(percentage of energy shield to maximum leech rate)", calcLib.val(modDB, "MaxEnergyShieldLeechRate")), + s_format("x %d%% ^8(enemy leech resistance mod)", 100 - enemyLeechResistance), s_format("= %.1f", output.MaxEnergyShieldLeechRate) } end - output.MaxManaLeechInstance = output.Mana * calcLib.val(modDB, "MaxManaLeechInstance") / 100 - output.MaxManaLeechRate = output.Mana * calcLib.val(modDB, "MaxManaLeechRate") / 100 + output.MaxManaLeechInstance = m_min(output.Mana * calcLib.val(modDB, "MaxManaLeechInstance") / 100, data.misc.LeechMaxInstance) + output.MaxManaLeechRate = output.Mana * (calcLib.val(modDB, "MaxManaLeechRate") / 100) * enemyLeechResMod if breakdown then breakdown.MaxManaLeechRate = { s_format("%d ^8(maximum mana)", output.Mana), s_format("x %d%% ^8(percentage of mana to maximum leech rate)", calcLib.val(modDB, "MaxManaLeechRate")), + s_format("x %d%% ^8(enemy leech resistance mod)", 100 - enemyLeechResistance), s_format("= %.1f", output.MaxManaLeechRate) } end diff --git a/src/Modules/Data.lua b/src/Modules/Data.lua index 340d528619..c4d4db2c05 100644 --- a/src/Modules/Data.lua +++ b/src/Modules/Data.lua @@ -198,6 +198,7 @@ data.misc = { -- magic numbers Transfiguration = 0.3, EnemyMaxResist = data.monsterConstants["base_maximum_all_resistances_%"], LeechRateBase = 0.02, + LeechMaxInstance = 40000, DotDpsCap = 35791394, -- (2 ^ 31 - 1) / 60 (int max / 60 seconds) BleedPercentBase = data.gameConstants["BleedingHitDamagePercentPerMinute"] / 60 / 100, BleedDurationBase = data.gameConstants["BaseBleedingDuration"], From 2d668e70413b8a12736ed4b9ee0fe06fc39ccdba Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Fri, 22 May 2026 04:03:55 -0500 Subject: [PATCH 2/3] cap damage correctly --- src/Modules/CalcDefence.lua | 6 +++--- src/Modules/CalcOffence.lua | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 76ecc99a85..88d8eaa3c8 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -1597,7 +1597,7 @@ function calcs.defence(env, actor) local enemyLeechResistance = data.monsterLeechResistanceTable[env.enemyLevel] / 100 local enemyLeechResMod = ((100 - enemyLeechResistance) / 100) -- Leech caps - output.MaxLifeLeechInstance = m_min(output.Life * calcLib.val(modDB, "MaxLifeLeechInstance") / 100, data.misc.LeechMaxInstance) + output.MaxLifeLeechInstance = output.Life * calcLib.val(modDB, "MaxLifeLeechInstance") / 100 output.MaxLifeLeechRatePercent = calcLib.val(modDB, "MaxLifeLeechRate") if modDB:Flag(nil, "MaximumLifeLeechIsEqualToParent") then output.MaxLifeLeechRatePercent = actor.parent.output.MaxLifeLeechRatePercent @@ -1613,7 +1613,7 @@ function calcs.defence(env, actor) s_format("= %.1f", output.MaxLifeLeechRate) } end - output.MaxEnergyShieldLeechInstance = m_min(output.EnergyShield * calcLib.val(modDB, "MaxEnergyShieldLeechInstance") / 100, data.misc.LeechMaxInstance) + output.MaxEnergyShieldLeechInstance = output.EnergyShield * calcLib.val(modDB, "MaxEnergyShieldLeechInstance") / 100 output.MaxEnergyShieldLeechRate = output.EnergyShield * (calcLib.val(modDB, "MaxEnergyShieldLeechRate") / 100) * enemyLeechResMod if breakdown then breakdown.MaxEnergyShieldLeechRate = { @@ -1623,7 +1623,7 @@ function calcs.defence(env, actor) s_format("= %.1f", output.MaxEnergyShieldLeechRate) } end - output.MaxManaLeechInstance = m_min(output.Mana * calcLib.val(modDB, "MaxManaLeechInstance") / 100, data.misc.LeechMaxInstance) + output.MaxManaLeechInstance = output.Mana * calcLib.val(modDB, "MaxManaLeechInstance") / 100 output.MaxManaLeechRate = output.Mana * (calcLib.val(modDB, "MaxManaLeechRate") / 100) * enemyLeechResMod if breakdown then breakdown.MaxManaLeechRate = { diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 03b0072011..e1bddbf4c4 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3964,13 +3964,13 @@ function calcs.offence(env, actor, activeSkill) end if lifeLeech > 0 and not noLifeLeech then - lifeLeechTotal = lifeLeechTotal + damageTypeHitAvg * lifeLeech / 100 + lifeLeechTotal = lifeLeechTotal + m_min(damageTypeHitAvg * lifeLeech / 100, data.misc.LeechMaxInstance) end if manaLeech > 0 and not noManaLeech then - manaLeechTotal = manaLeechTotal + damageTypeHitAvg * manaLeech / 100 + manaLeechTotal = manaLeechTotal + m_min(damageTypeHitAvg * manaLeech / 100, data.misc.LeechMaxInstance) end if energyShieldLeech > 0 and not noEnergyShieldLeech then - energyShieldLeechTotal = energyShieldLeechTotal + damageTypeHitAvg * energyShieldLeech / 100 + energyShieldLeechTotal = energyShieldLeechTotal + m_min(damageTypeHitAvg * energyShieldLeech / 100, data.misc.LeechMaxInstance) end else if breakdown then From 2cc94561a8d048df48433696d019a56de1a949f0 Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Fri, 22 May 2026 04:22:28 -0500 Subject: [PATCH 3/3] apply enemy resistances to leechperhit as well --- src/Modules/CalcBreakdown.lua | 5 +++-- src/Modules/CalcOffence.lua | 15 +++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Modules/CalcBreakdown.lua b/src/Modules/CalcBreakdown.lua index c2740d5dcd..ba9ac3418f 100644 --- a/src/Modules/CalcBreakdown.lua +++ b/src/Modules/CalcBreakdown.lua @@ -193,7 +193,7 @@ function breakdown.critDot(dotMulti, critMulti, dotChance, critChance) return out end -function breakdown.leech(instant, instantRate, instances, pool, rate, max, dur, instantLeechProportion, hitRate) +function breakdown.leech(instant, instantRate, instances, pool, rate, max, dur, instantLeechProportion, hitRate, enemyLeechResistance) local out = { } if actor.mainSkill.skillData.showAverage then if instant > 0 then @@ -212,7 +212,8 @@ function breakdown.leech(instant, instantRate, instances, pool, rate, max, dur, t_insert(out, s_format("x %.2f ^8(leech rate modifier)", rateMod)) end t_insert(out, s_format("x %.2fs ^8(instance duration)", dur)) - t_insert(out, s_format("= %.1f", pool * data.misc.LeechRateBase * rateMod * dur)) + t_insert(out, s_format("x %d%% ^8(enemy leech resistance mod)", 100 - enemyLeechResistance)) + t_insert(out, s_format("= %.1f", pool * data.misc.LeechRateBase * rateMod * dur * (100 - enemyLeechResistance) / 100)) end else if instantRate > 0 then diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index e1bddbf4c4..cf80d842e9 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -4419,15 +4419,18 @@ function calcs.offence(env, actor, activeSkill) end -- Calculate leech rates + local enemyLeechResistance = data.monsterLeechResistanceTable[env.enemyLevel] / 100 + local enemyLeechResMod = ((100 - enemyLeechResistance) / 100) + output.LifeLeechInstanceRate = output.Life * data.misc.LeechRateBase * calcLib.mod(skillModList, skillCfg, "LifeLeechRate") output.LifeLeechRate = output.LifeLeechInstances * output.LifeLeechInstanceRate - output.LifeLeechPerHit = output.LifeLeechInstanceRate + output.LifeLeechPerHit = output.LifeLeechInstanceRate * enemyLeechResMod output.EnergyShieldLeechInstanceRate = output.EnergyShield * data.misc.LeechRateBase * calcLib.mod(skillModList, skillCfg, "EnergyShieldLeechRate") output.EnergyShieldLeechRate = output.EnergyShieldLeechInstances * output.EnergyShieldLeechInstanceRate - output.EnergyShieldLeechPerHit = output.EnergyShieldLeechInstanceRate + output.EnergyShieldLeechPerHit = output.EnergyShieldLeechInstanceRate * enemyLeechResMod output.ManaLeechInstanceRate = output.Mana * data.misc.LeechRateBase * calcLib.mod(skillModList, skillCfg, "ManaLeechRate") output.ManaLeechRate = output.ManaLeechInstances * output.ManaLeechInstanceRate - output.ManaLeechPerHit = output.ManaLeechInstanceRate + output.ManaLeechPerHit = output.ManaLeechInstanceRate * enemyLeechResMod -- On full life, Immortal Ambition treats life leech as energy shield leech if skillModList:Flag(nil, "ImmortalAmbition") then output.EnergyShieldLeechRate = output.EnergyShieldLeechRate + output.LifeLeechRate @@ -4463,13 +4466,13 @@ function calcs.offence(env, actor, activeSkill) if breakdown then local hitRate = output.HitChance / 100 * (globalOutput.HitSpeed or globalOutput.Speed) * skillData.dpsMultiplier if skillFlags.leechLife then - breakdown.LifeLeech = breakdown.leech(output.LifeLeechInstant, output.LifeLeechInstantRate, output.LifeLeechInstances, output.Life, "LifeLeechRate", output.MaxLifeLeechRate, output.LifeLeechDuration, output.LifeLeechInstantProportion, hitRate) + breakdown.LifeLeech = breakdown.leech(output.LifeLeechInstant, output.LifeLeechInstantRate, output.LifeLeechInstances, output.Life, "LifeLeechRate", output.MaxLifeLeechRate, output.LifeLeechDuration, output.LifeLeechInstantProportion, hitRate, enemyLeechResistance) end if skillFlags.leechES then - breakdown.EnergyShieldLeech = breakdown.leech(output.EnergyShieldLeechInstant, output.EnergyShieldLeechInstantRate, output.EnergyShieldLeechInstances, output.EnergyShield, "EnergyShieldLeechRate", output.MaxEnergyShieldLeechRate, output.EnergyShieldLeechDuration, output.EnergyShieldLeechInstantProportion, hitRate) + breakdown.EnergyShieldLeech = breakdown.leech(output.EnergyShieldLeechInstant, output.EnergyShieldLeechInstantRate, output.EnergyShieldLeechInstances, output.EnergyShield, "EnergyShieldLeechRate", output.MaxEnergyShieldLeechRate, output.EnergyShieldLeechDuration, output.EnergyShieldLeechInstantProportion, hitRate, enemyLeechResistance) end if skillFlags.leechMana then - breakdown.ManaLeech = breakdown.leech(output.ManaLeechInstant, output.ManaLeechInstantRate, output.ManaLeechInstances, output.Mana, "ManaLeechRate", output.MaxManaLeechRate, output.ManaLeechDuration, output.ManaLeechInstantProportion, hitRate) + breakdown.ManaLeech = breakdown.leech(output.ManaLeechInstant, output.ManaLeechInstantRate, output.ManaLeechInstances, output.Mana, "ManaLeechRate", output.MaxManaLeechRate, output.ManaLeechDuration, output.ManaLeechInstantProportion, hitRate, enemyLeechResistance) end end