Skip to content

Fix negative Impale DPS for dual wielding combined attacks #8554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
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
41 changes: 41 additions & 0 deletions spec/System/TestImpale_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -284,4 +284,45 @@ describe("TestAttacks", function()
assert.are.near(120*1.3, build.calcsTab.mainOutput.ImpaleDPS, 0.0000001) -- 6 impales * 10% stored damage * 1.3 attacks per second
end)

it("impale dual wield simultaneous attack", function()
newBuild()
build.skillsTab:PasteSocketGroup("Cleave 20/0 Default 1\n")
-- exactly 100
build.itemsTab:CreateDisplayItemFromRaw("New Item\nVaal Blade\nQuality: 0\nAdds 54 to 14 physical damage\n50% chance to Impale Enemies on Hit with Attacks")
build.itemsTab:AddDisplayItem()
-- exactly 200 offhand
build.itemsTab:CreateDisplayItemFromRaw("New Item\nVaal Blade\nQuality: 0\nAdds 54 to 14 physical damage\n100% increased Physical Damage\n50% chance to Impale Enemies on Hit with Attacks")
build.itemsTab:AddDisplayItem()
build.itemsTab:CreateDisplayItemFromRaw("New Item\nPaua Amulet\nYour hits can't be evaded\n-20 strength\n")
build.itemsTab:AddDisplayItem()

-- 0% crit
build.configTab.input.customMods = "\z
never deal critical strikes\n\z
Impale Damage dealt to Enemies Impaled by you Overwhelms 100% Physical Damage Reduction\n\z
Overwhelm 100% physical damage reduction\n\z
"
build.configTab:BuildModList()
runCallback("OnFrame")

assert.are.equals(50, build.calcsTab.mainOutput.MainHand.ImpaleChance)
assert.are.equals(50, build.calcsTab.mainOutput.OffHand.ImpaleChance)
assert.are.equals(50, build.calcsTab.mainOutput.MainHand.ImpaleChanceOnCrit)
assert.are.equals(50, build.calcsTab.mainOutput.OffHand.ImpaleChanceOnCrit)

-- level 20 cleave (currently) has 511.2% damage effectiveness and a 40% less modifier for combined attacks
-- things get rounded in the calc tab so there's some margin
assert.are.near(5.112*100*0.6, build.calcsTab.mainOutput.MainHand.PhysicalHitAverage, 1)
assert.are.near(5.112*200*0.6, build.calcsTab.mainOutput.OffHand.PhysicalHitAverage, 1)
assert.are.near(5.112*100*0.6, build.calcsTab.mainOutput.MainHand.impaleStoredHitAvg, 1)
assert.are.near(5.112*200*0.6, build.calcsTab.mainOutput.OffHand.impaleStoredHitAvg, 1)
-- 5 impales * 10% stored damage * 50% impale chance
assert.are.equals(1+(5*0.1*0.5), build.calcsTab.mainOutput.MainHand.ImpaleModifier)
assert.are.equals(1+(5*0.1*0.5), build.calcsTab.mainOutput.OffHand.ImpaleModifier)

-- stored damage * 0.25 impale modifier * 1.3 attacks per second * 0.8 cleave modifier * 1.1 dual wield modifier
assert.are.near(300*5.112*0.6*0.25*1.3*0.8*1.1, build.calcsTab.mainOutput.ImpaleDPS, 0.1)

end)

