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
18 changes: 17 additions & 1 deletion spec/System/TestSkills_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,22 @@ describe("TestAttacks", function()

assert.True(preAdrenalineMaxStages < build.calcsTab.mainEnv.player.activeSkillList[1].skillModList:Sum("BASE", nil, "Multiplier:BlightMaxStages"))
end)

it("averages inverted elemental resistance after penetration", function()
build.skillsTab:PasteSocketGroup("Fireball 20/0 1")
build.configTab.input.enemyIsBoss = "None"
build.configTab.input.enemyFireResist = 50
build.configTab.input.customMods = "Hits have 50% chance to treat Enemy Monster Elemental Resistance values as inverted\nDamage Penetrates 50% of Enemy Fire Resistance"
build.configTab:BuildModList()
runCallback("OnFrame")

-- Unlike PoE 2, PoE 1 penetration can lower resistance below zero:
-- 50% of hits use 0% resistance and 50% use -100% resistance.
assert.are.equals(1.5, build.calcsTab.calcsOutput.FireEffMult)
local breakdownText = table.concat(build.calcsTab.calcsEnv.player.breakdown.FireEffMult, "\n")
assert.is_truthy(breakdownText:match("inverted hit"))
assert.is_truthy(breakdownText:match("weighted average"))
end)
it("Test cost efficiency modifiers", function()
-- Test Mana Cost Efficiency
build.skillsTab:PasteSocketGroup("Ball Lightning 1/0 1\n")
Expand Down Expand Up @@ -212,4 +228,4 @@ describe("TestAttacks", function()
local finalCost = build.calcsTab.mainOutput.ManaCost
assert.are.equals(7, round(finalCost))
end)
end)
end)
17 changes: 11 additions & 6 deletions src/Modules/CalcBreakdown.lua
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,25 @@ function breakdown.area(base, areaMod, total, incBreakpoint, moreBreakpoint, red
return out
end

function breakdown.effMult(damageType, resist, pen, taken, mult, takenMore, sourceRes, useRes, invertChance)
function breakdown.effMult(damageType, resist, pen, taken, mult, takenMore, sourceRes, useRes, invertChance, effectiveResist)
local out = { }
local resistForm = (damageType == "Physical") and "physical damage reduction" or "resistance"
local resistLabel = resistForm
effectiveResist = effectiveResist or resist - pen

if invertChance and invertChance ~= 0 then
resistLabel = "average inverted "..resistForm
end
if sourceRes and sourceRes ~= damageType then
t_insert(out, s_format("Enemy %s: %d%% ^8(%s)", resistLabel, resist, sourceRes))
elseif resist ~= 0 then
t_insert(out, s_format("Enemy %s: %d%%", resistLabel, resist))
end
if pen ~= 0 or not useRes then
if invertChance and invertChance ~= 0 and useRes then
local normalResist = resist - pen
local invertedResist = -resist - pen
t_insert(out, "Effective resistance:")
t_insert(out, s_format("%g%% ^8(non-inverted hit after penetration)", normalResist))
t_insert(out, s_format("%g%% ^8(inverted hit after penetration)", invertedResist))
t_insert(out, s_format("= %g%% ^8(weighted average from %.0f%% inversion chance)", effectiveResist, invertChance * 100))
elseif pen ~= 0 or not useRes then
t_insert(out, "Effective resistance:")
t_insert(out, s_format("%d%% ^8(resistance)", resist))
if pen < 0 then
Expand All @@ -139,7 +144,7 @@ function breakdown.effMult(damageType, resist, pen, taken, mult, takenMore, sour
if useRes then
breakdown.multiChain(out, {
label = "Effective DPS modifier:",
{ "%.2f ^8(%s)", 1 - (resist - pen) / 100, resistForm },
{ "%.2f ^8(%s)", 1 - effectiveResist / 100, resistForm },
{ "%.2f ^8(increased/reduced damage taken)", 1 + taken / 100 },
{ "%.2f ^8(more/less damage taken)", takenMore },
total = s_format("= %.3f", mult),
Expand Down
28 changes: 14 additions & 14 deletions src/Modules/CalcOffence.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3367,14 +3367,8 @@ function calcs.offence(env, actor, activeSkill)
end
end
local invertChanceEle = m_max(m_min(skillModList:Sum("CHANCE", cfg, "HitsInvertEleResChance"), 1), 0)
if isElemental[damageType] and invertChanceEle > 0 then
-- resist = (1 - invertChanceEle) * resist + invertChanceEle * (-1 * resist)
resist = resist - 2 * invertChanceEle * resist
end
local invertChanceChaos = m_max(m_min(skillModList:Sum("CHANCE", cfg, "HitsInvertChaosResChance"), 1), 0)
if damageType == "Chaos" and invertChanceChaos > 0 then
resist = resist - 2 * invertChanceChaos * resist
end
local invertChance = (isElemental[damageType] and invertChanceEle) or (damageType == "Chaos" and invertChanceChaos) or 0
sourceRes = env.modDB:Flag(nil, "Enemy"..sourceRes.."ResistEqualToYours") and "Your "..sourceRes.." Resistance" or (env.partyMembers.modDB:Flag(nil, "Enemy"..sourceRes.."ResistEqualToYours") and "Party Member "..sourceRes.." Resistance" or sourceRes)
if skillFlags.projectile then
takenInc = takenInc + enemyDB:Sum("INC", nil, "ProjectileDamageTaken")
Expand All @@ -3388,24 +3382,30 @@ function calcs.offence(env, actor, activeSkill)
local effMult = (1 + takenInc / 100) * takenMore
local useResChance = useThisResist(damageType)
local useRes = useResChance > 0
local effectiveResist = resist
if skillModList:Flag(cfg, isElemental[damageType] and "CannotElePenIgnore" or nil) then
effMult = effMult * (1 - resist / 100)
effectiveResist = invertChance > 0 and (resist - 2 * invertChance * resist) or resist
effMult = effMult * (1 - effectiveResist / 100)
elseif useRes then
effMult = effMult * (1 - ((resist - pen) * useResChance) / 100)
if invertChance > 0 then
effectiveResist = ((resist - pen) * (1 - invertChance) + (-resist - pen) * invertChance) * useResChance
else
effectiveResist = (resist - pen) * useResChance
end
effMult = effMult * (1 - effectiveResist / 100)
end
damageTypeHitMin = damageTypeHitMin * effMult
damageTypeHitMax = damageTypeHitMax * effMult
damageTypeHitAvg = damageTypeHitAvg * effMult
if env.mode == "CALCS" then
output[damageType.."EffMult"] = effMult
end
local invertChance = (isElemental[damageType] and invertChanceEle) or (damageType == "Chaos" and invertChanceChaos) or 0
if pass == 2 and breakdown and (effMult ~= 1 or sourceRes ~= damageType) and skillModList:Flag(cfg, isElemental[damageType] and "CannotElePenIgnore" or nil) then
if pass == 2 and breakdown and (effMult ~= 1 or sourceRes ~= damageType or invertChance > 0) and skillModList:Flag(cfg, isElemental[damageType] and "CannotElePenIgnore" or nil) then
t_insert(breakdown[damageType], s_format("x %.3f ^8(effective DPS modifier)", effMult))
breakdown[damageType.."EffMult"] = breakdown.effMult(damageType, resist, 0, takenInc, effMult, takenMore, sourceRes, useRes, invertChance)
elseif pass == 2 and breakdown and (effMult ~= 1 or sourceRes ~= damageType) then
breakdown[damageType.."EffMult"] = breakdown.effMult(damageType, resist, 0, takenInc, effMult, takenMore, sourceRes, useRes, invertChance, effectiveResist)
elseif pass == 2 and breakdown and (effMult ~= 1 or sourceRes ~= damageType or invertChance > 0) then
t_insert(breakdown[damageType], s_format("x %.3f ^8(effective DPS modifier)", effMult))
breakdown[damageType.."EffMult"] = breakdown.effMult(damageType, resist, pen, takenInc, effMult, takenMore, sourceRes, useRes, invertChance)
breakdown[damageType.."EffMult"] = breakdown.effMult(damageType, resist, pen, takenInc, effMult, takenMore, sourceRes, useRes, invertChance, effectiveResist)
end
end
if pass == 2 and breakdown then
Expand Down
Loading