From 411385a68d120afa39666a087decfd1369215b5a Mon Sep 17 00:00:00 2001 From: LocalIdentity <31035929+LocalIdentity@users.noreply.github.com> Date: Thu, 13 Aug 2026 12:16:26 +1000 Subject: [PATCH] Fix some mods not checking payable cost Some mods that grant damage only if you can pay the added cost of the mod were universally applying instead of checking that you actually had the resource available to pay it. Their `PercentStat` tags also rounded damage up instead of rounding down --- spec/System/TestSkills_spec.lua | 32 ++++++++++++++++++++++++++++++++ src/Data/ModCache.lua | 2 +- src/Modules/CalcOffence.lua | 2 ++ src/Modules/ModParser.lua | 20 ++++++++++---------- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/spec/System/TestSkills_spec.lua b/spec/System/TestSkills_spec.lua index af8896f64c..44427ceb8d 100644 --- a/spec/System/TestSkills_spec.lua +++ b/spec/System/TestSkills_spec.lua @@ -392,6 +392,38 @@ describe("TestSkills", function() -- 12 / 1.5 + 10 = 18 assert.equals(18, build.calcsTab.mainOutput.ESCost) end) + + it("only grants payable cost damage when the full cost can be paid", function() + build.skillsTab:PasteSocketGroup("Fireball 1/0 1\n") + build.configTab.input.customMods = "Skills gain Added Chaos Damage equal to 25% of Mana Cost, if Mana Cost is not higher than the maximum you could spend" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(5, build.calcsTab.mainOutput.ManaCost) + assert.are.equals(1, build.calcsTab.mainEnv.player.mainSkill.skillModList:Sum("BASE", build.calcsTab.mainEnv.player.mainSkill.skillCfg, "ChaosMin")) + + build.configTab.input.customMods = build.configTab.input.customMods .. "\n-10000 to maximum Mana" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(0, build.calcsTab.mainEnv.player.mainSkill.skillModList:Sum("BASE", build.calcsTab.mainEnv.player.mainSkill.skillCfg, "ChaosMin")) + + build.configTab.input.customMods = build.configTab.input.customMods .. "\nEnergy Shield protects Mana instead of Life\n+100 to maximum Energy Shield" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(1, build.calcsTab.mainEnv.player.mainSkill.skillModList:Sum("BASE", build.calcsTab.mainEnv.player.mainSkill.skillCfg, "ChaosMin")) + end) + + it("checks life-cost damage against the full life cost", function() + build.skillsTab:PasteSocketGroup("Fireball 1/0 1\n") + build.configTab.input.customMods = "Skills Cost Life instead of Mana\nSkills gain Added Chaos Damage equal to 25% of Life Cost, if Life Cost is not higher than the maximum you could spend\n-10000 to maximum Life" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(5, build.calcsTab.mainOutput.LifeCost) + assert.are.equals(0, build.calcsTab.mainEnv.player.mainSkill.skillModList:Sum("BASE", build.calcsTab.mainEnv.player.mainSkill.skillCfg, "ChaosMin")) + end) it("Test mana cost efficiency with support gems", function() -- Test interaction between cost efficiency and cost multipliers build.skillsTab:PasteSocketGroup("Contagion 6/0 1\nMagnified Area I 1/0 1") diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index 28da845876..d520bdf482 100755 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -11531,7 +11531,7 @@ c["Skills fire an additional Projectile if 6 Hunter Items are Equipped"]={{[1]={ c["Skills from Equipped Body Armour are Supported by Level 20 Fist of War"]={{[1]={[1]={slotName="Body Armour",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={level=20,skillId="SupportFistofWar"}}},nil} c["Skills from Equipped Body Armour are Supported by Level 30 Ancestral Call"]={{[1]={[1]={slotName="Body Armour",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={level=30,skillId="SupportAncestralCall"}}},nil} c["Skills from Equipped Main Hand Weapon are supported by level 1 Cruelty"]={{[1]={[1]={slotName="Weapon 1",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={level=1,skillId="SupportCruelty"}}},nil} -c["Skills gain Added Chaos Damage equal to 25% of Life Cost, if Life Cost is not higher than the maximum you could spend"]={{[1]={[1]={percent=25,stat="LifeCost",type="PercentStat"},[2]={stat="LifeUnreserved",thresholdPercent=25,thresholdStat="LifeCost",type="StatThreshold"},flags=0,keywordFlags=0,name="ChaosMin",type="BASE",value=1},[2]={[1]={percent=25,stat="LifeCost",type="PercentStat"},[2]={stat="LifeUnreserved",thresholdPercent=25,thresholdStat="LifeCost",type="StatThreshold"},flags=0,keywordFlags=0,name="ChaosMax",type="BASE",value=1}},nil} +c["Skills gain Added Chaos Damage equal to 25% of Life Cost, if Life Cost is not higher than the maximum you could spend"]={{[1]={[1]={floor=true,percent=25,stat="LifeCost",type="PercentStat"},[2]={stat="LifeUnreserved",thresholdStat="LifeCost",type="StatThreshold"},flags=0,keywordFlags=0,name="ChaosMin",type="BASE",value=1},[2]={[1]={floor=true,percent=25,stat="LifeCost",type="PercentStat"},[2]={stat="LifeUnreserved",thresholdStat="LifeCost",type="StatThreshold"},flags=0,keywordFlags=0,name="ChaosMax",type="BASE",value=1}},nil} c["Skills gain a Base Energy Shield Cost equal to 200% of Base Mana Cost"]={{[1]={flags=0,keywordFlags=0,name="ManaCostAsEnergyShieldCost",type="BASE",value=200}},nil} c["Skills gain a Base Life Cost equal to 100% of Base Mana Cost"]={{[1]={flags=0,keywordFlags=0,name="ManaCostAsLifeCost",type="BASE",value=100}},nil} c["Skills supported by Unleash have +1 to maximum number of Seals"]={{[1]={flags=0,keywordFlags=0,name="SealCount",type="BASE",value=1}},nil} diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 3fd3f028e3..4ba634d1ba 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -1837,6 +1837,8 @@ function calcs.offence(env, actor, activeSkill) end end end + -- Eldritch Battery adds maximum Energy Shield to the Mana available for payable-cost damage. + output.ManaCostPayablePool = (output.ManaUnreserved or 0) + (modDB:Flag(nil, "EnergyShieldProtectsMana") and output.EnergyShield or 0) -- account for Sacrificial Zeal -- Note: Sacrificial Zeal grants Added Spell Physical Damage equal to 25% of the Skill's Mana Cost, and causes you to take Physical Damage over Time, for 4 seconds diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 0b582014d4..4b31c51725 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -3045,8 +3045,8 @@ local specialModList = { ["(%d+)%% increased movement speed if you have equipped boots with no socketed gems"] = function(num) return { mod("MovementSpeed", "INC", num, { type = "MultiplierThreshold", var = "SocketedGemsInBoots", threshold = 0, upper = true}, { type = "Condition", var = "UsingBoots" }) } end, -- Warlock ["spells you cast yourself gain added physical damage equal to (%d+)%% of life cost, if life cost is not higher than the maximum you could spend"] = function(num) return { - mod("PhysicalMin", "BASE", 1, { type = "PercentStat", stat = "LifeCost", percent = num }, { type = "StatThreshold", stat = "LifeUnreserved", thresholdStat = "LifeCost", thresholdPercent = num }), - mod("PhysicalMax", "BASE", 1, { type = "PercentStat", stat = "LifeCost", percent = num }, { type = "StatThreshold", stat = "LifeUnreserved", thresholdStat = "LifeCost", thresholdPercent = num }), + mod("PhysicalMin", "BASE", 1, { type = "PercentStat", stat = "LifeCost", percent = num, floor = true }, { type = "StatThreshold", stat = "LifeUnreserved", thresholdStat = "LifeCost" }), + mod("PhysicalMax", "BASE", 1, { type = "PercentStat", stat = "LifeCost", percent = num, floor = true }, { type = "StatThreshold", stat = "LifeUnreserved", thresholdStat = "LifeCost" }), } end, ["gain maximum life instead of maximum energy shield from equipped armour items"] = { flag("ConvertArmourESToLife") }, -- Ritualist Bloodline @@ -3075,8 +3075,8 @@ local specialModList = { -- Oshabi Bloodline ["unsealed spells gain (%d+)%% more damage each time their effects reoccur"] = function(num) return { mod("MaxSealDamage", "MORE", num) } end, ["skills gain added chaos damage equal to (%d+)%% of life cost, if life cost is not higher than the maximum you could spend"] = function(num) return { - mod("ChaosMin", "BASE", 1, { type = "PercentStat", stat = "LifeCost", percent = num }, { type = "StatThreshold", stat = "LifeUnreserved", thresholdStat = "LifeCost", thresholdPercent = num }), - mod("ChaosMax", "BASE", 1, { type = "PercentStat", stat = "LifeCost", percent = num }, { type = "StatThreshold", stat = "LifeUnreserved", thresholdStat = "LifeCost", thresholdPercent = num }), + mod("ChaosMin", "BASE", 1, { type = "PercentStat", stat = "LifeCost", percent = num, floor = true }, { type = "StatThreshold", stat = "LifeUnreserved", thresholdStat = "LifeCost" }), + mod("ChaosMax", "BASE", 1, { type = "PercentStat", stat = "LifeCost", percent = num, floor = true }, { type = "StatThreshold", stat = "LifeUnreserved", thresholdStat = "LifeCost" }), } end, ["lose all rage on reaching maximum rage and gain wild savagery for 1 second per 10 rage lost this way"] = { flag("WildSavagery") }, -- Velka Bloodline @@ -5583,16 +5583,16 @@ local specialModList = { mod("LightningMax", "BASE", 1, nil, ModFlag.Attack, { type = "PercentStat", stat = "Mana", percent = num }), } end, ["arc and crackling lance gains added cold damage equal to (%d+)%% of mana cost, if mana cost is not higher than the maximum you could spend"] = function(num) return { - mod("ColdMin", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num }, { type = "SkillName", skillNameList = { "Arc", "Crackling Lance" }, includeTransfigured = true }), - mod("ColdMax", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num }, { type = "SkillName", skillNameList = { "Arc", "Crackling Lance" }, includeTransfigured = true }), + mod("ColdMin", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num, floor = true }, { type = "StatThreshold", stat = "ManaCostPayablePool", thresholdStat = "ManaCost" }, { type = "SkillName", skillNameList = { "Arc", "Crackling Lance" }, includeTransfigured = true }), + mod("ColdMax", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num, floor = true }, { type = "StatThreshold", stat = "ManaCostPayablePool", thresholdStat = "ManaCost" }, { type = "SkillName", skillNameList = { "Arc", "Crackling Lance" }, includeTransfigured = true }), } end, ["forbidden rite and dark pact gains added chaos damage equal to (%d+)%% of mana cost, if mana cost is not higher than the maximum you could spend"] = function(num) return { - mod("ChaosMin", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num }, { type = "SkillName", skillNameList = { "Forbidden Rite", "Dark Bargain" }, includeTransfigured = true }), - mod("ChaosMax", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num }, { type = "SkillName", skillNameList = { "Forbidden Rite", "Dark Bargain" }, includeTransfigured = true }), + mod("ChaosMin", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num, floor = true }, { type = "StatThreshold", stat = "ManaCostPayablePool", thresholdStat = "ManaCost" }, { type = "SkillName", skillNameList = { "Forbidden Rite", "Dark Bargain" }, includeTransfigured = true }), + mod("ChaosMax", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num, floor = true }, { type = "StatThreshold", stat = "ManaCostPayablePool", thresholdStat = "ManaCost" }, { type = "SkillName", skillNameList = { "Forbidden Rite", "Dark Bargain" }, includeTransfigured = true }), } end, ["skills gain added chaos damage equal to (%d+)%% of mana cost, if mana cost is not higher than the maximum you could spend"] = function(num) return { - mod("ChaosMin", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num }), - mod("ChaosMax", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num }), + mod("ChaosMin", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num, floor = true }, { type = "StatThreshold", stat = "ManaCostPayablePool", thresholdStat = "ManaCost" }), + mod("ChaosMax", "BASE", 1, { type = "PercentStat", stat = "ManaCost", percent = num, floor = true }, { type = "StatThreshold", stat = "ManaCostPayablePool", thresholdStat = "ManaCost" }), } end, ["herald of thunder's storms hit enemies with (%d+)%% increased frequency"] = function(num) return { mod("HeraldStormFrequency", "INC", num), } end, ["storms hit enemies with (%d+)%% increased frequency"] = function(num) return { mod("HeraldStormFrequency", "INC", num), } end,