From db433b9f16bc4bb5e69da09d51503fe28941974d Mon Sep 17 00:00:00 2001 From: Regisle Date: Thu, 19 Oct 2023 11:00:09 +1030 Subject: [PATCH 1/2] Add support for pseudo recoup like divine shield and juggernaut --- src/Data/ModCache.lua | 6 ++-- src/Modules/CalcDefence.lua | 65 ++++++++++++++++++++++++++++++++++-- src/Modules/CalcSections.lua | 20 ++++++++--- src/Modules/ModParser.lua | 5 +++ 4 files changed, 85 insertions(+), 11 deletions(-) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index 5b96dde39d..1ff9b68f31 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -1896,9 +1896,8 @@ c["1.5% of Lightning Damage is Leeched as Energy Shield while affected by Wrath" c["1.5% of Lightning Damage is Leeched as Mana while affected by Wrath"]={{[1]={[1]={type="Condition",var="AffectedByWrath"},flags=0,keywordFlags=0,name="LightningDamageManaLeech",type="BASE",value=1.5}},nil} c["1.5% of Physical Attack Damage Leeched as Mana"]={{[1]={flags=1,keywordFlags=0,name="PhysicalDamageManaLeech",type="BASE",value=1.5}},nil} c["1.5% of Physical Damage prevented from Hits in the past"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="BASE",value=1.5}}," prevented from Hits in the past "} -c["1.5% of Physical Damage prevented from Hits in the past 10 seconds is Regenerated as Life per second"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="BASE",value=1.5}}," prevented from Hits in the past 10 seconds is Regenerated as Life per second "} +c["1.5% of Physical Damage prevented from Hits in the past 10 seconds is Regenerated as Life per second"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamageMitigatedLifePseudoRecoup",type="BASE",value=15},[2]={flags=0,keywordFlags=0,name="PhysicalDamageMitigatedLifePseudoRecoupDuration",type="BASE",value="10"}},nil} c["1.6% of Physical Attack Damage Leeched as Life"]={{[1]={flags=1,keywordFlags=0,name="PhysicalDamageLifeLeech",type="BASE",value=1.6}},nil} -c["10 seconds is Regenerated as Life per second"]={{[1]={flags=0,keywordFlags=0,name="Life",type="BASE",value=10}}," seconds is Regenerated as per second "} c["10% Chance for Traps to Trigger an additional time"]={{}," to Trigger an additional time "} c["10% Chance to Block Attack Damage"]={{[1]={flags=0,keywordFlags=0,name="BlockChance",type="BASE",value=10}},nil} c["10% Chance to Block Attack Damage during Effect"]={{[1]={[1]={type="Condition",var="UsingFlask"},flags=0,keywordFlags=0,name="BlockChance",type="BASE",value=10}},nil} @@ -4126,8 +4125,7 @@ c["3% more Spell Damage per Power Charge"]={{[1]={[1]={type="Multiplier",var="Po c["3% of Attack Damage leeched as Life against Bleeding Enemies"]={{[1]={[1]={actor="enemy",type="ActorCondition",var="Bleeding"},flags=1,keywordFlags=0,name="DamageLifeLeech",type="BASE",value=3}},nil} c["3% of Life Regenerated per Second if you've dealt a Critical Strike in the past 8 seconds"]={{[1]={[1]={type="Condition",var="CritInPast8Sec"},flags=0,keywordFlags=0,name="LifeRegenPercent",type="BASE",value=3}},nil} c["3% of Physical Attack Damage Leeched as Life"]={{[1]={flags=1,keywordFlags=0,name="PhysicalDamageLifeLeech",type="BASE",value=3}},nil} -c["3% of Physical Damage prevented from Hits Recently is Regenerated as Energy Shield per second"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="BASE",value=3}}," prevented from Hits Recently is Regenerated as Energy Shield per second "} -c["3% of Physical Damage prevented from Hits Recently is Regenerated as Energy Shield per second Limited to 1 Keystone Tattoo"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="BASE",value=3}}," prevented from Hits Recently is Regenerated as Energy Shield per second Limited to 1 Keystone Tattoo "} +c["3% of Physical Damage prevented from Hits Recently is Regenerated as Energy Shield per second"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamageMitigatedEnergyShieldPseudoRecoup",type="BASE",value=12}},nil} c["3% reduced Attack and Cast Speed per Frenzy Charge"]={{[1]={[1]={type="Multiplier",var="FrenzyCharge"},flags=0,keywordFlags=0,name="Speed",type="INC",value=-3}},nil} c["3% reduced Cost of Skills"]={{[1]={flags=0,keywordFlags=0,name="Cost",type="INC",value=-3}},nil} c["3% reduced Mana Cost of Skills"]={{[1]={flags=0,keywordFlags=0,name="ManaCost",type="INC",value=-3}},nil} diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 4121195114..d0037468f9 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -1141,6 +1141,36 @@ function calcs.defence(env, actor) end end end + + -- pseudo recoup (eg %physicial damage prevented from hits regenerated) + for _, resource in ipairs(recoupTypeList) do + if not modDB:Flag(nil, "No"..resource.."Regen") and not modDB:Flag(nil, "CannotGain"..resource) then + local PhysicalDamageMitigatedPseudoRecoup = modDB:Sum("BASE", nil, "PhysicalDamageMitigated"..resource.."PseudoRecoup") + if PhysicalDamageMitigatedPseudoRecoup > 0 then + output["PhysicalDamageMitigated"..resource.."PseudoRecoupDuration"] = modDB:Sum("BASE", nil, "PhysicalDamageMitigated"..resource.."PseudoRecoupDuration") + if output["PhysicalDamageMitigated"..resource.."PseudoRecoupDuration"] == 0 then + output["PhysicalDamageMitigated"..resource.."PseudoRecoupDuration"] = 4 + end + local inc = modDB:Sum("INC", nil, resource.."Regen") + local more = modDB:More(nil, resource.."Regen") + output["PhysicalDamageMitigated"..resource.."PseudoRecoup"] = PhysicalDamageMitigatedPseudoRecoup * (1 + inc/100) * more * output[resource.."RecoveryRateMod"] + output["anyRecoup"] = output["anyRecoup"] + output["PhysicalDamageMitigated"..resource.."PseudoRecoup"] + if breakdown then + breakdown["PhysicalDamageMitigated"..resource.."PseudoRecoup"] = { } + if output[resource.."RecoveryRateMod"] ~= 1 or inc ~= 0 or more ~= 1 then + t_insert(breakdown["PhysicalDamageMitigated"..resource.."PseudoRecoup"], s_format("%d%% ^8(base)", PhysicalDamageMitigatedPseudoRecoup)) + if inc ~= 0 or more ~= 1 then + t_insert(breakdown["PhysicalDamageMitigated"..resource.."PseudoRecoup"], s_format("* %.2f ^8(regeneration rate modifier)", (1 + inc/100) * more)) + end + if output[resource.."RecoveryRateMod"] ~= 1 then + t_insert(breakdown["PhysicalDamageMitigated"..resource.."PseudoRecoup"], s_format("* %.2f ^8(recovery rate modifier)", output[resource.."RecoveryRateMod"])) + end + end + t_insert(breakdown["PhysicalDamageMitigated"..resource.."PseudoRecoup"], s_format("= %.1f%% over %d seconds", output["PhysicalDamageMitigated"..resource.."PseudoRecoup"], output["PhysicalDamageMitigated"..resource.."PseudoRecoupDuration"])) + end + end + end + end end -- Ward recharge @@ -2497,6 +2527,8 @@ function calcs.buildDefenceEstimations(env, actor) if output["anyRecoup"] > 0 then local totalDamage = 0 local totalElementalDamage = 0 + local totalPhysicalDamageMitigated = output["NumberOfMitigatedDamagingHits"] * (output.PhysicalTakenDamage - output.PhysicalTakenHit) + local extraPseudoRecoup = {} for _, damageType in ipairs(dmgTypeList) do totalDamage = totalDamage + output[damageType.."PoolLost"] if isElemental[damageType] then @@ -2504,7 +2536,7 @@ function calcs.buildDefenceEstimations(env, actor) end end local recoupTypeList = {"Life", "Mana", "EnergyShield"} - for _, recoupType in ipairs(recoupTypeList) do + for i, recoupType in ipairs(recoupTypeList) do local recoupTime = (modDB:Flag(nil, "3Second"..recoupType.."Recoup") or modDB:Flag(nil, "3SecondRecoup")) and 3 or 4 output["Total"..recoupType.."RecoupRecovery"] = (output[recoupType.."Recoup"] or 0) / 100 * totalDamage if (output["Elemental"..recoupType.."Recoup"] or 0) > 0 and totalElementalDamage > 0 then @@ -2515,8 +2547,19 @@ function calcs.buildDefenceEstimations(env, actor) output["Total"..recoupType.."RecoupRecovery"] = output["Total"..recoupType.."RecoupRecovery"] + output[damageType..recoupType.."Recoup"] / 100 * output[damageType.."PoolLost"] end end - output[recoupType.."RecoupRecoveryMax"] = output["Total"..recoupType.."RecoupRecovery"] / recoupTime - output[recoupType.."RecoupRecoveryAvg"] = output["Total"..recoupType.."RecoupRecovery"] / (output["EHPsurvivalTime"] + recoupTime) + output["Total"..recoupType.."PseudoRecoup"] = (output["PhysicalDamageMitigated"..recoupType.."PseudoRecoup"] or 0) / 100 * totalPhysicalDamageMitigated + local PseudoRecoupDuration = (output["PhysicalDamageMitigated"..recoupType.."PseudoRecoupDuration"] or 4) + -- Pious Path + if output["Total"..recoupType.."PseudoRecoup"] ~= 0 then + for j=i+1,#recoupTypeList do + if modDB:Flag(nil, recoupType.."RegenerationRecovers"..recoupTypeList[j]) and not modDB:Flag(nil, "UnaffectedBy"..recoupTypeList[j].."Regen") and not modDB:Flag(nil, "No"..recoupTypeList[j].."Regen") and not modDB:Flag(nil, "CannotGain"..recoupTypeList[j]) then + extraPseudoRecoup[recoupTypeList[j]] = { output["Total"..recoupType.."PseudoRecoup"] * output[recoupTypeList[j].."RecoveryRateMod"] / output[recoupType.."RecoveryRateMod"], PseudoRecoupDuration } + end + end + end + output["Total"..recoupType.."PseudoRecoup"] = ((not modDB:Flag(nil, "UnaffectedBy"..recoupType.."Regen")) and output["Total"..recoupType.."PseudoRecoup"] or 0) + output[recoupType.."RecoupRecoveryMax"] = output["Total"..recoupType.."RecoupRecovery"] / recoupTime + output["Total"..recoupType.."PseudoRecoup"] / PseudoRecoupDuration + (extraPseudoRecoup[recoupType] and (extraPseudoRecoup[recoupType][1] / extraPseudoRecoup[recoupType][2]) or 0) + output[recoupType.."RecoupRecoveryAvg"] = output["Total"..recoupType.."RecoupRecovery"] / (output["EHPsurvivalTime"] + recoupTime) + output["Total"..recoupType.."PseudoRecoup"] / (output["EHPsurvivalTime"] + PseudoRecoupDuration) + (extraPseudoRecoup[recoupType] and (extraPseudoRecoup[recoupType][1] / (output["EHPsurvivalTime"] + extraPseudoRecoup[recoupType][2])) or 0) if breakdown then local multipleTypes = 0 breakdown[recoupType.."RecoupRecoveryMax"] = { } @@ -2546,8 +2589,24 @@ function calcs.buildDefenceEstimations(env, actor) t_insert(breakdown[recoupType.."RecoupRecoveryMax"], s_format("= %d ^8(total damage recoup amount)", output["Total"..recoupType.."RecoupRecovery"])) breakdown[recoupType.."RecoupRecoveryAvg"] = copyTable(breakdown[recoupType.."RecoupRecoveryMax"]) t_insert(breakdown[recoupType.."RecoupRecoveryMax"], s_format("/ %.2f ^8(over %d seconds)", recoupTime, recoupTime)) + if output["Total"..recoupType.."PseudoRecoup"] > 0 then + t_insert(breakdown[recoupType.."RecoupRecoveryMax"], s_format("+ %.2f ^8(total damage mitigated pseudo recoup amount)", output["Total"..recoupType.."PseudoRecoup"])) + t_insert(breakdown[recoupType.."RecoupRecoveryMax"], s_format("/ %.2f ^8(over %d seconds)", PseudoRecoupDuration, PseudoRecoupDuration)) + end + if extraPseudoRecoup[recoupType] then + t_insert(breakdown[recoupType.."RecoupRecoveryMax"], s_format("+ %.2f ^8(total damage mitigated pseudo recoup amount)", extraPseudoRecoup[recoupType][1])) + t_insert(breakdown[recoupType.."RecoupRecoveryMax"], s_format("/ %.2f ^8(over %d seconds)", extraPseudoRecoup[recoupType][2], extraPseudoRecoup[recoupType][2])) + end t_insert(breakdown[recoupType.."RecoupRecoveryMax"], s_format("= %.2f per second ^8", output[recoupType.."RecoupRecoveryMax"])) t_insert(breakdown[recoupType.."RecoupRecoveryAvg"], s_format("/ %.2f ^8(total time of the recoup (survival time + %d seconds))", (output["EHPsurvivalTime"] + recoupTime), recoupTime)) + if output["Total"..recoupType.."PseudoRecoup"] > 0 then + t_insert(breakdown[recoupType.."RecoupRecoveryAvg"], s_format("+ %.2f ^8(total damage mitigated pseudo recoup amount)", output["Total"..recoupType.."PseudoRecoup"])) + t_insert(breakdown[recoupType.."RecoupRecoveryAvg"], s_format("/ %.2f ^8(total time of the recoup (survival time + %d seconds)", (output["EHPsurvivalTime"] + PseudoRecoupDuration), PseudoRecoupDuration)) + end + if extraPseudoRecoup[recoupType] then + t_insert(breakdown[recoupType.."RecoupRecoveryAvg"], s_format("+ %.2f ^8(total damage mitigated pseudo recoup amount)", extraPseudoRecoup[recoupType][1])) + t_insert(breakdown[recoupType.."RecoupRecoveryAvg"], s_format("/ %.2f ^8(total time of the recoup (survival time + %d seconds)", (output["EHPsurvivalTime"] + extraPseudoRecoup[recoupType][2]), extraPseudoRecoup[recoupType][2])) + end t_insert(breakdown[recoupType.."RecoupRecoveryAvg"], s_format("= %.2f per second ^8", output[recoupType.."RecoupRecoveryAvg"])) end end diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index adb91e316e..4d155e5135 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -1384,6 +1384,12 @@ return { { label = "Recovery modifiers", modName = "LifeRecoveryRate" }, { label = "FasterRecoup", modName = { "3SecondRecoup", "3SecondLifeRecoup" } }, }, }, + { label = "Dmg. Mit. Regen", haveOutput = "PhysicalDamageMitigatedLifePseudoRecoup", { format = "{1:output:PhysicalDamageMitigatedLifePseudoRecoup}%", { breakdown = "PhysicalDamageMitigatedLifePseudoRecoup" }, + { label = "Sources", modName = "PhysicalDamageMitigatedLifePseudoRecoup" }, + { label = "Increased Life Regeneration Rate", modName = { "LifeRegen" }, modType = "INC" }, + { label = "More Life Regeneration Rate", modName = { "LifeRegen" }, modType = "MORE" }, + { label = "Recovery modifiers", modName = "LifeRecoveryRate" }, + }, }, } } } }, { 1, "Mana", 2, colorCodes.MANA, {{ defaultCollapsed = false, label = "Mana", data = { @@ -1444,6 +1450,12 @@ return { { label = "Recovery modifiers", modName = "EnergyShieldRecoveryRate" }, { label = "FasterRecoup", modName = "3SecondRecoup" }, }, }, + { label = "Dmg. Mit. Regen", haveOutput = "PhysicalDamageMitigatedEnergyShieldPseudoRecoup", { format = "{1:output:PhysicalDamageMitigatedEnergyShieldPseudoRecoup}%", { breakdown = "PhysicalDamageMitigatedEnergyShieldPseudoRecoup" }, + { label = "Sources", modName = "PhysicalDamageMitigatedEnergyShieldPseudoRecoup" }, + { label = "Increased Energy Shield Regeneration Rate", modName = { "EnergyShieldRegen" }, modType = "INC" }, + { label = "More Energy Shield Regeneration Rate", modName = { "EnergyShieldRegen" }, modType = "MORE" }, + { label = "Recovery modifiers", modName = "EnergyShieldRecoveryRate" }, + }, }, } } } }, { 1, "Ward", 2, colorCodes.WARD, {{ defaultCollapsed = false, label = "Ward", data = { @@ -2136,7 +2148,7 @@ return { { label = "Recoup Max.", haveOutput = "anyRecoup", { format = "{0:output:LifeRecoupRecoveryMax}", { breakdown = "LifeRecoupRecoveryMax" }, - { label = "Sources", modName = { "LifeRecoup", "PhysicalLifeRecoup", "LightningLifeRecoup", "ColdLifeRecoup", "FireLifeRecoup", "ChaosLifeRecoup" } }, + { label = "Sources", modName = { "LifeRecoup", "PhysicalLifeRecoup", "LightningLifeRecoup", "ColdLifeRecoup", "FireLifeRecoup", "ChaosLifeRecoup", "PhysicalDamageMitigatedLifePseudoRecoup" } }, { label = "Recovery modifiers", modName = "LifeRecoveryRate" }, { label = "Faster Recoup", modName = "3SecondRecoup" }, }, @@ -2148,7 +2160,7 @@ return { }, { format = "{0:output:EnergyShieldRecoupRecoveryMax}", { breakdown = "EnergyShieldRecoupRecoveryMax" }, - { label = "Sources", modName = { "EnergyShieldRecoup", "ElementalEnergyShieldRecoup" } }, + { label = "Sources", modName = { "EnergyShieldRecoup", "ElementalEnergyShieldRecoup", "PhysicalDamageMitigatedEnergyShieldPseudoRecoup" } }, { label = "Recovery modifiers", modName = "EnergyShieldRecoveryRate" }, { label = "Faster Recoup", modName = "3SecondRecoup" }, }, @@ -2156,7 +2168,7 @@ return { { label = "Recoup Avg.", haveOutput = "anyRecoup", { format = "{0:output:LifeRecoupRecoveryAvg}", { breakdown = "LifeRecoupRecoveryAvg" }, - { label = "Sources", modName = { "LifeRecoup", "PhysicalLifeRecoup", "LightningLifeRecoup", "ColdLifeRecoup", "FireLifeRecoup", "ChaosLifeRecoup" } }, + { label = "Sources", modName = { "LifeRecoup", "PhysicalLifeRecoup", "LightningLifeRecoup", "ColdLifeRecoup", "FireLifeRecoup", "ChaosLifeRecoup", "PhysicalDamageMitigatedLifePseudoRecoup" } }, { label = "Recovery modifiers", modName = "LifeRecoveryRate" }, { label = "Faster Recoup", modName = "3SecondRecoup" }, }, @@ -2168,7 +2180,7 @@ return { }, { format = "{0:output:EnergyShieldRecoupRecoveryAvg}", { breakdown = "EnergyShieldRecoupRecoveryAvg" }, - { label = "Sources", modName = { "EnergyShieldRecoup", "ElementalEnergyShieldRecoup" } }, + { label = "Sources", modName = { "EnergyShieldRecoup", "ElementalEnergyShieldRecoup", "PhysicalDamageMitigatedEnergyShieldPseudoRecoup" } }, { label = "Recovery modifiers", modName = "EnergyShieldRecoveryRate" }, { label = "Faster Recoup", modName = "3SecondRecoup" }, }, diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 6f8dfe65f1..ba39780ef3 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -3880,6 +3880,11 @@ local specialModList = { ["(%d+)%% of damage taken while affected by clarity recouped as mana"] = function(num) return { mod("ManaRecoup", "BASE", num, { type = "Condition", var = "AffectedByClarity" }) } end, ["recoup effects instead occur over 3 seconds"] = { flag("3SecondRecoup") }, ["life recoup effects instead occur over 3 seconds"] = { flag("3SecondLifeRecoup") }, + ["([%d%.]+)%% of physical damage prevented from hits in the past (%d+) seconds is regenerated as life per second"] = function(num, _, duration) return { + mod("PhysicalDamageMitigatedLifePseudoRecoup", "BASE", num * duration), + mod("PhysicalDamageMitigatedLifePseudoRecoupDuration", "BASE", duration), + } end, + ["([%d%.]+)%% of physical damage prevented from hits recently is regenerated as energy shield per second"] = function(num) return { mod("PhysicalDamageMitigatedEnergyShieldPseudoRecoup", "BASE", num * 4) } end, ["cannot leech or regenerate mana"] = { flag("NoManaRegen"), flag("CannotLeechMana") }, ["right ring slot: you cannot regenerate mana" ] = { flag("NoManaRegen", { type = "SlotNumber", num = 2 }) }, ["y?o?u? ?cannot recharge energy shield"] = { flag("NoEnergyShieldRecharge") }, From aee54a59619b2ddd4b76a1ed03c2c3b46a90d428 Mon Sep 17 00:00:00 2001 From: Regisle Date: Thu, 19 Oct 2023 11:09:00 +1030 Subject: [PATCH 2/2] fix spelling --- src/Modules/CalcDefence.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index d0037468f9..67bf0c20de 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -1142,7 +1142,7 @@ function calcs.defence(env, actor) end end - -- pseudo recoup (eg %physicial damage prevented from hits regenerated) + -- pseudo recoup (eg %physical damage prevented from hits regenerated) for _, resource in ipairs(recoupTypeList) do if not modDB:Flag(nil, "No"..resource.."Regen") and not modDB:Flag(nil, "CannotGain"..resource) then local PhysicalDamageMitigatedPseudoRecoup = modDB:Sum("BASE", nil, "PhysicalDamageMitigated"..resource.."PseudoRecoup")