From 06487a9edd11671c03204d762e5fa8c9ebcf9958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=A0i=C5=A1ka?= Date: Sun, 27 Sep 2026 21:14:25 +0200 Subject: [PATCH] Calculate leech with the PoE2 leech rules Leech was still modelled on PoE1: every instance recovered 2% of the pool per second, instances stacked without limit, each instance was capped at 10% of the pool, and the total rate was capped at 20% of life/mana (10% of energy shield) per second. "Increased amount of Life Leeched" and "increased amount of Mana Leeched" only raised that total rate cap, so they did nothing unless a build hit the cap. PoE2 leech works differently (poe2wiki Leech, 0.5.0): - a hit leeches a percentage of its damage, recovered over 1 second - only one leech instance per resource recovers at a time - hits above 40,000 damage leech as though they dealt 40,000, with every damage type scaled down evenly - there is no cap on a single instance or on the total leech rate Now: - "amount of Life/Mana Leeched" multiplies the amount leeched per hit - an instance lasts 1s divided by leech speed ("Leech X% faster"), and the instant part of the leech shortens it by the same proportion - the sustained rate is one instance's rate times the time an instance is active, so hitting more than once per instance duration no longer raises leech - the PoE1 caps, their base mods, parser entries and calcs rows are removed - "Leech X% faster/slower" without a resource applies to life, mana and energy shield leech Monster leech resistance is not included yet. Co-Authored-By: Claude Opus 5.5 --- spec/System/TestLeech_spec.lua | 117 +++++++++++++++++++++++++++++++++ src/Data/ModCache.lua | 54 +++++++-------- src/Data/SkillStatMap.lua | 6 -- src/Modules/CalcBreakdown.lua | 72 +++++++------------- src/Modules/CalcDefence.lua | 35 ---------- src/Modules/CalcOffence.lua | 70 ++++++++++++-------- src/Modules/CalcPerform.lua | 2 - src/Modules/CalcSections.lua | 24 +++---- src/Modules/CalcSetup.lua | 6 -- src/Modules/Data.lua | 3 +- src/Modules/ModParser.lua | 22 ++----- 11 files changed, 228 insertions(+), 183 deletions(-) create mode 100644 spec/System/TestLeech_spec.lua diff --git a/spec/System/TestLeech_spec.lua b/spec/System/TestLeech_spec.lua new file mode 100644 index 0000000000..311e4c8175 --- /dev/null +++ b/spec/System/TestLeech_spec.lua @@ -0,0 +1,117 @@ +describe("TestLeech", function() + -- Punch with a large flat hit that always lands and never crits, so each hit deals exactly out.AverageDamage + local baseMods = [[ +Never deal Critical Hits ++100000 to Accuracy Rating +Adds 1000 to 1000 Physical Damage to Attacks +]] + + local function calcWith(mods) + build.configTab.input.customMods = baseMods .. mods + build.configTab:BuildModList() + runCallback("OnFrame") + local out = build.calcsTab.mainOutput + assert.are.equals(100, out.HitChance) + return out + end + + before_each(function() + newBuild() + end) + + it("leeches a percentage of hit damage without a cap based on the size of the pool", function() + local out = calcWith("Leech 10% of Physical Attack Damage as Life") + -- 10% of maximum Life was the PoE1 per-instance cap + assert.is_true(out.AverageDamage * 0.1 > out.Life * 0.1) + assert.are.near(out.AverageDamage * 0.1, out.LifeLeechPerHit, 0.01) + end) + + it("increased amount of Life Leeched multiplies the amount leeched per hit", function() + local out = calcWith("Leech 10% of Physical Attack Damage as Life\n50% increased amount of Life Leeched") + assert.are.near(out.AverageDamage * 0.1 * 1.5, out.LifeLeechPerHit, 0.01) + end) + + it("increased amount of Mana Leeched multiplies the amount leeched per hit", function() + local out = calcWith("Leech 10% of Physical Attack Damage as Mana\n50% increased amount of Mana Leeched") + assert.are.near(out.AverageDamage * 0.1 * 1.5, out.ManaLeechPerHit, 0.01) + end) + + it("recovers one leech instance at a time, so hitting more than once per second does not raise the rate", function() + local out = calcWith("Leech 10% of Physical Attack Damage as Life") + assert.is_true(out.Speed > 1) + -- one instance recovers its whole amount over 1 second + assert.are.near(out.AverageDamage * 0.1, out.LifeLeechRate, 0.01) + + newBuild() + local fastOut = calcWith("Leech 10% of Physical Attack Damage as Life\n100% increased Attack Speed") + assert.are.near(out.LifeLeechRate, fastOut.LifeLeechRate, 0.01) + end) + + it("scales the leech rate with hit rate when hitting less than once per second", function() + local out = calcWith("Leech 10% of Physical Attack Damage as Life\n75% reduced Attack Speed") + assert.is_true(out.Speed < 1) + assert.are.near(out.AverageDamage * 0.1 * out.Speed, out.LifeLeechRate, 0.01) + end) + + it("faster leech shortens each instance instead of adding recovery", function() + local out = calcWith("Leech 10% of Physical Attack Damage as Life\nLeech Life 50% faster") + assert.is_true(out.Speed > 1.5) + assert.are.near(out.AverageDamage * 0.1, out.LifeLeechPerHit, 0.01) + assert.are.near(1 / 1.5, out.LifeLeechDuration, 0.0001) + -- the single active instance recovers 1.5x its amount per second and is always refreshed + assert.are.near(out.AverageDamage * 0.1 * 1.5, out.LifeLeechRate, 0.01) + end) + + it("recovers the instant share immediately and the rest over the remaining duration", function() + local out = calcWith("Leech 10% of Physical Attack Damage as Life\n20% of Leech is Instant") + assert.are.near(out.AverageDamage * 0.1 * 0.2, out.LifeLeechInstant, 0.01) + assert.are.near(0.8, out.LifeLeechDuration, 0.0001) + assert.are.near(out.AverageDamage * 0.1, out.LifeLeechPerHit, 0.01) + end) + + it("treats hits above 40,000 damage as dealing 40,000 damage", function() + local out = calcWith("Leech 10% of Physical Attack Damage as Life\nAdds 100000 to 100000 Physical Damage to Attacks") + assert.is_true(out.AverageDamage > 40000) + assert.are.near(4000, out.LifeLeechPerHit, 0.01) + end) + + it("scales every damage type of a capped hit evenly", function() + local out = calcWith("Leech 10% of Physical Attack Damage as Life\nAdds 100000 to 100000 Physical Damage to Attacks\nAdds 100000 to 100000 Fire Damage to Attacks") + local physical = out.MainHand.PhysicalHitAverage + local fire = out.MainHand.FireHitAverage + assert.is_true(fire > 0) + assert.are.near(4000 * physical / (physical + fire), out.LifeLeechPerHit, 0.01) + end) + + it("explains the single active instance and its uptime in the leech rate breakdown", function() + local out = calcWith("Leech 10% of Physical Attack Damage as Life\n75% reduced Attack Speed") + local lines = build.calcsTab.calcsEnv.player.breakdown.LifeLeech + local text = table.concat(lines, "\n") + assert.truthy(text:find("Only one instance recovers at a time", 1, true)) + assert.truthy(text:find(string.format("%.2f hits per second", out.Speed), 1, true)) + assert.truthy(lines[#lines]:find(string.format("%.1f", out.LifeLeechRate), 1, true)) + end) + + it("averages the leech of both weapons when dual wielding hits once with each weapon", function() + build.skillsTab:PasteSocketGroup("skillId:MeleeMaceMacePlayer Mace Strike 20/0 1") + build.itemsTab:CreateDisplayItemFromRaw("New Item\nMarauding Mace\nQuality: 0\nAdds 500 to 500 Physical Damage") + build.itemsTab:AddDisplayItem() + build.itemsTab:CreateDisplayItemFromRaw("New Item\nMarauding Mace\nQuality: 0") + build.itemsTab:AddDisplayItem() + local out = calcWith("Leech 10% of Physical Attack Damage as Life") + assert.is_true(build.calcsTab.mainEnv.player.mainSkill.activeEffect.statSet.skillFlags.bothWeaponAttack) + local mainHandLeech = out.MainHand.AverageDamage * 0.1 + local offHandLeech = out.OffHand.AverageDamage * 0.1 + assert.is_true(mainHandLeech > offHandLeech) + assert.are.near((mainHandLeech + offHandLeech) / 2, out.LifeLeechPerHit, 0.01) + -- each use hits once with each weapon, so an instance is always active while using the skill at least twice per second + assert.is_true(out.Speed > 0.5) + assert.are.near((mainHandLeech + offHandLeech) / 2, out.LifeLeechRate, 0.01) + end) + + it("applies 'Leech X% faster' to life, mana and energy shield leech", function() + local out = calcWith("Leech 10% of Physical Attack Damage as Life\nLeech 10% of Physical Attack Damage as Mana\nLeech 30% faster") + assert.are.near(1 / 1.3, out.LifeLeechDuration, 0.0001) + assert.are.near(1 / 1.3, out.ManaLeechDuration, 0.0001) + end) +end) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index 701abf6fd2..26c6eb3672 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -1700,9 +1700,9 @@ c["10% increased Warcry Buff Effect"]={{[1]={flags=0,keywordFlags=4,name="BuffEf c["10% increased Warcry Cooldown Recovery Rate"]={{[1]={flags=0,keywordFlags=4,name="CooldownRecovery",type="INC",value=10}},nil} c["10% increased Weapon Damage per 10 Strength"]={{[1]={[1]={div=10,stat="Str",type="PerStat"},flags=8192,keywordFlags=0,name="Damage",type="INC",value=10}},nil} c["10% increased Withered Magnitude"]={{[1]={flags=0,keywordFlags=0,name="WitherEffect",type="INC",value=10}},nil} -c["10% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=10}},nil} -c["10% increased amount of Life Leeched while Shapeshifted"]={{[1]={[1]={type="Condition",var="Shapeshifted"},flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=10}},nil} -c["10% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxManaLeechRate",type="INC",value=10}},nil} +c["10% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=10}},nil} +c["10% increased amount of Life Leeched while Shapeshifted"]={{[1]={[1]={type="Condition",var="Shapeshifted"},flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=10}},nil} +c["10% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="ManaLeechAmount",type="INC",value=10}},nil} c["10% increased chance to Shock"]={{[1]={flags=0,keywordFlags=0,name="EnemyShockChance",type="INC",value=10}},nil} c["10% increased chance to inflict Ailments"]={{[1]={flags=0,keywordFlags=0,name="AilmentChance",type="INC",value=10}},nil} c["10% increased effect of Arcane Surge on you"]={{[1]={flags=0,keywordFlags=0,name="ArcaneSurgeEffect",type="INC",value=10}},nil} @@ -1857,7 +1857,7 @@ c["100% increased Stun Threshold for each time you've been Stunned Recently"]={{ c["100% increased Thorns damage"]={{[1]={flags=32,keywordFlags=0,name="Damage",type="INC",value=100}},nil} c["100% increased Thorns damage if you've consumed an Endurance Charge Recently"]={{[1]={[1]={limit=1,type="Multiplier",var="RemovableEnduranceCharge"},flags=32,keywordFlags=0,name="Damage",type="INC",value=100}},nil} c["100% increased Vaal Skill Critical Hit Chance"]={{[1]={flags=0,keywordFlags=512,name="CritChance",type="INC",value=100}},nil} -c["100% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=100}},nil} +c["100% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=100}},nil} c["100% increased chance to Shock"]={{[1]={flags=0,keywordFlags=0,name="EnemyShockChance",type="INC",value=100}},nil} c["100% increased effect of Socketed Augment Items"]={{[1]={flags=0,keywordFlags=0,name="SocketedAugmentItemEffect",type="INC",value=100}},nil} c["100% increased effect of Socketed Soul Cores"]={{[1]={flags=0,keywordFlags=0,name="SocketedSoulCoreEffect",type="INC",value=100}},nil} @@ -1917,8 +1917,8 @@ c["11% increased Reload Speed"]={{[1]={flags=1,keywordFlags=0,name="ReloadSpeed" c["11% increased Spell Damage"]={{[1]={flags=2,keywordFlags=0,name="Damage",type="INC",value=11}},nil} c["11% increased Stun Threshold"]={{[1]={flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=11}},nil} c["11% increased Trap Damage"]={{[1]={flags=0,keywordFlags=4096,name="Damage",type="INC",value=11}},nil} -c["11% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=11}},nil} -c["11% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxManaLeechRate",type="INC",value=11}},nil} +c["11% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=11}},nil} +c["11% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="ManaLeechAmount",type="INC",value=11}},nil} c["11% increased speed of Recoup Effects"]={{[1]={flags=0,keywordFlags=0,name="LocalEffect",type="INC",value=11}}," speed of Recoup s "} c["11% less damage taken while on Low Life"]={{[1]={[1]={type="Condition",var="LowLife"},flags=0,keywordFlags=0,name="DamageTaken",type="MORE",value=-11}},nil} c["11% of Damage taken Recouped as Life"]={{[1]={flags=0,keywordFlags=0,name="LifeRecoup",type="BASE",value=11}},nil} @@ -2034,7 +2034,7 @@ c["12% increased Stun Duration on Enemies"]={{[1]={flags=0,keywordFlags=0,name=" c["12% increased Stun Threshold"]={{[1]={flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=12}},nil} c["12% increased Stun Threshold if you haven't been Stunned Recently"]={{[1]={[1]={neg=true,type="Condition",var="StunnedRecently"},flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=12}},nil} c["12% increased Thorns damage"]={{[1]={flags=32,keywordFlags=0,name="Damage",type="INC",value=12}},nil} -c["12% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=12}},nil} +c["12% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=12}},nil} c["12% increased chance to Shock"]={{[1]={flags=0,keywordFlags=0,name="EnemyShockChance",type="INC",value=12}},nil} c["12% increased maximum Energy Shield"]={{[1]={[1]={type="Global"},flags=0,keywordFlags=0,name="EnergyShield",type="INC",value=12}},nil} c["12% of Damage is taken from Mana before Life"]={{[1]={flags=0,keywordFlags=0,name="DamageTakenFromManaBeforeLife",type="BASE",value=12}},nil} @@ -2070,7 +2070,7 @@ c["125% increased Physical Damage"]={{[1]={flags=0,keywordFlags=0,name="Physical c["125% increased Rarity of Items Dropped by Slain Magic Enemies"]={{[1]={flags=0,keywordFlags=0,name="LootRarityMagicEnemies",type="INC",value=125}},nil} c["125% increased Thorns damage"]={{[1]={flags=32,keywordFlags=0,name="Damage",type="INC",value=125}},nil} c["125% increased Thorns damage if you've Blocked Recently"]={{[1]={[1]={type="Condition",var="BlockedRecently"},flags=32,keywordFlags=0,name="Damage",type="INC",value=125}},nil} -c["125% increased amount of Mana Leeched if you've dealt a Critical Hit Recently"]={{[1]={[1]={type="Condition",var="CritRecently"},flags=0,keywordFlags=0,name="MaxManaLeechRate",type="INC",value=125}},nil} +c["125% increased amount of Mana Leeched if you've dealt a Critical Hit Recently"]={{[1]={[1]={type="Condition",var="CritRecently"},flags=0,keywordFlags=0,name="ManaLeechAmount",type="INC",value=125}},nil} c["13 Mana gained when you Block"]={{[1]={flags=0,keywordFlags=0,name="ManaOnBlock",type="BASE",value=13}},nil} c["13 to 23 Physical Thorns damage"]={{[1]={flags=32,keywordFlags=0,name="PhysicalMin",type="BASE",value=13},[2]={flags=32,keywordFlags=0,name="PhysicalMax",type="BASE",value=23}},nil} c["13% chance for Flasks you use to not consume Charges"]={{[1]={flags=0,keywordFlags=0,name="FlaskChanceNotConsumeCharges",type="BASE",value=13}},nil} @@ -2432,8 +2432,8 @@ c["15% increased Trap Damage"]={{[1]={flags=0,keywordFlags=4096,name="Damage",ty c["15% increased Volatility Explosion delay"]={{}," Volatility Explosion delay "} c["15% increased Warcry Cooldown Recovery Rate"]={{[1]={flags=0,keywordFlags=4,name="CooldownRecovery",type="INC",value=15}},nil} c["15% increased Warcry Speed"]={{[1]={flags=0,keywordFlags=4,name="WarcrySpeed",type="INC",value=15}},nil} -c["15% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=15}},nil} -c["15% increased amount of Life Leeched while Shapeshifted"]={{[1]={[1]={type="Condition",var="Shapeshifted"},flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=15}},nil} +c["15% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=15}},nil} +c["15% increased amount of Life Leeched while Shapeshifted"]={{[1]={[1]={type="Condition",var="Shapeshifted"},flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=15}},nil} c["15% increased chance to Poison"]={{[1]={flags=0,keywordFlags=0,name="PoisonChance",type="INC",value=15}}," chance "} c["15% increased chance to Shock"]={{[1]={flags=0,keywordFlags=0,name="EnemyShockChance",type="INC",value=15}},nil} c["15% increased chance to inflict Ailments"]={{[1]={flags=0,keywordFlags=0,name="AilmentChance",type="INC",value=15}},nil} @@ -2515,7 +2515,7 @@ c["150% increased Global Evasion Rating when on Low Life"]={{[1]={[1]={type="Glo c["150% increased Mana Regeneration Rate if you've dealt a Critical Hit Recently"]={{[1]={[1]={type="Condition",var="CritRecently"},flags=0,keywordFlags=0,name="ManaRegen",type="INC",value=150}},nil} c["150% increased Physical Damage"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="INC",value=150}},nil} c["150% increased Spell Damage"]={{[1]={flags=2,keywordFlags=0,name="Damage",type="INC",value=150}},nil} -c["150% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=150}},nil} +c["150% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=150}},nil} c["16% increased Accuracy Rating at Close Range"]={{[1]={[1]={type="Condition",var="AtCloseRange"},flags=0,keywordFlags=0,name="AccuracyVsEnemy",type="INC",value=16}},nil} c["16% increased Accuracy Rating with One Handed Melee Weapons"]={{[1]={flags=21474836484,keywordFlags=0,name="Accuracy",type="INC",value=16}},nil} c["16% increased Accuracy Rating with Two Handed Melee Weapons"]={{[1]={flags=38654705668,keywordFlags=0,name="Accuracy",type="INC",value=16}},nil} @@ -2564,8 +2564,8 @@ c["16% increased Thorns damage"]={{[1]={flags=32,keywordFlags=0,name="Damage",ty c["16% increased Totem Life"]={{[1]={flags=0,keywordFlags=0,name="TotemLife",type="INC",value=16}},nil} c["16% increased Trap Throwing Speed"]={{[1]={flags=0,keywordFlags=0,name="TrapThrowingSpeed",type="INC",value=16}},nil} c["16% increased Warcry Speed"]={{[1]={flags=0,keywordFlags=4,name="WarcrySpeed",type="INC",value=16}},nil} -c["16% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=16}},nil} -c["16% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxManaLeechRate",type="INC",value=16}},nil} +c["16% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=16}},nil} +c["16% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="ManaLeechAmount",type="INC",value=16}},nil} c["16% increased maximum Energy Shield"]={{[1]={[1]={type="Global"},flags=0,keywordFlags=0,name="EnergyShield",type="INC",value=16}},nil} c["16% reduced Charges per use"]={{[1]={flags=0,keywordFlags=0,name="FlaskChargesUsed",type="INC",value=-16}},nil} c["16% reduced Skill Effect Duration"]={{[1]={flags=0,keywordFlags=0,name="Duration",type="INC",value=-16}},nil} @@ -2993,7 +2993,7 @@ c["20% increased Tribute"]={{[1]={flags=0,keywordFlags=0,name="Tribute",type="IN c["20% increased Warcry Speed"]={{[1]={flags=0,keywordFlags=4,name="WarcrySpeed",type="INC",value=20}},nil} c["20% increased Weapon Swap Speed"]={{[1]={flags=0,keywordFlags=0,name="WeaponSwapSpeed",type="INC",value=20}},nil} c["20% increased Withered Magnitude"]={{[1]={flags=0,keywordFlags=0,name="WitherEffect",type="INC",value=20}},nil} -c["20% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=20}},nil} +c["20% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=20}},nil} c["20% increased bonuses gained from Equipped Quiver"]={{[1]={flags=0,keywordFlags=0,name="EffectOfBonusesFromQuiver",type="INC",value=20}},nil} c["20% increased chance to Shock"]={{[1]={flags=0,keywordFlags=0,name="EnemyShockChance",type="INC",value=20}},nil} c["20% increased chance to inflict Ailments"]={{[1]={flags=0,keywordFlags=0,name="AilmentChance",type="INC",value=20}},nil} @@ -3094,7 +3094,7 @@ c["200% increased Ice Crystal Life"]={{[1]={flags=0,keywordFlags=0,name="IceCrys c["200% increased Physical Damage"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="INC",value=200}},nil} c["200% increased Spell Damage if you've dealt a Critical Hit in the past 8 seconds"]={{[1]={[1]={type="Condition",var="CritInPast8Sec"},flags=2,keywordFlags=0,name="Damage",type="INC",value=200}},nil} c["200% increased Stun Recovery"]={{[1]={flags=0,keywordFlags=0,name="StunRecovery",type="INC",value=200}},nil} -c["200% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=200}},nil} +c["200% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=200}},nil} c["200% increased bonuses gained from Equipped Quiver"]={{[1]={flags=0,keywordFlags=0,name="EffectOfBonusesFromQuiver",type="INC",value=200}},nil} c["200% increased effect of Socketed Runes"]={{[1]={flags=0,keywordFlags=0,name="SocketedRuneEffect",type="INC",value=200}},nil} c["200% increased effect of Socketed Soul Cores"]={{[1]={flags=0,keywordFlags=0,name="SocketedSoulCoreEffect",type="INC",value=200}},nil} @@ -3150,7 +3150,7 @@ c["23% increased Skill Speed"]={{[1]={flags=0,keywordFlags=0,name="Speed",type=" c["23% increased Spell damage for each 200 total Mana you have Spent Recently"]={{[1]={[1]={div=200,type="Multiplier",var="ManaSpentRecently"},flags=2,keywordFlags=0,name="Damage",type="INC",value=23}},nil} c["23% increased Strength"]={{[1]={flags=0,keywordFlags=0,name="Str",type="INC",value=23}},nil} c["23% increased Trap Damage"]={{[1]={flags=0,keywordFlags=4096,name="Damage",type="INC",value=23}},nil} -c["23% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=23}},nil} +c["23% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=23}},nil} c["23% more Global Evasion Rating and Energy Shield"]={{[1]={flags=0,keywordFlags=0,name="Evasion",type="MORE",value=23},[2]={flags=0,keywordFlags=0,name="EnergyShield",type="MORE",value=23}},nil} c["23% of Damage taken during effect Recouped as Life"]={{[1]={[1]={type="Condition",var="UsingFlask"},flags=0,keywordFlags=0,name="DamageTaken",type="BASE",value=23}}," Recouped as Life "} c["23% reduced Duration"]={{[1]={flags=0,keywordFlags=0,name="Duration",type="INC",value=-23}},nil} @@ -3385,9 +3385,9 @@ c["25% increased Trap Damage"]={{[1]={flags=0,keywordFlags=4096,name="Damage",ty c["25% increased Warcry Cooldown Recovery Rate"]={{[1]={flags=0,keywordFlags=4,name="CooldownRecovery",type="INC",value=25}},nil} c["25% increased Warcry Speed"]={{[1]={flags=0,keywordFlags=4,name="WarcrySpeed",type="INC",value=25}},nil} c["25% increased Weapon Swap Speed"]={{[1]={flags=0,keywordFlags=0,name="WeaponSwapSpeed",type="INC",value=25}},nil} -c["25% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=25}},nil} -c["25% increased amount of Life Leeched if you've consumed a Frenzy Charge Recently"]={{[1]={[1]={limit=1,type="Multiplier",var="RemovableFrenzyCharge"},flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=25}},nil} -c["25% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxManaLeechRate",type="INC",value=25}},nil} +c["25% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=25}},nil} +c["25% increased amount of Life Leeched if you've consumed a Frenzy Charge Recently"]={{[1]={[1]={limit=1,type="Multiplier",var="RemovableFrenzyCharge"},flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=25}},nil} +c["25% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="ManaLeechAmount",type="INC",value=25}},nil} c["25% increased bonuses gained from Equipped Rings and Amulets"]={{[1]={flags=0,keywordFlags=0,name="EffectOfBonusesFromRing 1",type="INC",value=25},[2]={flags=0,keywordFlags=0,name="EffectOfBonusesFromRing 2",type="INC",value=25},[3]={flags=0,keywordFlags=0,name="EffectOfBonusesFromRing 3",type="INC",value=25},[4]={flags=0,keywordFlags=0,name="EffectOfBonusesFromAmulet",type="INC",value=25}},nil} c["25% increased bonuses gained from left Equipped Ring"]={{[1]={flags=0,keywordFlags=0,name="EffectOfBonusesFromRing 1",type="INC",value=25}},nil} c["25% increased bonuses gained from right Equipped Ring"]={{[1]={flags=0,keywordFlags=0,name="EffectOfBonusesFromRing 2",type="INC",value=25}},nil} @@ -3780,8 +3780,8 @@ c["30% increased Totem Duration"]={{[1]={flags=0,keywordFlags=0,name="TotemDurat c["30% increased Totem Life"]={{[1]={flags=0,keywordFlags=0,name="TotemLife",type="INC",value=30}},nil} c["30% increased Totem Placement speed"]={{[1]={flags=0,keywordFlags=0,name="TotemPlacementSpeed",type="INC",value=30}},nil} c["30% increased Warcry Speed"]={{[1]={flags=0,keywordFlags=4,name="WarcrySpeed",type="INC",value=30}},nil} -c["30% increased amount of Life Leeched if you've consumed a Frenzy Charge Recently"]={{[1]={[1]={limit=1,type="Multiplier",var="RemovableFrenzyCharge"},flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=30}},nil} -c["30% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxManaLeechRate",type="INC",value=30}},nil} +c["30% increased amount of Life Leeched if you've consumed a Frenzy Charge Recently"]={{[1]={[1]={limit=1,type="Multiplier",var="RemovableFrenzyCharge"},flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=30}},nil} +c["30% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="ManaLeechAmount",type="INC",value=30}},nil} c["30% increased bonuses gained from left Equipped Ring"]={{[1]={flags=0,keywordFlags=0,name="EffectOfBonusesFromRing 1",type="INC",value=30}},nil} c["30% increased bonuses gained from right Equipped Ring"]={{[1]={flags=0,keywordFlags=0,name="EffectOfBonusesFromRing 2",type="INC",value=30}},nil} c["30% increased chance to Shock"]={{[1]={flags=0,keywordFlags=0,name="EnemyShockChance",type="INC",value=30}},nil} @@ -3965,7 +3965,7 @@ c["35% increased Spell Damage if you have consumed an Elemental Infusion Recentl c["35% increased Stun Buildup"]={{[1]={flags=0,keywordFlags=0,name="EnemyHeavyStunBuildup",type="INC",value=35}},nil} c["35% increased Stun Threshold"]={{[1]={flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=35}},nil} c["35% increased Trap Damage"]={{[1]={flags=0,keywordFlags=4096,name="Damage",type="INC",value=35}},nil} -c["35% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=35}},nil} +c["35% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=35}},nil} c["35% increased bonuses gained from Equipped Quiver"]={{[1]={flags=0,keywordFlags=0,name="EffectOfBonusesFromQuiver",type="INC",value=35}},nil} c["35% increased effect of Fully Broken Armour"]={{[1]={flags=0,keywordFlags=0,name="FullyBrokenArmourEffect",type="INC",value=35}},nil} c["35% increased maximum Energy Shield"]={{[1]={[1]={type="Global"},flags=0,keywordFlags=0,name="EnergyShield",type="INC",value=35}},nil} @@ -4610,7 +4610,7 @@ c["50% increased Stun Threshold while Channelling"]={{[1]={[1]={type="Condition" c["50% increased Surrounded Area of Effect"]={{[1]={flags=0,keywordFlags=0,name="SurroundedArea",type="INC",value=50}},nil} c["50% increased Totem Placement range"]={{}," Placement range "} c["50% increased Trap Trigger Area of Effect"]={{[1]={flags=0,keywordFlags=0,name="TrapTriggerAreaOfEffect",type="INC",value=50}},nil} -c["50% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxManaLeechRate",type="INC",value=50}},nil} +c["50% increased amount of Mana Leeched"]={{[1]={flags=0,keywordFlags=0,name="ManaLeechAmount",type="INC",value=50}},nil} c["50% increased chance to inflict Ailments against Enemies affected by Abyssal Wasting"]={{[1]={flags=0,keywordFlags=0,name="AbyssalWastingAlsoGrants",type="LIST",value={mod={flags=0,keywordFlags=0,name="AilmentChance",type="INC",value=50},unscalable=true}}},nil} c["50% increased effect of Curses on you"]={{[1]={flags=0,keywordFlags=0,name="CurseEffectOnSelf",type="INC",value=50}},nil} c["50% increased effect of Incision"]={{[1]={flags=0,keywordFlags=0,name="IncisionEffect",type="INC",value=50}},nil} @@ -4633,7 +4633,7 @@ c["50% more Critical Damage Bonus"]={{[1]={flags=0,keywordFlags=0,name="CritMult c["50% more Damage with Arrow Hits at Close Range"]={{[1]={[1]={type="Condition",var="AtCloseRange"},flags=4,keywordFlags=2048,name="Damage",type="MORE",value=50}},nil} c["50% more Magnitude of Bleeding you inflict"]={{[1]={flags=0,keywordFlags=4194304,name="AilmentMagnitude",type="MORE",value=50}},nil} c["50% more Mana Cost of Skills if you have no Energy Shield"]={{[1]={[1]={neg=true,type="Condition",var="HaveEnergyShield"},flags=0,keywordFlags=0,name="ManaCost",type="MORE",value=50}},nil} -c["50% more amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="MORE",value=50}},nil} +c["50% more amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="MORE",value=50}},nil} c["50% more damage against enemies with an Open Weakness"]={{[1]={[1]={type="Condition",var="EnemyHasOpenWeakness"},flags=0,keywordFlags=0,name="Damage",type="MORE",value=50}},nil} c["50% of Chaos damage you prevent when Hit Recouped as Life and Mana during effect"]={{[1]={[1]={type="Condition",var="UsingFlask"},flags=0,keywordFlags=0,name="ChaosDamage",type="BASE",value=50}}," you prevent when Hit Recouped as Life and Mana "} c["50% of Charges consumed by used Charms are granted to your Life Flasks"]={{[1]={flags=0,keywordFlags=0,name="FlaskCharges",type="BASE",value=50}}," consumed by used Charms are granted to your Life Flasks "} @@ -4804,7 +4804,7 @@ c["6% increased Totem Damage"]={{[1]={flags=0,keywordFlags=16384,name="Damage",t c["6% increased Trap Throwing Speed"]={{[1]={flags=0,keywordFlags=0,name="TrapThrowingSpeed",type="INC",value=6}},nil} c["6% increased Warcry Buff Effect"]={{[1]={flags=0,keywordFlags=4,name="BuffEffect",type="INC",value=6}},nil} c["6% increased Warcry Cooldown Recovery Rate"]={{[1]={flags=0,keywordFlags=4,name="CooldownRecovery",type="INC",value=6}},nil} -c["6% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=6}},nil} +c["6% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=6}},nil} c["6% increased bonuses gained from Equipped Quiver"]={{[1]={flags=0,keywordFlags=0,name="EffectOfBonusesFromQuiver",type="INC",value=6}},nil} c["6% increased chance to inflict Ailments"]={{[1]={flags=0,keywordFlags=0,name="AilmentChance",type="INC",value=6}},nil} c["6% increased maximum Life"]={{[1]={flags=0,keywordFlags=0,name="Life",type="INC",value=6}},nil} @@ -5132,7 +5132,7 @@ c["8% increased Strength"]={{[1]={flags=0,keywordFlags=0,name="Str",type="INC",v c["8% increased Stun Threshold"]={{[1]={flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=8}},nil} c["8% increased Warcry Speed"]={{[1]={flags=0,keywordFlags=4,name="WarcrySpeed",type="INC",value=8}},nil} c["8% increased Withered Magnitude"]={{[1]={flags=0,keywordFlags=0,name="WitherEffect",type="INC",value=8}},nil} -c["8% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=8}},nil} +c["8% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechAmount",type="INC",value=8}},nil} c["8% increased chance to Shock"]={{[1]={flags=0,keywordFlags=0,name="EnemyShockChance",type="INC",value=8}},nil} c["8% increased chance to inflict Ailments"]={{[1]={flags=0,keywordFlags=0,name="AilmentChance",type="INC",value=8}},nil} c["8% increased maximum Energy Shield"]={{[1]={[1]={type="Global"},flags=0,keywordFlags=0,name="EnergyShield",type="INC",value=8}},nil} @@ -8392,7 +8392,7 @@ c["Leech 10% of Physical Attack Damage as Life"]={{[1]={flags=1,keywordFlags=0,n c["Leech 15% of Physical Attack Damage as Life"]={{[1]={flags=1,keywordFlags=0,name="PhysicalDamageLifeLeech",type="BASE",value=15}},nil} c["Leech 2% of Physical Attack Damage as Mana"]={{[1]={flags=1,keywordFlags=0,name="PhysicalDamageManaLeech",type="BASE",value=2}},nil} c["Leech 3% of Physical Attack Damage as Life"]={{[1]={flags=1,keywordFlags=0,name="PhysicalDamageLifeLeech",type="BASE",value=3}},nil} -c["Leech 30% faster"]={nil,"Leech 30% faster "} +c["Leech 30% faster"]={{[1]={flags=0,keywordFlags=0,name="LifeLeechRate",type="INC",value=30},[2]={flags=0,keywordFlags=0,name="ManaLeechRate",type="INC",value=30},[3]={flags=0,keywordFlags=0,name="EnergyShieldLeechRate",type="INC",value=30}},nil} c["Leech 5% of Physical Attack Damage as Life"]={{[1]={flags=1,keywordFlags=0,name="PhysicalDamageLifeLeech",type="BASE",value=5}},nil} c["Leech 5% of Physical Attack Damage as Mana"]={{[1]={flags=1,keywordFlags=0,name="PhysicalDamageManaLeech",type="BASE",value=5}},nil} c["Leech 6% of Physical Attack Damage as Mana"]={{[1]={flags=1,keywordFlags=0,name="PhysicalDamageManaLeech",type="BASE",value=6}},nil} diff --git a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua index 3346810c6c..8dfec0801e 100644 --- a/src/Data/SkillStatMap.lua +++ b/src/Data/SkillStatMap.lua @@ -508,12 +508,6 @@ return function(mod, flag, skill) mod("DamageEnergyShieldLeech", "BASE", nil, ModFlag.Spell), div = 100, }, -["maximum_life_leech_amount_per_leech_+%"] = { - mod("MaxLifeLeechRate", "INC", nil) -}, -["maximum_energy_shield_leech_amount_per_leech_+%"] = { - mod("MaxEnergyShieldLeechRate", "INC", nil) -}, ["mana_gain_per_target"] = { mod("ManaOnHit", "BASE", nil) }, diff --git a/src/Modules/CalcBreakdown.lua b/src/Modules/CalcBreakdown.lua index 193db6af9a..35d62eb317 100644 --- a/src/Modules/CalcBreakdown.lua +++ b/src/Modules/CalcBreakdown.lua @@ -206,57 +206,35 @@ return function(modDB, output, actor) return out end - function breakdown.leech(instant, instantRate, instances, pool, rate, max, dur, instantLeechProportion, hitRate) + function breakdown.leech(amount, instant, instantRate, instances, dur, recoveryRateMod, hitRate) local out = { } - if actor.mainSkill.skillData.showAverage then - if instant > 0 then - if instantLeechProportion ~= 1 then - t_insert(out, s_format("Instant Leech: %.1f ^8(%d%% x %.1f)", instant, instantLeechProportion * 100, dur * pool * data.misc.LeechRateBase / (1-instantLeechProportion))) - else - t_insert(out, s_format("Instant Leech: %.1f", instant)) - end - end - if instances > 0 then - t_insert(out, "Total leeched per instance:") - t_insert(out, s_format("%d ^8(size of leech destination pool)", pool)) - t_insert(out, s_format("x %.2f ^8(base leech rate is %d%% per second)", data.misc.LeechRateBase, 100 * data.misc.LeechRateBase)) - local rateMod = calcLib.mod(modDB, skillCfg, rate) - if rateMod ~= 1 then - 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)) + if instant > 0 then + t_insert(out, s_format("Instant Leech: %.1f ^8per hit", instant)) + if not actor.mainSkill.skillData.showAverage then + t_insert(out, s_format("Instant Leech per second: %.1f ^8(%.1f x %.2f hits per second)", instantRate, instant, hitRate)) end - else - if instantRate > 0 then - if instantLeechProportion ~= 1 then - t_insert(out, s_format("Instant Leech: %.1f ^8(%d%% x %.1f)", instant, instantLeechProportion * 100, dur * pool * data.misc.LeechRateBase / (1-instantLeechProportion))) - else - t_insert(out, s_format("Instant Leech: %.1f", instant)) - end - t_insert(out, s_format("Instant Leech per second: %.1f ^8(%.1f x %.2f)", instantRate, instant, hitRate)) - end - if instances > 0 then - t_insert(out, "Rate per instance:") - t_insert(out, s_format("%d ^8(size of leech destination pool)", pool)) - t_insert(out, s_format("x %.2f ^8(base leech rate is %d%% per second)", data.misc.LeechRateBase, 100 * data.misc.LeechRateBase)) - local rateMod = calcLib.mod(modDB, skillCfg, rate) - if rateMod ~= 1 then - t_insert(out, s_format("x %.2f ^8(leech rate modifier)", rateMod)) - end - t_insert(out, s_format("= %.1f ^8per second", pool * data.misc.LeechRateBase * rateMod)) - t_insert(out, "Maximum leech rate against one target:") - t_insert(out, s_format("%.1f", pool * data.misc.LeechRateBase * rateMod)) - t_insert(out, s_format("x %.2f ^8(average instances)", instances)) - local total = pool * data.misc.LeechRateBase * rateMod * instances - t_insert(out, s_format("= %.1f ^8per second", total)) - if total <= max then - t_insert(out, s_format("Time to reach max: %.1fs", dur)) + end + if dur > 0 then + if actor.mainSkill.skillData.showAverage then + t_insert(out, "Leeched over time per hit:") + t_insert(out, s_format("%.1f", amount)) + if recoveryRateMod ~= 1 then + t_insert(out, s_format("x %.2f ^8(recovery rate modifier)", recoveryRateMod)) end - t_insert(out, s_format("Leech rate cap: %.1f", max)) - if total > max then - t_insert(out, s_format("Time to reach cap: %.1fs", dur / total * max)) + t_insert(out, s_format("= %.1f ^8over %.2fs", amount * recoveryRateMod, dur)) + else + local instanceRate = amount / dur * recoveryRateMod + t_insert(out, "Rate of one instance:") + t_insert(out, s_format("%.1f ^8(leeched over time per hit)", amount)) + t_insert(out, s_format("/ %.2fs ^8(instance duration)", dur)) + if recoveryRateMod ~= 1 then + t_insert(out, s_format("x %.2f ^8(recovery rate modifier)", recoveryRateMod)) end + t_insert(out, s_format("= %.1f ^8per second", instanceRate)) + t_insert(out, "Only one instance recovers at a time:") + t_insert(out, s_format("%.1f", instanceRate)) + t_insert(out, s_format("x %.2f ^8(uptime: %.2f hits per second x %.2fs, up to 100%%)", m_min(instances, 1), hitRate, dur)) + t_insert(out, s_format("= %.1f ^8per second", instanceRate * m_min(instances, 1))) end end return out diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index b9e0c14773..cf807c7114 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -1659,41 +1659,6 @@ function calcs.defence(env, actor) output.ManaRecoveryRateMod = calcLib.mod(modDB, nil, "ManaRecoveryRate") output.EnergyShieldRecoveryRateMod = calcLib.mod(modDB, nil, "EnergyShieldRecoveryRate") - -- Leech caps - 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 - elseif modDB:Flag(nil, "MaximumLifeLeechIsEqualToPartyMember") then - output.MaxLifeLeechRatePercent = actor.partyMembers.output.MaxLifeLeechRatePercent - end - output.MaxLifeLeechRate = output.Life * output.MaxLifeLeechRatePercent / 100 - 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("= %.1f", output.MaxLifeLeechRate) - } - end - output.MaxEnergyShieldLeechInstance = output.EnergyShield * calcLib.val(modDB, "MaxEnergyShieldLeechInstance") / 100 - output.MaxEnergyShieldLeechRate = output.EnergyShield * calcLib.val(modDB, "MaxEnergyShieldLeechRate") / 100 - 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("= %.1f", output.MaxEnergyShieldLeechRate) - } - end - output.MaxManaLeechInstance = output.Mana * calcLib.val(modDB, "MaxManaLeechInstance") / 100 - output.MaxManaLeechRate = output.Mana * calcLib.val(modDB, "MaxManaLeechRate") / 100 - 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("= %.1f", output.MaxManaLeechRate) - } - end - -- Regeneration local resources = {"Mana", "Life", "Energy Shield", "Rage", "Ward"} for i, resourceName in ipairs(resources) do diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 960a5e16d4..5d742ed18c 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3338,11 +3338,13 @@ function calcs.offence(env, actor, activeSkill) end -- Calculate leech - local function getLeechInstances(amount, total, hitRate) - if total == 0 then + -- Each hit creates a leech instance that recovers its amount over LeechDurationBase seconds, shortened by leech speed modifiers. + -- The instant part of the leech is recovered on hit and removes the same proportion of the instance's duration. + local function getLeechInstances(amount, rateMod, instantProportion, hitRate) + if amount <= 0 or rateMod <= 0 then return 0, 0 end - local duration = amount / total / data.misc.LeechRateBase + local duration = data.misc.LeechDurationBase / rateMod * (1 - m_min(instantProportion, 1)) return duration, duration * hitRate end -- dynamic way of calculating the Ancestral Boost from a single source without duplicating the code @@ -4455,17 +4457,23 @@ function calcs.offence(env, actor, activeSkill) totalHitMax = totalHitMax + damageTypeHitMax end end + -- Hits dealing more than the leech damage cap leech as though they dealt the cap, with every damage type scaled down evenly + local passHitAvg = (pass == 1) and totalCritAvg or totalHitAvg + if passHitAvg > data.misc.LeechDamageCap then + local leechDamageScale = data.misc.LeechDamageCap / passHitAvg + lifeLeechTotal = lifeLeechTotal * leechDamageScale + energyShieldLeechTotal = energyShieldLeechTotal * leechDamageScale + manaLeechTotal = manaLeechTotal * leechDamageScale + end if skillData.lifeLeechPerUse then lifeLeechTotal = lifeLeechTotal + skillData.lifeLeechPerUse end if skillData.manaLeechPerUse then manaLeechTotal = manaLeechTotal + skillData.manaLeechPerUse end - - -- leech caps per instance - lifeLeechTotal = m_min(lifeLeechTotal, globalOutput.MaxLifeLeechInstance) - energyShieldLeechTotal = m_min(energyShieldLeechTotal, globalOutput.MaxEnergyShieldLeechInstance) - manaLeechTotal = m_min(manaLeechTotal, globalOutput.MaxManaLeechInstance) + lifeLeechTotal = lifeLeechTotal * calcLib.mod(skillModList, cfg, "LifeLeechAmount") + energyShieldLeechTotal = energyShieldLeechTotal * calcLib.mod(skillModList, cfg, "EnergyShieldLeechAmount") + manaLeechTotal = manaLeechTotal * calcLib.mod(skillModList, cfg, "ManaLeechAmount") local portion = (pass == 1) and (output.CritChance / 100) or (1 - output.CritChance / 100) output.LifeLeech = output.LifeLeech + lifeLeechTotal * portion @@ -4523,11 +4531,11 @@ function calcs.offence(env, actor, activeSkill) output.EnergyShieldLeech = output.EnergyShieldLeech * (1 - output.EnergyShieldLeechInstantProportion) end - output.LifeLeechDuration, output.LifeLeechInstances = getLeechInstances(output.LifeLeech, globalOutput.Life, hitRate) + output.LifeLeechDuration, output.LifeLeechInstances = getLeechInstances(output.LifeLeech, calcLib.mod(skillModList, cfg, "LifeLeechRate"), output.LifeLeechInstantProportion, hitRate) output.LifeLeechInstantRate = output.LifeLeechInstant * hitRate - output.EnergyShieldLeechDuration, output.EnergyShieldLeechInstances = getLeechInstances(output.EnergyShieldLeech, globalOutput.EnergyShield, hitRate) + output.EnergyShieldLeechDuration, output.EnergyShieldLeechInstances = getLeechInstances(output.EnergyShieldLeech, calcLib.mod(skillModList, cfg, "EnergyShieldLeechRate"), output.EnergyShieldLeechInstantProportion, hitRate) output.EnergyShieldLeechInstantRate = output.EnergyShieldLeechInstant * hitRate - output.ManaLeechDuration, output.ManaLeechInstances = getLeechInstances(output.ManaLeech, globalOutput.Mana, hitRate) + output.ManaLeechDuration, output.ManaLeechInstances = getLeechInstances(output.ManaLeech, calcLib.mod(skillModList, cfg, "ManaLeechRate"), output.ManaLeechInstantProportion, hitRate) output.ManaLeechInstantRate = output.ManaLeechInstant * hitRate -- Calculate gain on hit @@ -4730,16 +4738,19 @@ function calcs.offence(env, actor, activeSkill) combineStat("DpsMultiplier", "DPS") combineStat("TotalDPS", "DPS") combineStat("PvpTotalDPS", "DPS") + combineStat("LifeLeech", "DPS") combineStat("LifeLeechDuration", "DPS") combineStat("LifeLeechInstances", "DPS") combineStat("LifeLeechInstant", "DPS") combineStat("LifeLeechInstantRate", "DPS") combineStat("LifeLeechInstantProportion", "DPS") + combineStat("EnergyShieldLeech", "DPS") combineStat("EnergyShieldLeechDuration", "DPS") combineStat("EnergyShieldLeechInstances", "DPS") combineStat("EnergyShieldLeechInstant", "DPS") combineStat("EnergyShieldLeechInstantRate", "DPS") combineStat("EnergyShieldLeechInstantProportion", "DPS") + combineStat("ManaLeech", "DPS") combineStat("ManaLeechDuration", "DPS") combineStat("ManaLeechInstances", "DPS") combineStat("ManaLeechInstant", "DPS") @@ -4905,15 +4916,16 @@ function calcs.offence(env, actor, activeSkill) end -- Calculate leech rates - output.LifeLeechInstanceRate = output.Life * data.misc.LeechRateBase * calcLib.mod(skillModList, skillCfg, "LifeLeechRate") - output.LifeLeechRate = output.LifeLeechInstances * output.LifeLeechInstanceRate - output.LifeLeechPerHit = output.LifeLeechInstanceRate - output.EnergyShieldLeechInstanceRate = output.EnergyShield * data.misc.LeechRateBase * calcLib.mod(skillModList, skillCfg, "EnergyShieldLeechRate") - output.EnergyShieldLeechRate = output.EnergyShieldLeechInstances * output.EnergyShieldLeechInstanceRate - output.EnergyShieldLeechPerHit = output.EnergyShieldLeechInstanceRate - output.ManaLeechInstanceRate = output.Mana * data.misc.LeechRateBase * calcLib.mod(skillModList, skillCfg, "ManaLeechRate") - output.ManaLeechRate = output.ManaLeechInstances * output.ManaLeechInstanceRate - output.ManaLeechPerHit = output.ManaLeechInstanceRate + -- Only one leech instance per resource recovers at a time, so the sustained rate is the rate of one instance for the portion of time an instance is active + output.LifeLeechInstanceRate = output.LifeLeechDuration > 0 and output.LifeLeech / output.LifeLeechDuration or 0 + output.LifeLeechRate = output.LifeLeechInstanceRate * m_min(output.LifeLeechInstances, 1) + output.LifeLeechPerHit = output.LifeLeech + output.EnergyShieldLeechInstanceRate = output.EnergyShieldLeechDuration > 0 and output.EnergyShieldLeech / output.EnergyShieldLeechDuration or 0 + output.EnergyShieldLeechRate = output.EnergyShieldLeechInstanceRate * m_min(output.EnergyShieldLeechInstances, 1) + output.EnergyShieldLeechPerHit = output.EnergyShieldLeech + output.ManaLeechInstanceRate = output.ManaLeechDuration > 0 and output.ManaLeech / output.ManaLeechDuration or 0 + output.ManaLeechRate = output.ManaLeechInstanceRate * m_min(output.ManaLeechInstances, 1) + output.ManaLeechPerHit = output.ManaLeech -- On full life, Immortal Ambition treats life leech as energy shield leech if skillModList:Flag(nil, "ImmortalAmbition") then output.EnergyShieldLeechRate = output.EnergyShieldLeechRate + output.LifeLeechRate @@ -4928,12 +4940,12 @@ function calcs.offence(env, actor, activeSkill) output.LifeLeechPerHit = 0 output.LifeLeechInstances = 0 end - output.LifeLeechRate = output.LifeLeechInstantRate + m_min(output.LifeLeechRate, output.MaxLifeLeechRate) * output.LifeRecoveryRateMod - output.LifeLeechPerHit = output.LifeLeechInstant + m_min(output.LifeLeechPerHit, output.MaxLifeLeechRate) * output.LifeLeechDuration * output.LifeRecoveryRateMod - output.EnergyShieldLeechRate = output.EnergyShieldLeechInstantRate + m_min(output.EnergyShieldLeechRate, output.MaxEnergyShieldLeechRate) * output.EnergyShieldRecoveryRateMod - output.EnergyShieldLeechPerHit = output.EnergyShieldLeechInstant + m_min(output.EnergyShieldLeechPerHit, output.MaxEnergyShieldLeechRate) * output.EnergyShieldLeechDuration * output.EnergyShieldRecoveryRateMod - output.ManaLeechRate = output.ManaLeechInstantRate + m_min(output.ManaLeechRate, output.MaxManaLeechRate) * output.ManaRecoveryRateMod - output.ManaLeechPerHit = output.ManaLeechInstant + m_min(output.ManaLeechPerHit, output.MaxManaLeechRate) * output.ManaLeechDuration * output.ManaRecoveryRateMod + output.LifeLeechRate = output.LifeLeechInstantRate + output.LifeLeechRate * output.LifeRecoveryRateMod + output.LifeLeechPerHit = output.LifeLeechInstant + output.LifeLeechPerHit * output.LifeRecoveryRateMod + output.EnergyShieldLeechRate = output.EnergyShieldLeechInstantRate + output.EnergyShieldLeechRate * output.EnergyShieldRecoveryRateMod + output.EnergyShieldLeechPerHit = output.EnergyShieldLeechInstant + output.EnergyShieldLeechPerHit * output.EnergyShieldRecoveryRateMod + output.ManaLeechRate = output.ManaLeechInstantRate + output.ManaLeechRate * output.ManaRecoveryRateMod + output.ManaLeechPerHit = output.ManaLeechInstant + output.ManaLeechPerHit * output.ManaRecoveryRateMod skillFlags.leechLife = output.LifeLeechRate > 0 skillFlags.leechES = output.EnergyShieldLeechRate > 0 skillFlags.leechMana = output.ManaLeechRate > 0 @@ -4949,13 +4961,13 @@ function calcs.offence(env, actor, activeSkill) if breakdown then local hitRate = output.HitChance / 100 * (globalOutput.HitSpeed or globalOutput.Speed) * output.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.LifeLeech, output.LifeLeechInstant, output.LifeLeechInstantRate, output.LifeLeechInstances, output.LifeLeechDuration, output.LifeRecoveryRateMod, hitRate) 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.EnergyShieldLeech, output.EnergyShieldLeechInstant, output.EnergyShieldLeechInstantRate, output.EnergyShieldLeechInstances, output.EnergyShieldLeechDuration, output.EnergyShieldRecoveryRateMod, hitRate) 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.ManaLeech, output.ManaLeechInstant, output.ManaLeechInstantRate, output.ManaLeechInstances, output.ManaLeechDuration, output.ManaRecoveryRateMod, hitRate) end end diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index b2f044f345..9ed0133020 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -3632,8 +3632,6 @@ function calcs.perform(env, skipEHP) buffExports.PlayerMods["BlockChanceMax="..tostring(output["BlockChanceMax"])] = true elseif mod.name == "BlockAttackChanceIsEqualToParent" then buffExports.PlayerMods["BlockChance="..tostring(output["BlockChance"])] = true - elseif mod.name == "MaximumLifeLeechIsEqualToPartyMember" then - buffExports.PlayerMods["MaxLifeLeechRatePercent="..tostring(output["MaxLifeLeechRatePercent"])] = true elseif mod.name == "TakenFromParentESBeforeYou" then buffExports.PlayerMods["EnergyShieldRecoveryCap="..tostring(output["EnergyShieldRecoveryCap"])] = true elseif mod.name == "MainHandCritIsEqualToParent" then diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index e5604958c8..65856a2207 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -1219,10 +1219,6 @@ return { } } } }, { 1, "LeechGain", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Leech & Gain on Hit", data = { - { label = "Life Leech Cap", flag = "leechLife", { format = "{1:output:MaxLifeLeechRate}", - { breakdown = "MaxLifeLeechRate" }, - { modName = "MaxLifeLeechRate" }, - }, }, { label = "Life Leech Rate", flag = "leechLife", notFlag = "showAverage", { format = "{1:output:LifeLeechRate}", { breakdown = "LifeLeech" }, { label = "Player modifiers", notFlagList = { "totem", "attack" }, modName = { "DamageLeech", "DamageLifeLeech", "PhysicalDamageLifeLeech", "LightningDamageLifeLeech", "ColdDamageLifeLeech", "FireDamageLifeLeech", "ChaosDamageLifeLeech", "ElementalDamageLifeLeech" }, modType = "BASE", cfg = "skill" }, @@ -1231,6 +1227,8 @@ return { { label = "Totem modifiers", flag = "totem", modName = { "DamageLifeLeechToPlayer" }, modType = "BASE", cfg = "skill" }, { label = "Enemy modifiers", modName = { "SelfDamageLifeLeech" }, modType = "BASE", enemy = true }, { label = "Leech Conversion", modName = { "LifeLeechBasedOnPhysicalDamage", "LifeLeechBasedOnColdDamage", "LifeLeechBasedOnFireDamage", "LifeLeechBasedOnLightningDamage", "LifeLeechBasedOnElementalDamage", "LifeLeechBasedOnChaosDamage", "Condition:NoLifeLeechFromPhysicalDamage", "Condition:NoLifeLeechFromColdDamage", "Condition:NoLifeLeechFromFireDamage", "Condition:NoLifeLeechFromLightningDamage", "Condition:NoLifeLeechFromElementalDamage", "Condition:NoLifeLeechFromChaosDamage" }, cfg = "skill" }, + { label = "Leech amount", modName = "LifeLeechAmount", cfg = "skill" }, + { label = "Leech speed", modName = "LifeLeechRate", cfg = "skill" }, }, }, { label = "Life Leech per Hit", flagList = { "leechLife", "showAverage" }, { format = "{1:output:LifeLeechPerHit}", { breakdown = "LifeLeech" }, @@ -1240,6 +1238,8 @@ return { { label = "Totem modifiers", flag = "totem", modName = { "DamageLifeLeechToPlayer" }, modType = "BASE", cfg = "skill" }, { label = "Enemy modifiers", modName = { "SelfDamageLifeLeech" }, modType = "BASE", enemy = true }, { label = "Leech Conversion", modName = { "LifeLeechBasedOnPhysicalDamage", "LifeLeechBasedOnColdDamage", "LifeLeechBasedOnFireDamage", "LifeLeechBasedOnLightningDamage", "LifeLeechBasedOnElementalDamage", "LifeLeechBasedOnChaosDamage", "Condition:NoLifeLeechFromPhysicalDamage", "Condition:NoLifeLeechFromColdDamage", "Condition:NoLifeLeechFromFireDamage", "Condition:NoLifeLeechFromLightningDamage", "Condition:NoLifeLeechFromElementalDamage", "Condition:NoLifeLeechFromChaosDamage" }, cfg = "skill" }, + { label = "Leech amount", modName = "LifeLeechAmount", cfg = "skill" }, + { label = "Leech speed", modName = "LifeLeechRate", cfg = "skill" }, }, }, { label = "Life Gain Rate", notFlag = "showAverage", haveOutput = "LifeOnHitRate", { format = "{1:output:LifeOnHitRate}", { label = "Player modifiers", notFlag = "attack", modName = "LifeOnHit", modType = "BASE", cfg = "skill" }, @@ -1256,10 +1256,6 @@ return { { label = "Life Gain on Kill", haveOutput = "LifeOnKill", { format = "{1:output:LifeOnKill}", {modName = "LifeOnKill"}, }, }, - { label = "ES Leech Cap", flag = "leechES", { format = "{1:output:MaxEnergyShieldLeechRate}", - { breakdown = "MaxEnergyShieldLeechRate" }, - { modName = "MaxEnergyShieldLeechRate" }, - }, }, { label = "ES Leech Rate", flag = "leechES", notFlag = "showAverage", { format = "{1:output:EnergyShieldLeechRate}", { breakdown = "EnergyShieldLeech" }, { label = "Player modifiers", notFlagList = { "totem", "attack" }, modName = { "DamageEnergyShieldLeech", "PhysicalDamageEnergyShieldLeech", "LightningDamageEnergyShieldLeech", "ColdDamageEnergyShieldLeech", "FireDamageEnergyShieldLeech", "ChaosDamageEnergyShieldLeech", "ElementalDamageEnergyShieldLeech" }, modType = "BASE", cfg = "skill" }, @@ -1268,6 +1264,8 @@ return { { label = "Totem modifiers", flag = "totem", modName = { "DamageEnergyShieldLeechToPlayer" }, modType = "BASE", cfg = "skill" }, { label = "Enemy modifiers", modName = { "SelfDamageEnergyShieldLeech" }, modType = "BASE", enemy = true }, { label = "Leech Conversion", modName = { "EnergyShieldLeechBasedOnPhysicalDamage", "EnergyShieldLeechBasedOnColdDamage", "EnergyShieldLeechBasedOnFireDamage", "EnergyShieldLeechBasedOnLightningDamage", "EnergyShieldLeechBasedOnElementalDamage", "EnergyShieldLeechBasedOnChaosDamage", "Condition:NoEnergyShieldLeechFromPhysicalDamage", "Condition:NoEnergyShieldLeechFromColdDamage", "Condition:NoEnergyShieldLeechFromFireDamage", "Condition:NoEnergyShieldLeechFromLightningDamage", "Condition:NoEnergyShieldLeechFromElementalDamage", "Condition:NoEnergyShieldLeechFromChaosDamage" }, cfg = "skill" }, + { label = "Leech amount", modName = "EnergyShieldLeechAmount", cfg = "skill" }, + { label = "Leech speed", modName = "EnergyShieldLeechRate", cfg = "skill" }, }, }, { label = "ES Leech per Hit", flagList = { "leechES", "showAverage" }, { format = "{1:output:EnergyShieldLeechPerHit}", { breakdown = "EnergyShieldLeech" }, @@ -1277,6 +1275,8 @@ return { { label = "Totem modifiers", flag = "totem", modName = { "DamageEnergyShieldLeechToPlayer" }, modType = "BASE", cfg = "skill" }, { label = "Enemy modifiers", modName = { "SelfDamageEnergyShieldLeech" }, modType = "BASE", enemy = true }, { label = "Leech Conversion", modName = { "EnergyShieldLeechBasedOnPhysicalDamage", "EnergyShieldLeechBasedOnColdDamage", "EnergyShieldLeechBasedOnFireDamage", "EnergyShieldLeechBasedOnLightningDamage", "EnergyShieldLeechBasedOnElementalDamage", "EnergyShieldLeechBasedOnChaosDamage", "Condition:NoEnergyShieldLeechFromPhysicalDamage", "Condition:NoEnergyShieldLeechFromColdDamage", "Condition:NoEnergyShieldLeechFromFireDamage", "Condition:NoEnergyShieldLeechFromLightningDamage", "Condition:NoEnergyShieldLeechFromElementalDamage", "Condition:NoEnergyShieldLeechFromChaosDamage" }, cfg = "skill" }, + { label = "Leech amount", modName = "EnergyShieldLeechAmount", cfg = "skill" }, + { label = "Leech speed", modName = "EnergyShieldLeechRate", cfg = "skill" }, }, }, { label = "ES Gain Rate", notFlag = "showAverage", haveOutput = "EnergyShieldOnHitRate", { format = "{1:output:EnergyShieldOnHitRate}", { label = "Player modifiers", notFlag = "attack", modName = "EnergyShieldOnHit", modType = "BASE", cfg = "skill" }, @@ -1293,10 +1293,6 @@ return { { label = "ES Gain on Kill", haveOutput = "EnergyShieldOnKill", { format = "{1:output:EnergyShieldOnKill}", {modName = "EnergyShieldOnKill"}, }, }, - { label = "Mana Leech Cap", flag = "leechMana", { format = "{1:output:MaxManaLeechRate}", - { breakdown = "MaxManaLeechRate" }, - { modName = "MaxManaLeechRate" }, - }, }, { label = "Mana Leech Rate", flag = "leechMana", notFlag = "showAverage", { format = "{1:output:ManaLeechRate}", { breakdown = "ManaLeech" }, { label = "Player modifiers", notFlag = "attack", modName = { "DamageLeech", "DamageManaLeech", "PhysicalDamageManaLeech", "LightningDamageManaLeech", "ColdDamageManaLeech", "FireDamageManaLeech", "ChaosDamageManaLeech", "ElementalDamageManaLeech" }, modType = "BASE", cfg = "skill" }, @@ -1304,6 +1300,8 @@ return { { label = "Off Hand", flag = "weapon2Attack", modName = { "DamageLeech", "DamageManaLeech", "PhysicalDamageManaLeech", "LightningDamageManaLeech", "ColdDamageManaLeech", "FireDamageManaLeech", "ChaosDamageManaLeech", "ElementalDamageManaLeech" }, modType = "BASE", cfg = "weapon2" }, { label = "Enemy modifiers", modName = { "SelfDamageManaLeech" }, modType = "BASE", cfg = "skill", enemy = true }, { label = "Leech Conversion", modName = { "ManaLeechBasedOnPhysicalDamage", "ManaLeechBasedOnColdDamage", "ManaLeechBasedOnFireDamage", "ManaLeechBasedOnLightningDamage", "ManaLeechBasedOnElementalDamage", "ManaLeechBasedOnChaosDamage", "Condition:NoManaLeechFromPhysicalDamage", "Condition:NoManaLeechFromColdDamage", "Condition:NoManaLeechFromFireDamage", "Condition:NoManaLeechFromLightningDamage", "Condition:NoManaLeechFromElementalDamage", "Condition:NoManaLeechFromChaosDamage" }, cfg = "skill" }, + { label = "Leech amount", modName = "ManaLeechAmount", cfg = "skill" }, + { label = "Leech speed", modName = "ManaLeechRate", cfg = "skill" }, }, }, { label = "Mana Leech per Hit", flagList = { "leechMana", "showAverage" }, { format = "{1:output:ManaLeechPerHit}", { breakdown = "ManaLeech" }, @@ -1312,6 +1310,8 @@ return { { label = "Off Hand", flag = "weapon2Attack", modName = { "DamageLeech", "DamageManaLeech", "PhysicalDamageManaLeech", "LightningDamageManaLeech", "ColdDamageManaLeech", "FireDamageManaLeech", "ChaosDamageManaLeech", "ElementalDamageManaLeech" }, modType = "BASE", cfg = "weapon2" }, { label = "Enemy modifiers", modName = { "SelfDamageManaLeech" }, modType = "BASE", enemy = true }, { label = "Leech Conversion", modName = { "ManaLeechBasedOnPhysicalDamage", "ManaLeechBasedOnColdDamage", "ManaLeechBasedOnFireDamage", "ManaLeechBasedOnLightningDamage", "ManaLeechBasedOnElementalDamage", "ManaLeechBasedOnChaosDamage", "Condition:NoManaLeechFromPhysicalDamage", "Condition:NoManaLeechFromColdDamage", "Condition:NoManaLeechFromFireDamage", "Condition:NoManaLeechFromLightningDamage", "Condition:NoManaLeechFromElementalDamage", "Condition:NoManaLeechFromChaosDamage" }, cfg = "skill" }, + { label = "Leech amount", modName = "ManaLeechAmount", cfg = "skill" }, + { label = "Leech speed", modName = "ManaLeechRate", cfg = "skill" }, }, }, { label = "Mana Gain Rate", notFlag = "showAverage", haveOutput = "ManaOnHitRate", { format = "{1:output:ManaOnHitRate}", { label = "Player modifiers", notFlag = "attack", modName = "ManaOnHit", modType = "BASE", cfg = "skill" }, diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 76c1bd37ba..88ec662996 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -49,16 +49,10 @@ function calcs.initModDB(env, modDB) modDB:NewMod("AbsorptionChargesMax", "BASE", 0, "Base") modDB:NewMod("AfflictionChargesMax", "BASE", 0, "Base") modDB:NewMod("BloodChargesMax", "BASE", 5, "Base") - modDB:NewMod("MaxLifeLeechRate", "BASE", 20, "Base") - modDB:NewMod("MaxManaLeechRate", "BASE", 20, "Base") modDB:NewMod("ImpaleStacksMax", "BASE", 5, "Base") modDB:NewMod("IgniteStacksMax", "BASE", 1, "Base") modDB:NewMod("BleedStacksMax", "BASE", 1, "Base") modDB:NewMod("PoisonStacksMax", "BASE", 1, "Base") - modDB:NewMod("MaxEnergyShieldLeechRate", "BASE", 10, "Base") - modDB:NewMod("MaxLifeLeechInstance", "BASE", 10, "Base") - modDB:NewMod("MaxManaLeechInstance", "BASE", 10, "Base") - modDB:NewMod("MaxEnergyShieldLeechInstance", "BASE", 10, "Base") modDB:NewMod("TrapThrowingTime", "BASE", 0.6, "Base") modDB:NewMod("MineLayingTime", "BASE", 0.3, "Base") modDB:NewMod("WarcryCastTime", "BASE", 0.8, "Base") diff --git a/src/Modules/Data.lua b/src/Modules/Data.lua index 90546be5bf..515721cfc5 100644 --- a/src/Modules/Data.lua +++ b/src/Modules/Data.lua @@ -265,7 +265,8 @@ data.misc = { -- magic numbers EnergyShieldRechargeDelay = 4, Transfiguration = 0.3, EnemyMaxResist = data.monsterConstants["base_maximum_all_resistances_%"], - LeechRateBase = 0.02, + LeechDurationBase = 1, + LeechDamageCap = data.gameConstants["EffectiveMaxDamageForLeech"], DotDpsCap = 35791394, -- (2 ^ 31 - 1) / 60 (int max / 60 seconds) BleedPercentBase = data.gameConstants["BleedingHitDamagePercentPerMinute"] / 60 / 100, BleedDurationBase = data.gameConstants["BaseBleedingDuration"], diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 6d8d909dcb..257dc8461b 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -576,21 +576,11 @@ local modNameList = { ["total recovery per second from mana leech"] = "ManaLeechRate", ["recovery per second from mana leech"] = "ManaLeechRate", ["total recovery per second from life, mana, or energy shield leech"] = { "LifeLeechRate", "ManaLeechRate", "EnergyShieldLeechRate" }, - ["maximum recovery per life leech"] = "MaxLifeLeechInstance", - ["maximum recovery per energy shield leech"] = "MaxEnergyShieldLeechInstance", - ["maximum recovery per mana leech"] = "MaxManaLeechInstance", - ["maximum total recovery per second from life leech"] = "MaxLifeLeechRate", - ["maximum total life recovery per second from leech"] = "MaxLifeLeechRate", - ["maximum total recovery per second from energy shield leech"] = "MaxEnergyShieldLeechRate", - ["maximum total energy shield recovery per second from leech"] = "MaxEnergyShieldLeechRate", - ["maximum total recovery per second from mana leech"] = "MaxManaLeechRate", - ["maximum total mana recovery per second from leech"] = "MaxManaLeechRate", - ["maximum total life, mana and energy shield recovery per second from leech"] = { "MaxLifeLeechRate", "MaxManaLeechRate", "MaxEnergyShieldLeechRate" }, ["life and mana leech is instant"] = { "InstantManaLeech", "InstantLifeLeech" }, ["life leech is instant"] = "InstantLifeLeech", ["mana leech is instant"] = "InstantManaLeech", - ["amount of mana leeched"] = "MaxManaLeechRate", - ["amount of life leeched"] = "MaxLifeLeechRate", + ["amount of mana leeched"] = "ManaLeechAmount", + ["amount of life leeched"] = "LifeLeechAmount", ["energy shield leech is instant"] = { "InstantEnergyShieldLeech" }, ["leech is instant"] = { "InstantEnergyShieldLeech", "InstantManaLeech", "InstantLifeLeech" }, ["to impale enemies on hit"] = "ImpaleChance", @@ -2358,13 +2348,7 @@ local specialModList = { flag("Condition:CanGainRage"), } end, ["(%w+) recovery from regeneration is not applied"] = function(_, type) return { flag("UnaffectedBy" .. firstToUpper(type) .. "Regen") } end, - ["(%d+)%% less damage taken for every (%d+)%% life recovery per second from leech"] = function(num, _, div) - return { mod("DamageTaken", "MORE", -num, { type = "PerStat", stat = "MaxLifeLeechRatePercent", div = tonumber(div) }) } - end, ["(%w+) recovery from non%-instant leech is not applied"] = function(_, type) return { flag("UnaffectedByNonInstant" .. firstToUpper(type) .. "Leech") } end, - ["(%d+)%% additional physical damage reduction for every (%d+)%% life recovery per second from leech"] = function(num, _, div) - return { mod("PhysicalDamageReduction", "BASE", num, { type = "PerStat", stat = "MaxLifeLeechRatePercent", div = tonumber(div) }, { type = "Condition", var = "Leeching"}) } - end, ["modifiers to chance to suppress spell damage instead apply to chance to dodge spell hits at 50%% of their value"] = { flag("ConvertSpellSuppressionToSpellDodge"), mod("SpellSuppressionChance", "OVERRIDE", 0, "Acrobatics"), @@ -2410,6 +2394,8 @@ local specialModList = { }, ["leech life (%d+)%% slower"] = function(num) return {mod("LifeLeechRate", "INC", -num)} end, ["leech life (%d+)%% faster"] = function(num) return {mod("LifeLeechRate", "INC", num)} end, + ["leech (%d+)%% slower"] = function(num) return { mod("LifeLeechRate", "INC", -num), mod("ManaLeechRate", "INC", -num), mod("EnergyShieldLeechRate", "INC", -num) } end, + ["leech (%d+)%% faster"] = function(num) return { mod("LifeLeechRate", "INC", num), mod("ManaLeechRate", "INC", num), mod("EnergyShieldLeechRate", "INC", num) } end, ["life regeneration is applied to energy shield instead"] = { flag("ZealotsOath") }, ["mana recovery from regeneration is also applied to runic ward"] = { flag("ManaRegenerationRecoversWard") }, ["excess life recovery from regeneration is applied to energy shield"] = { flag("ZealotsOath", { type = "Condition", var = "FullLife" }) },