Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions spec/System/TestSkills_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,66 @@ describe("TestAttacks", function()

assert.True(preAdrenalineMaxStages < build.calcsTab.mainEnv.player.activeSkillList[1].skillModList:Sum("BASE", nil, "Multiplier:BlightMaxStages"))
end)
it("Test cost efficiency modifiers", function()
-- Test Mana Cost Efficiency
build.skillsTab:PasteSocketGroup("Ball Lightning 1/0 1\n")
runCallback("OnFrame")

-- Get base mana cost (Ball Lightning level 1 has 12 mana cost)
local baseCost = build.calcsTab.mainOutput.ManaCost
assert.are.equals(12, baseCost)

-- Add 50% mana cost efficiency (should reduce cost to 12/1.5 = 8)
build.configTab.input.customMods = "50% increased Mana Cost Efficiency"
build.configTab:BuildModList()
runCallback("OnFrame")

local reducedCost = build.calcsTab.mainOutput.ManaCost
assert.are.equals(8, reducedCost)

-- Test generic cost efficiency (should also affect mana)
newBuild()
build.skillsTab:PasteSocketGroup("Ball Lightning 1/0 1\n")
build.configTab.input.customMods = "25% increased Cost Efficiency"
build.configTab:BuildModList()
runCallback("OnFrame")

local genericEfficiencyCost = build.calcsTab.mainOutput.ManaCost
-- Test actual behavior: 12/1.25 = 9.6 (not rounded)
assert.True(math.abs(genericEfficiencyCost - 9.6) < 0.001)

-- Test multiple efficiency sources stacking additively
build.configTab.input.customMods = "25% increased Cost Efficiency\n25% increased Mana Cost Efficiency"
build.configTab:BuildModList()
runCallback("OnFrame")

local stackedCost = build.calcsTab.mainOutput.ManaCost
assert.are.equals(8, stackedCost) -- 12/(1 + 0.25 + 0.25) = 12/1.5 = 8
end)

