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
14 changes: 14 additions & 0 deletions spec/System/TestSkills_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,20 @@ describe("TestSkills", function()
assert.True(build.calcsTab.mainEnv.enemyDB:Sum("BASE", nil, "FireResist") < fireResistWithoutPotentExposure)
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")

assert.are.equals(1.25, build.calcsTab.calcsOutput.FireEffMult)
local breakdownText = table.concat(build.calcsTab.calcsEnv.player.breakdown.FireEffMult, "\n")
assert.truthy(breakdownText:match("inverted hit"))
assert.truthy(breakdownText:match("weighted average"))
end)

it("Test granted skills with exposure stats make exposure configurable", function()
build.skillsTab:PasteSocketGroup("Fireball 20/0 1")
local spec = build.spec
Expand Down
21 changes: 15 additions & 6 deletions src/Modules/CalcBreakdown.lua
Original file line number Diff line number Diff line change
Expand Up @@ -110,20 +110,29 @@ function breakdown.area(base, areaMod, total, incBreakpoint, moreBreakpoint, red
return out
end

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

if invertChance and invertChance ~= 0 then
resistLabel = "average inverted "..resistForm
minPen = minPen or 0
local calcPenResist = function(resist)
return resist > minPen and m_max(resist - pen, minPen) or resist
end
effectiveResist = effectiveResist or calcPenResist(resist)

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 = calcPenResist(resist)
local invertedResist = calcPenResist(-resist)
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 @@ -145,7 +154,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 - (math.max(resist - pen,0)) / 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: 17 additions & 11 deletions src/Modules/CalcOffence.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4157,11 +4157,7 @@ function calcs.offence(env, actor, activeSkill)
end
end

local invertChance = m_max(m_min(skillModList:Sum("CHANCE", cfg, "HitsInvertEleResChance"), 1), 0)
if isElemental[damageType] and invertChance > 0 then
-- resist = (1 - invertChance) * resist + invertChance * (-1 * resist)
resist = resist - 2 * invertChance * resist
end
local invertChance = isElemental[damageType] and m_max(m_min(skillModList:Sum("CHANCE", cfg, "HitsInvertEleResChance"), 1), 0) 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 @@ -4174,23 +4170,33 @@ function calcs.offence(env, actor, activeSkill)
end
local effMult = (1 + takenInc / 100) * takenMore
local useRes = useThisResist(damageType)
local effectiveResist = resist
local calcPenResist = function(resist)
return resist > minPen and m_max(resist - pen, minPen) or resist
end
if skillModList:Flag(cfg, isElemental[damageType] and "CannotElePenIgnore" or nil) then
effMult = effMult * (1 - resist / 100)
effectiveResist = (isElemental[damageType] and invertChance > 0) and (resist - 2 * invertChance * resist) or resist
effMult = effMult * (1 - effectiveResist / 100)
elseif useRes then
effMult = effMult * (1 - (resist > minPen and m_max(resist - pen, minPen) or resist) / 100)
if isElemental[damageType] and invertChance > 0 then
effectiveResist = calcPenResist(resist) * (1 - invertChance) + calcPenResist(-resist) * invertChance
else
effectiveResist = calcPenResist(resist)
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
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, minPen)
elseif pass == 2 and breakdown and (effMult ~= 1 or (resist - pen) < minPen or sourceRes ~= damageType) then
breakdown[damageType.."EffMult"] = breakdown.effMult(damageType, resist, 0, takenInc, effMult, takenMore, sourceRes, useRes, invertChance, minPen, effectiveResist)
elseif pass == 2 and breakdown and (effMult ~= 1 or (resist - pen) < minPen 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, minPen)
breakdown[damageType.."EffMult"] = breakdown.effMult(damageType, resist, pen, takenInc, effMult, takenMore, sourceRes, useRes, invertChance, minPen, effectiveResist)
end
end
if pass == 2 and breakdown then
Expand Down
Loading