Skip to content

Commit bd68476

Browse files
AntaresqueLocalIdentity
and
LocalIdentity
authored
Add support for Forking Critical Strikes (#1100)
* Add prototype version of critforking * Failsafe for 100% crit chance override * Fix Crit effect calculation The forked effective crit multi was using the preHitCheckCritChance value for some reason which was skewing the values from being correct e.g. With 50% crit chance you have a 25% chance for your crit to hit to be a forking crit not 33.33% chance that it was calculating * Fix Calcs when accuracy is below 100% The game uses the effective crit chance when calculating the chance for lucky or forked crits so we need to incorporate the effect from accuracy earlier * Add breakdown for forked crit chance * Breakdown Formatting --------- Co-authored-by: LocalIdentity <[email protected]>
1 parent 7efe3cf commit bd68476

File tree

5 files changed

+54
-10
lines changed

5 files changed

+54
-10
lines changed

src/Data/ModCache.lua

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3809,8 +3809,7 @@ c["Fire Exposure you inflict lowers Total Fire Resistance by an extra 5%"]={{[1]
38093809
c["Fire Resistance is unaffected by Area Penalties"]={nil,"Fire Resistance is unaffected by Area Penalties "}
38103810
c["Fire Resistance is unaffected by Area Penalties Lightning Resistance is unaffected by Area Penalties"]={nil,"Fire Resistance is unaffected by Area Penalties Lightning Resistance is unaffected by Area Penalties "}
38113811
c["Flasks gain 0.17 charges per Second"]={{[1]={flags=0,keywordFlags=0,name="FlaskChargesGenerated",type="BASE",value=0.17}},nil}
3812-
c["Forks Critical Hits"]={nil,"Forks Critical Hits "}
3813-
c["Forks Critical Hits 10% of Skill Mana Costs Converted to Life Costs"]={nil,"Forks Critical Hits 10% of Skill Mana Costs Converted to Life Costs "}
3812+
c["Forks Critical Hits"]={{[1]={flags=0,keywordFlags=0,name="ForkCrit",type="FLAG",value=true}},nil}
38143813
c["Freeze as though dealing Cold damage equal to 10% of your maximum Mana when Hit"]={nil,"Freeze as though dealing Cold damage equal to 10% of your maximum Mana when Hit "}
38153814
c["Frenzy or Power Charge"]={nil,"Frenzy or Power Charge "}
38163815
c["Fully Armour Broken enemies you kill with Hits Shatter"]={nil,"Fully Armour Broken enemies you kill with Hits Shatter "}

src/Modules/BuildDisplayStats.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ local displayStats = {
3232
{ stat = "ReloadTime", label = "Reload Time", fmt = ".2fs", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ReloadTime end },
3333
{ stat = "PreEffectiveCritChance", label = "Crit Chance", fmt = ".2f%%", flag = "hit" },
3434
{ stat = "CritChance", label = "Effective Crit Chance", fmt = ".2f%%", flag = "hit", condFunc = function(v,o) return v ~= o.PreEffectiveCritChance end },
35+
{ stat = "CritForks", label = "Crit Forks Chance", fmt = ".2f%%", flag = "hit", condFunc = function(v,o) return (o.CritForks or 0) > 0 end },
3536
{ stat = "CritMultiplier", label = "Crit Multiplier", fmt = "d%%", pc = true, condFunc = function(v,o) return (o.CritChance or 0) > 0 end },
3637
{ stat = "HitChance", label = "Hit Chance", fmt = ".0f%%", flag = "attack" },
3738
{ stat = "HitChance", label = "Hit Chance", fmt = ".0f%%", condFunc = function(v,o) return o.enemyHasSpellBlock end },

src/Modules/CalcOffence.lua

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3151,6 +3151,7 @@ function calcs.offence(env, actor, activeSkill)
31513151

31523152
if critOverride == 100 then
31533153
output.PreEffectiveCritChance = 100
3154+
output.PreForkCritChance = 100
31543155
output.CritChance = 100
31553156
else
31563157
local base = 0
@@ -3168,13 +3169,18 @@ function calcs.offence(env, actor, activeSkill)
31683169
output.CritChance = m_max(output.CritChance, 0)
31693170
end
31703171
output.PreEffectiveCritChance = output.CritChance
3172+
local preHitCheckCritChance = output.CritChance
3173+
if env.mode_effective then
3174+
output.CritChance = output.CritChance * output.AccuracyHitChance / 100
3175+
end
31713176
local preLuckyCritChance = output.CritChance
31723177
if env.mode_effective and skillModList:Flag(cfg, "CritChanceLucky") then
31733178
output.CritChance = (1 - (1 - output.CritChance / 100) ^ 2) * 100
31743179
end
3175-
local preHitCheckCritChance = output.CritChance
3176-
if env.mode_effective then
3177-
output.CritChance = output.CritChance * output.AccuracyHitChance / 100
3180+
output.PreForkCritChance = output.CritChance
3181+
local preForkCritChance = output.CritChance
3182+
if env.mode_effective and skillModList:Flag(cfg, "ForkCrit") then
3183+
output.CritChance = (1 - (1 - output.CritChance / 100) ^ 2) * 100
31783184
end
31793185
if breakdown and output.CritChance ~= baseCrit then
31803186
breakdown.CritChance = { }
@@ -3195,15 +3201,21 @@ function calcs.offence(env, actor, activeSkill)
31953201
local overCap = preCapCritChance - 100
31963202
t_insert(breakdown.CritChance, s_format("Crit is overcapped by %.2f%% (%d%% increased Critical Hit Chance)", overCap, overCap / more / (baseCrit + base) * 100))
31973203
end
3204+
if env.mode_effective and output.AccuracyHitChance < 100 then
3205+
t_insert(breakdown.CritChance, "")
3206+
t_insert(breakdown.CritChance, "Effective Crit Chance:")
3207+
t_insert(breakdown.CritChance, s_format("%.2f%%", preHitCheckCritChance))
3208+
t_insert(breakdown.CritChance, s_format("x %.2f ^8(chance to hit)", output.AccuracyHitChance / 100))
3209+
t_insert(breakdown.CritChance, s_format("= %.2f%%", preLuckyCritChance))
3210+
end
31983211
if env.mode_effective and skillModList:Flag(cfg, "CritChanceLucky") then
31993212
t_insert(breakdown.CritChance, "Crit Chance is Lucky:")
32003213
t_insert(breakdown.CritChance, s_format("1 - (1 - %.4f) x (1 - %.4f)", preLuckyCritChance / 100, preLuckyCritChance / 100))
3201-
t_insert(breakdown.CritChance, s_format("= %.2f%%", preHitCheckCritChance))
3214+
t_insert(breakdown.CritChance, s_format("= %.2f%%", preForkCritChance))
32023215
end
3203-
if env.mode_effective and output.AccuracyHitChance < 100 then
3204-
t_insert(breakdown.CritChance, "Crit confirmation roll:")
3205-
t_insert(breakdown.CritChance, s_format("%.2f%%", preHitCheckCritChance))
3206-
t_insert(breakdown.CritChance, s_format("x %.2f ^8(chance to hit)", output.AccuracyHitChance / 100))
3216+
if env.mode_effective and skillModList:Flag(cfg, "ForkCrit") then
3217+
t_insert(breakdown.CritChance, "Critical Strike Forks:")
3218+
t_insert(breakdown.CritChance, s_format("1 - (1 - %.4f) x (1 - %.4f)", preForkCritChance / 100, preForkCritChance / 100))
32073219
t_insert(breakdown.CritChance, s_format("= %.2f%%", output.CritChance))
32083220
end
32093221
end
@@ -3221,6 +3233,27 @@ function calcs.offence(env, actor, activeSkill)
32213233
if multiOverride then
32223234
extraDamage = multiOverride / 100
32233235
end
3236+
3237+
output.PreEffectiveCritMultiplier = 1 + extraDamage
3238+
-- if crit forks are enabled, roll for crit twice and add multiplier for each
3239+
if env.mode_effective and skillModList:Flag(cfg, "ForkCrit") then
3240+
-- get crit chance and calculate odds of critting twice
3241+
local critChancePercentage = output.PreForkCritChance
3242+
local forkMultiChance = (critChancePercentage ^ 2) / 100
3243+
output.CritForks = forkMultiChance
3244+
local damageBonus = extraDamage
3245+
local forkedBonus = forkMultiChance * extraDamage / 100
3246+
if breakdown and enemyInc ~= 1 then
3247+
breakdown.CritForks = {
3248+
s_format("%.2f%% ^8(effective crit chance)", critChancePercentage),
3249+
s_format("x %.2f%%", critChancePercentage),
3250+
s_format("= %.2f%% ^8(crit forks chance)", forkMultiChance),
3251+
}
3252+
end
3253+
extraDamage = damageBonus + forkedBonus
3254+
skillModList:NewMod("CritMultiplier", "MORE", floor(forkMultiChance, 2), "Forked Crit Damage Bonus")
3255+
end
3256+
32243257
if env.mode_effective then
32253258
local enemyInc = 1 + enemyDB:Sum("INC", nil, "SelfCritMultiplier") / 100
32263259
extraDamage = extraDamage + enemyDB:Sum("BASE", nil, "SelfCritMultiplier") / 100
@@ -3896,7 +3929,9 @@ function calcs.offence(env, actor, activeSkill)
38963929
-- Combine crit stats, average damage and DPS
38973930
combineStat("PreEffectiveCritChance", "AVERAGE")
38983931
combineStat("CritChance", "AVERAGE")
3932+
combineStat("PreEffectiveCritMultiplier", "AVERAGE")
38993933
combineStat("CritMultiplier", "AVERAGE")
3934+
combineStat("CritForks", "AVERAGE")
39003935
combineStat("AverageDamage", "DPS")
39013936
combineStat("PvpAverageDamage", "DPS")
39023937
combineStat("TotalDPS", "DPS")

src/Modules/CalcSections.lua

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,10 @@ return {
546546
{ label = "Player modifiers", modName = { "CritChance", "WeaponBaseCritChance", "MainHandCritIsEqualToParent", "MainHandCritIsEqualToPartyMember", "AttackCritIsEqualToParentMainHand" }, cfg = "weapon1" },
547547
{ label = "Enemy modifiers", modName = "SelfCritChance", enemy = true },
548548
}, },
549+
{ label = "MH Crit Forks", bgCol = colorCodes.MAINHANDBG, flag = "weapon1Attack", { format = "{2:output:MainHand.CritForks}%",
550+
{ breakdown = "MainHand.CritForks" },
551+
{ label = "Player modifiers", modName = "ForkCrit", cfg = "weapon1" },
552+
}, },
549553
{ label = "MH Crit Multiplier", bgCol = colorCodes.MAINHANDBG, flag = "weapon1Attack", { format = "x {2:output:MainHand.CritMultiplier}",
550554
{ breakdown = "MainHand.CritMultiplier" },
551555
{ label = "Player modifiers", modName = "CritMultiplier", cfg = "weapon1" },
@@ -562,6 +566,10 @@ return {
562566
{ label = "Player modifiers", modName = { "CritChance", "WeaponBaseCritChance", "AttackCritIsEqualToParentMainHand" }, cfg = "weapon2" },
563567
{ label = "Enemy modifiers", modName = "SelfCritChance", enemy = true },
564568
}, },
569+
{ label = "OH Crit Forks", bgCol = colorCodes.OFFHANDBG, flag = "weapon2Attack", { format = "{2:output:OffHand.CritForks}%",
570+
{ breakdown = "OffHand.CritForks" },
571+
{ label = "Player modifiers", modName = "ForkCrit", cfg = "weapon2" },
572+
}, },
565573
{ label = "OH Crit Multiplier", bgCol = colorCodes.OFFHANDBG, flag = "weapon2Attack", { format = "x {2:output:OffHand.CritMultiplier}",
566574
{ breakdown = "OffHand.CritMultiplier" },
567575
{ label = "Player modifiers", modName = "CritMultiplier", cfg = "weapon2" },

src/Modules/ModParser.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3329,6 +3329,7 @@ local specialModList = {
33293329
["minion critical hits do not deal extra damage"] = { mod("MinionModifier", "LIST", { mod = flag("NoCritMultiplier") }) },
33303330
["lightning damage with non%-critical hits is lucky"] = { flag("LightningNoCritLucky") },
33313331
["your damage with critical hits is lucky"] = { flag("CritLucky") },
3332+
["forks critical hits"] = { flag("ForkCrit") },
33323333
["critical hits deal no damage"] = { mod("Damage", "MORE", -100, { type = "Condition", var = "CriticalStrike" }) },
33333334
["critical hit chance is increased by uncapped lightning resistance"] = { flag("CritChanceIncreasedByUncappedLightningRes") },
33343335
["critical hit chance is increased by lightning resistance"] = { flag("CritChanceIncreasedByLightningRes") },

0 commit comments

Comments
 (0)