From 310b99327c470aab072516485f1b22799a86b744 Mon Sep 17 00:00:00 2001 From: LocalIdentity <31035929+LocalIdentity@users.noreply.github.com> Date: Thu, 13 Aug 2026 12:29:15 +1000 Subject: [PATCH] Convert positive late flat skill costs with their resource Fix added Total Mana cost when converting to Energy Shield or Life cost. For some reason the game can only add to the base cost but not subtract from it. So modifiers such as `Non-Channelling Skills have -7 to Total Mana Cost` do not reduce Blood Magic life cost but `Non-Channelling Skills have +7 to Total Mana Cost` would increase it. Added tests to cover multiple scenarios --- spec/System/TestSkills_spec.lua | 60 +++++++++++++++++++++++++++++++++ src/Modules/CalcOffence.lua | 16 +++++++++ 2 files changed, 76 insertions(+) diff --git a/spec/System/TestSkills_spec.lua b/spec/System/TestSkills_spec.lua index af8896f64c..db61b6ffa4 100644 --- a/spec/System/TestSkills_spec.lua +++ b/spec/System/TestSkills_spec.lua @@ -381,6 +381,46 @@ describe("TestSkills", function() assert.equals(18, build.calcsTab.mainOutput.LifeCost) end) + it("converts and rounds flat mana cost separately from base cost", function() + build.skillsTab:PasteSocketGroup("Hydrosphere 1/0 1\n") + build.configTab.input.customMods = "Skills Cost Life instead of 15% of Mana Cost\n+4 to Total Mana Cost" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.equals(3, build.calcsTab.mainOutput.LifeCost) + assert.equals(13, build.calcsTab.mainOutput.ManaCost) + end) + + it("moves flat mana cost when all costs are converted", function() + build.skillsTab:PasteSocketGroup("Hydrosphere 1/0 1\n") + build.configTab.input.customMods = "Skills Cost Life instead of Mana\n+4 to Total Mana Cost" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.equals(16, build.calcsTab.mainOutput.LifeCost) + assert.equals(0, build.calcsTab.mainOutput.ManaCost) + end) + + it("does not move reduced flat mana cost to life", function() + build.skillsTab:PasteSocketGroup("Hydrosphere 1/0 1\n") + build.configTab.input.customMods = "Skills Cost Life instead of Mana\nNon-Channelling Skills have -7 to Total Mana Cost" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.equals(12, build.calcsTab.mainOutput.LifeCost) + assert.equals(0, build.calcsTab.mainOutput.ManaCost) + end) + + it("does not partially convert reduced flat mana cost to life", function() + build.skillsTab:PasteSocketGroup("Hydrosphere 1/0 1\n") + build.configTab.input.customMods = "Skills Cost Life instead of 15% of Mana Cost\nNon-Channelling Skills have -7 to Total Mana Cost" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.equals(2, build.calcsTab.mainOutput.LifeCost) + assert.equals(4, build.calcsTab.mainOutput.ManaCost) + end) + it("Test flat cost is added after cost efficiency for energy shield costs", function() build.skillsTab:PasteSocketGroup("Hydrosphere 1/0 1\n") @@ -392,6 +432,26 @@ describe("TestSkills", function() -- 12 / 1.5 + 10 = 18 assert.equals(18, build.calcsTab.mainOutput.ESCost) end) + + it("moves flat mana cost to energy shield with the base cost", function() + build.skillsTab:PasteSocketGroup("Hydrosphere 1/0 1\n") + build.configTab.input.customMods = "Skills Cost Energy Shield instead of Mana or Life\n+4 to Total Mana Cost" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.equals(16, build.calcsTab.mainOutput.ESCost) + assert.equals(0, build.calcsTab.mainOutput.ManaCost) + end) + + it("does not move reduced flat mana cost to energy shield", function() + build.skillsTab:PasteSocketGroup("Hydrosphere 1/0 1\n") + build.configTab.input.customMods = "Skills Cost Energy Shield instead of Mana or Life\nNon-Channelling Skills have -7 to Total Mana Cost" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.equals(12, build.calcsTab.mainOutput.ESCost) + assert.equals(0, build.calcsTab.mainOutput.ManaCost) + 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/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 3fd3f028e3..68d6d21735 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -1707,6 +1707,11 @@ function calcs.offence(env, actor, activeSkill) if val.type == "Life" then local manaType = resource:gsub("Life", "Mana") if skillModList:Flag(skillCfg, "CostLifeInsteadOfMana") then -- Blood Magic / Lifetap + if val.upfront then + local manaTotalCost = skillModList:Sum("BASE", skillCfg, manaType.."Cost") + val.totalCost = val.totalCost + m_max(0, manaTotalCost) + costs[manaType].totalCost = costs[manaType].totalCost - manaTotalCost + end val.baseCost = val.baseCost + costs[manaType].baseCost val.baseCostNoMult = val.baseCostNoMult + costs[manaType].baseCostNoMult val.finalBaseCost = val.finalBaseCost + costs[manaType].finalBaseCost @@ -1717,11 +1722,22 @@ function calcs.offence(env, actor, activeSkill) elseif (additionalLifeCost > 0 or hybridLifeCost > 0) and not skillModList:Flag(skillCfg, "CostESInsteadOfManaOrLife") then val.baseCost = costs[manaType].baseCost val.finalBaseCost = val.finalBaseCost + round(costs[manaType].finalBaseCost * (hybridLifeCost + additionalLifeCost)) + if val.upfront and hybridLifeCost > 0 then + -- Only positive flat mana cost is converted, and it is rounded separately from base cost. + val.totalCost = val.totalCost + round(m_max(0, skillModList:Sum("BASE", skillCfg, manaType.."Cost")) * hybridLifeCost) + end end elseif val.type == "ES" then local manaType = resource:gsub("ES", "Mana") local lifeType = resource:gsub("ES", "Life") if skillModList:Flag(skillCfg, "CostESInsteadOfManaOrLife") then -- Whispers of Infinity + if val.upfront then + local manaTotalCost = skillModList:Sum("BASE", skillCfg, manaType.."Cost") + local lifeTotalCost = skillModList:Sum("BASE", skillCfg, lifeType.."Cost") + val.totalCost = val.totalCost + m_max(0, manaTotalCost) + m_max(0, lifeTotalCost) + costs[manaType].totalCost = costs[manaType].totalCost - manaTotalCost + costs[lifeType].totalCost = costs[lifeType].totalCost - lifeTotalCost + end val.baseCost = val.baseCost + costs[manaType].baseCost+ costs[lifeType].baseCost val.baseCostNoMult = val.baseCostNoMult + costs[manaType].baseCostNoMult + costs[lifeType].baseCostNoMult val.finalBaseCost = val.finalBaseCost + costs[manaType].finalBaseCost + costs[lifeType].finalBaseCost