end)
49 changes: 34 additions & 15 deletions src/Modules/CalcOffence.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5538,11 +5538,15 @@ function calcs.offence(env, actor, activeSkill)
output.WithBleedDPS = baseDPS
end
if skillFlags.impale then
local mainHandImpaleDPS, offHandImpaleDPS
if skillFlags.attack and skillData.doubleHitsWhenDualWielding and skillFlags.bothWeaponAttack then
-- due to how its being combined
output.ImpaleModifier = output.ImpaleModifier / 2
-- separately combine
mainHandImpaleDPS = output.MainHand.impaleStoredHitAvg * ((output.MainHand.ImpaleModifier or 1) - 1) * output.MainHand.HitChance / 100 * skillData.dpsMultiplier
offHandImpaleDPS = output.OffHand.impaleStoredHitAvg * ((output.OffHand.ImpaleModifier or 1) - 1) * output.OffHand.HitChance / 100 * skillData.dpsMultiplier
output.ImpaleDPS = mainHandImpaleDPS + offHandImpaleDPS
else
output.ImpaleDPS = output.impaleStoredHitAvg * ((output.ImpaleModifier or 1) - 1) * output.HitChance / 100 * skillData.dpsMultiplier
end
output.ImpaleDPS = output.impaleStoredHitAvg * ((output.ImpaleModifier or 1) - 1) * output.HitChance / 100 * skillData.dpsMultiplier
if skillData.showAverage then
output.WithImpaleDPS = output.AverageDamage + output.ImpaleDPS
output.CombinedAvg = output.CombinedAvg + output.ImpaleDPS
Expand All @@ -5557,19 +5561,34 @@ function calcs.offence(env, actor, activeSkill)
output.CombinedDPS = output.CombinedDPS + output.ImpaleDPS
if breakdown then
breakdown.ImpaleDPS = {}
t_insert(breakdown.ImpaleDPS, s_format("%.2f ^8(average physical hit before mitigation)", output.impaleStoredHitAvg))
t_insert(breakdown.ImpaleDPS, s_format("x %.2f ^8(chance to hit)", output.HitChance / 100))
if skillFlags.notAverage then
t_insert(breakdown.ImpaleDPS, output.HitSpeed and s_format("x %.2f ^8(hit rate)", output.HitSpeed) or s_format("x %.2f ^8(%s rate)", output.Speed, skillFlags.attack and "attack" or "cast"))
end
t_insert(breakdown.ImpaleDPS, s_format("x %.2f ^8(impale damage multiplier)", ((output.ImpaleModifier or 1) - 1)))
if skillData.dpsMultiplier ~= 1 then
t_insert(breakdown.ImpaleDPS, s_format("x %g ^8(dps multiplier for this skill)", skillData.dpsMultiplier))
end
if quantityMultiplier > 1 then
t_insert(breakdown.ImpaleDPS, s_format("x %g ^8(quantity multiplier for this skill)", quantityMultiplier))
if skillFlags.attack and skillData.doubleHitsWhenDualWielding and skillFlags.bothWeaponAttack then
t_insert(breakdown.ImpaleDPS, s_format("Main Hand:"))
t_insert(breakdown.ImpaleDPS, s_format("%.2f ^8(MH average physical hit before mitigation)", output.MainHand.impaleStoredHitAvg))
t_insert(breakdown.ImpaleDPS, s_format("x %.2f ^8(MH chance to hit)", output.MainHand.HitChance / 100))
t_insert(breakdown.ImpaleDPS, s_format("x %.2f ^8(MH impale damage multiplier)\n", ((output.MainHand.ImpaleModifier or 1) - 1)))
t_insert(breakdown.ImpaleDPS, s_format("= %.2f", mainHandImpaleDPS))
t_insert(breakdown.ImpaleDPS, s_format("Off Hand:"))
t_insert(breakdown.ImpaleDPS, s_format("%.2f ^8(OH average physical hit before mitigation)", output.OffHand.impaleStoredHitAvg))
t_insert(breakdown.ImpaleDPS, s_format("x %.2f ^8(OH chance to hit)", output.OffHand.HitChance / 100))
t_insert(breakdown.ImpaleDPS, s_format("x %.2f ^8(OH impale damage multiplier)", ((output.OffHand.ImpaleModifier or 1) - 1)))
t_insert(breakdown.ImpaleDPS, s_format("= %.2f", offHandImpaleDPS))
t_insert(breakdown.ImpaleDPS, s_format("Combined total:"))
t_insert(breakdown.ImpaleDPS, s_format("%.2f + %.2f", mainHandImpaleDPS, offHandImpaleDPS))
else
t_insert(breakdown.ImpaleDPS, s_format("%.2f ^8(average physical hit before mitigation)", output.impaleStoredHitAvg))
t_insert(breakdown.ImpaleDPS, s_format("x %.2f ^8(chance to hit)", output.HitChance / 100))
t_insert(breakdown.ImpaleDPS, s_format("x %.2f ^8(impale damage multiplier)", ((output.ImpaleModifier or 1) - 1)))
end
t_insert(breakdown.ImpaleDPS, s_format("= %.1f", output.ImpaleDPS))
if skillFlags.notAverage then
t_insert(breakdown.ImpaleDPS, output.HitSpeed and s_format("x %.2f ^8(hit rate)", output.HitSpeed) or s_format("x %.2f ^8(%s rate)", output.Speed, skillFlags.attack and "attack" or "cast"))
end
if skillData.dpsMultiplier ~= 1 then
t_insert(breakdown.ImpaleDPS, s_format("x %g ^8(dps multiplier for this skill)", skillData.dpsMultiplier))
end
if quantityMultiplier > 1 then
t_insert(breakdown.ImpaleDPS, s_format("x %g ^8(quantity multiplier for this skill)", quantityMultiplier))
end
t_insert(breakdown.ImpaleDPS, s_format("= %.1f", output.ImpaleDPS))
end
end

Expand Down