diff --git a/spec/System/TestAttacks_spec.lua b/spec/System/TestAttacks_spec.lua index 80e87b7c3..73525e64a 100644 --- a/spec/System/TestAttacks_spec.lua +++ b/spec/System/TestAttacks_spec.lua @@ -231,6 +231,49 @@ describe("TestAttacks", function() end end) + it("correctly calculates Garukhan's Resolve bifurcated critical hit damage", function() + local function setup(socketGroup) + newBuild() + build.itemsTab:CreateDisplayItemFromRaw([[ + New Item + Razor Quarterstaff + Quality: 0 + This Weapon's Critical Hit Chance is 0% + -100% increased physical damage + adds 1 to 1 physical damage to attacks + nearby enemies have 100% less armour + nearby enemies have 100% less evasion + ]]) + build.itemsTab:AddDisplayItem() + runCallback("OnFrame") + build.skillsTab:PasteSocketGroup(socketGroup) + runCallback("OnFrame") + + build.configTab.input.customMods = [[ + +50% to critical hit chance + your critical damage bonus is 1000000% + +4000 to accuracy + ]] + build.configTab:BuildModList() + runCallback("OnFrame") + build.calcsTab:BuildOutput() + runCallback("OnFrame") + + return build.calcsTab.mainOutput.MainHand + end + + local normalOutput = setup("Quarterstaff Strike 1/0 1") + assert.are.equals(50, normalOutput.CritChance) + assert.are.equals(10001, normalOutput.CritMultiplier) + assert.are.equals(5001, normalOutput.AverageHit) + + local garukhanOutput = setup("Quarterstaff Strike 1/0 1\nGarukhan's Resolve 1/0 1") + assert.are.equals(50, garukhanOutput.PreBifurcateCritChance) + assert.are.equals(75, garukhanOutput.CritChance) + assert.is_true(math.abs(1 / 3 - (garukhanOutput.CritBifurcates - 1)) < 0.000001) + assert.is_true(math.abs(10001 - garukhanOutput.AverageHit) < 0.01) + end) + it("correctly adds damage with oracle forced outcome", function() -- Setup: Add weapon with no crit chance, and strip enemy defenses build.itemsTab:CreateDisplayItemFromRaw([[ diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 71f740b7e..c314de83f 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3808,18 +3808,22 @@ function calcs.offence(env, actor, activeSkill) -- get crit chance and calculate odds of critting twice local critChancePercentage = output.PreBifurcateCritChance local bifurcateMultiChance = (critChancePercentage ^ 2) / 100 - output.CritBifurcates = bifurcateMultiChance + local effectiveCritChance = output.CritChance + local conditionalBifurcateChance = effectiveCritChance > 0 and bifurcateMultiChance / effectiveCritChance or 0 + output.CritBifurcates = 1 + conditionalBifurcateChance local damageBonus = extraDamage - local bifurcatedBonus = bifurcateMultiChance * extraDamage / 100 - if breakdown and enemyInc ~= 1 then + local bifurcatedBonus = conditionalBifurcateChance * extraDamage + if breakdown then breakdown.CritBifurcates = { - s_format("%.2f%% ^8(effective crit chance)", critChancePercentage), + s_format("%.2f%% ^8(pre-bifurcate crit chance)", critChancePercentage), s_format("x %.2f%%", critChancePercentage), - s_format("= %.2f%% ^8(crit Bifurcates chance)", bifurcateMultiChance), + s_format("= %.2f%% ^8(chance both crit rolls succeed)", bifurcateMultiChance), + s_format("/ %.2f%% ^8(chance at least one crit roll succeeds)", effectiveCritChance), + s_format("= %.2f ^8(crit Bifurcates effect)", 1 + conditionalBifurcateChance), } end extraDamage = damageBonus + bifurcatedBonus - skillModList:NewMod("CritMultiplier", "MORE", floor(bifurcateMultiChance, 2), "Bifurcated Crit Damage Bonus") + skillModList:NewMod("CritMultiplier", "MORE", floor(conditionalBifurcateChance * 100, 2), "Bifurcated Crit Damage Bonus") end if env.mode_effective then diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index ac2c815f9..0dc32ba24 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -576,7 +576,7 @@ return { { label = "Player modifiers", modName = { "CritChance", "WeaponBaseCritChance", "MainHandCritIsEqualToParent", "MainHandCritIsEqualToPartyMember", "AttackCritIsEqualToParentMainHand", "InevitableCriticalHits" }, cfg = "weapon1" }, { label = "Enemy modifiers", modName = "SelfCritChance", enemy = true }, }, }, - { label = "MH Crit Bifurcates", bgCol = colorCodes.MAINHANDBG, haveOutput = "MainHand.CritBifurcates", flag = "weapon1Attack", { format = "{2:output:MainHand.CritBifurcates}%", + { label = "MH Crit Bifurcates", bgCol = colorCodes.MAINHANDBG, haveOutput = "MainHand.CritBifurcates", flag = "weapon1Attack", { format = "x {2:output:MainHand.CritBifurcates}", { breakdown = "MainHand.CritBifurcates" }, { label = "Player modifiers", modName = "BifurcateCrit", cfg = "weapon1" }, }, }, @@ -596,7 +596,7 @@ return { { label = "Player modifiers", modName = { "CritChance", "WeaponBaseCritChance", "AttackCritIsEqualToParentMainHand", "InevitableCriticalHits" }, cfg = "weapon2" }, { label = "Enemy modifiers", modName = "SelfCritChance", enemy = true }, }, }, - { label = "OH Crit Bifurcates", bgCol = colorCodes.OFFHANDBG, haveOutput = "OffHand.CritBifurcates", flag = "weapon2Attack", { format = "{2:output:OffHand.CritBifurcates}%", + { label = "OH Crit Bifurcates", bgCol = colorCodes.OFFHANDBG, haveOutput = "OffHand.CritBifurcates", flag = "weapon2Attack", { format = "x {2:output:OffHand.CritBifurcates}", { breakdown = "OffHand.CritBifurcates" }, { label = "Player modifiers", modName = "BifurcateCrit", cfg = "weapon2" }, }, },