it("Test cost efficiency with cost modifiers", function()
-- Test interaction between cost efficiency and cost multipliers
build.skillsTab:PasteSocketGroup("Ball Lightning 1/0 1\n")

-- Add cost multiplier and efficiency
build.configTab.input.customMods = "50% increased Mana Cost\n50% increased Mana Cost Efficiency"
build.configTab:BuildModList()
runCallback("OnFrame")

local finalCost = build.calcsTab.mainOutput.ManaCost
assert.True(math.abs(finalCost - 12) < 0.1) -- floor(12 * 1.5) / 1.5
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")

-- Add efficiency
build.configTab.input.customMods = "36% increased Mana Cost Efficiency"
build.configTab:BuildModList()
runCallback("OnFrame")

local finalCost = build.calcsTab.mainOutput.ManaCost
assert.are.equals(7, round(finalCost))
end)
end)
12 changes: 10 additions & 2 deletions src/Modules/CalcOffence.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1747,12 +1747,13 @@ function calcs.offence(env, actor, activeSkill)
local moreType = 1
local moreCost = 1
local inc = 0
local costEfficiency = calcLib.mod(skillModList, skillCfg, val.type .. "CostEfficiency", "CostEfficiency")
if not val.unaffectedByGenericCostMults then
output[costName] = val.finalBaseCost
moreType = skillModList:More(skillCfg, val.type.."Cost")
moreCost = skillModList:More(skillCfg, "Cost")
inc = skillModList:Sum("INC", skillCfg, val.type.."Cost", "Cost")
output[costNameRaw] = val.baseCostRaw and m_max(0, m_max(0, (1 + inc / 100) * val.baseCostRaw * moreType * moreCost) + val.totalCost)
output[costNameRaw] = val.baseCostRaw and m_max(0, m_max(0, (1 + inc / 100) * val.baseCostRaw * moreType * moreCost / costEfficiency) + val.totalCost)
if inc < 0 then
output[costName] = m_max(0, m_ceil((1 + inc / 100) * output[costName]))
else
Expand All @@ -1768,6 +1769,8 @@ function calcs.offence(env, actor, activeSkill)
else
output[costName] = m_max(0, m_floor(moreCost * output[costName]))
end
-- Apply cost efficiency (similar to reservation efficiency)
output[costName] = m_max(0, output[costName] / costEfficiency)
output[costName] = m_max(0, output[costName] + val.totalCost)
if val.type == "Mana" and hybridLifeCost > 0 then -- Life/Mana Mastery
output[costName] = m_max(0, m_floor((1 - hybridLifeCost) * output[costName]))
Expand All @@ -1779,8 +1782,10 @@ function calcs.offence(env, actor, activeSkill)
output[costName] = m_floor(val.baseCost + val.baseCostNoMult)
output[costName] = m_max(0, (1 + inc / 100) * output[costName])
output[costName] = m_max(0, moreType * output[costName])
-- Apply cost efficiency for unaffected costs too
output[costName] = m_max(0, output[costName] / costEfficiency)
output[costName] = m_max(0, output[costName] + val.totalCost)
output[costNameRaw] = val.baseCostRaw and m_max(0, m_max(0, (1 + inc / 100) * (val.baseCostRaw + val.baseCostNoMult) * moreType) + val.totalCost)
output[costNameRaw] = val.baseCostRaw and m_max(0, m_max(0, (1 + inc / 100) * (val.baseCostRaw + val.baseCostNoMult) * moreType / costEfficiency) + val.totalCost)
end
if breakdown and hasCost then
breakdown[costName] = {
Expand All @@ -1807,6 +1812,9 @@ function calcs.offence(env, actor, activeSkill)
if moreType ~= 1 then
t_insert(breakdown[costName], s_format("x %.2f ^8(more/less "..val.text.." cost)", moreType))
end
if costEfficiency ~= 1 then
t_insert(breakdown[costName], s_format("/ %.2f ^8(" .. val.text .. " cost efficiency)", costEfficiency))
end
if val.totalCost ~= 0 then
t_insert(breakdown[costName], s_format("%+d ^8(total "..val.text.." cost)", val.totalCost))
end
Expand Down
2 changes: 1 addition & 1 deletion src/Modules/CalcPerform.lua
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ local function doActorMisc(env, actor)
if modDB:Flag(nil, "Fanaticism") and actor.mainSkill and actor.mainSkill.skillFlags.selfCast then
local effect = m_floor(75 * (1 + modDB:Sum("INC", nil, "BuffEffectOnSelf") / 100))
modDB:NewMod("Speed", "MORE", effect, "Fanaticism", ModFlag.Cast)
modDB:NewMod("Cost", "INC", -effect, "Fanaticism", ModFlag.Cast)
modDB:NewMod("Cost", "MORE", -effect, "Fanaticism", ModFlag.Cast)
modDB:NewMod("AreaOfEffect", "INC", effect, "Fanaticism", ModFlag.Cast)
end
if modDB:Flag(nil, "UnholyMight") then
Expand Down
22 changes: 22 additions & 0 deletions src/Modules/ModParser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,27 @@ local modNameList = {
["cost of skills"] = "Cost",
["cost of attacks"] = { "Cost", tag = { type = "SkillType", skillType = SkillType.Attack } },
["cost of retaliation skills"] = { "Cost", tag = { type = "SkillType", skillType = SkillType.Retaliation } },
-- Cost efficiency
["cost efficiency"] = "CostEfficiency",
["cost efficiency of skills"] = "CostEfficiency",
["cost efficiency of attacks"] = { "CostEfficiency", tag = { type = "SkillType", skillType = SkillType.Attack } },
["cost efficiency of spells"] = { "CostEfficiency", tag = { type = "SkillType", skillType = SkillType.Spell } },
["mana cost efficiency"] = "ManaCostEfficiency",
["mana cost efficiency of skills"] = "ManaCostEfficiency",
["mana cost efficiency of attacks"] = { "ManaCostEfficiency", tag = { type = "SkillType", skillType = SkillType.Attack } },
["mana cost efficiency of spells"] = { "ManaCostEfficiency", tag = { type = "SkillType", skillType = SkillType.Spell } },
["life cost efficiency"] = "LifeCostEfficiency",
["life cost efficiency of skills"] = "LifeCostEfficiency",
["life cost efficiency of attacks"] = { "LifeCostEfficiency", tag = { type = "SkillType", skillType = SkillType.Attack } },
["life cost efficiency of spells"] = { "LifeCostEfficiency", tag = { type = "SkillType", skillType = SkillType.Spell } },
["energy shield cost efficiency"] = "ESCostEfficiency",
["energy shield cost efficiency of skills"] = "ESCostEfficiency",
["es cost efficiency"] = "ESCostEfficiency",
["es cost efficiency of skills"] = "ESCostEfficiency",
["soul cost efficiency"] = "SoulCostEfficiency",
["soul cost efficiency of skills"] = "SoulCostEfficiency",
["rage cost efficiency"] = "RageCostEfficiency",
["rage cost efficiency of skills"] = "RageCostEfficiency",
["mana reserved"] = "ManaReserved",
["mana reservation"] = "ManaReserved",
["mana reservation of skills"] = { "ManaReserved", tag = { type = "SkillType", skillType = SkillType.Aura } },
Expand Down Expand Up @@ -1293,6 +1314,7 @@ local modTagList = {
["per siphoning charge"] = { tag = { type = "Multiplier", var = "SiphoningCharge" } },
["per spirit charge"] = { tag = { type = "Multiplier", var = "SpiritCharge" } },
["per challenger charge"] = { tag = { type = "Multiplier", var = "ChallengerCharge" } },
["per maximum power charge"] = { tag = { type = "Multiplier", var = "PowerChargeMax" } },
["per gale force"] = { tag = { type = "Multiplier", var = "GaleForce" } },
["per intensity"] = { tag = { type = "Multiplier", var = "Intensity" } },
["per brand"] = { tag = { type = "Multiplier", var = "ActiveBrand" } },
Expand Down
Loading