Skip to content

Commit 4c80961

Browse files
Apply armour before resistances (#57)
And armour applies to x mods
1 parent bdfb378 commit 4c80961

File tree

2 files changed

+44
-38
lines changed

2 files changed

+44
-38
lines changed

src/Modules/CalcDefence.lua

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,7 @@ function calcs.applyDmgTakenConversion(activeSkill, output, breakdown, sourceTyp
287287
local percentOfArmourApplies = m_min((not activeSkill.skillModList:Flag(nil, "ArmourDoesNotApplyTo"..damageType.."DamageTaken") and activeSkill.skillModList:Sum("BASE", nil, "ArmourAppliesTo"..damageType.."DamageTaken") or 0), 100)
288288
if percentOfArmourApplies > 0 then
289289
local effArmour = (output.Armour * percentOfArmourApplies / 100) * (1 + output.ArmourDefense)
290-
local effDamage = damage * resMult
291-
armourReduct = round(effArmour ~= 0 and damage * resMult ~= 0 and calcs.armourReductionF(effArmour, effDamage) or 0)
290+
armourReduct = round(effArmour ~= 0 and damage ~= 0 and calcs.armourReductionF(effArmour, damage) or 0)
292291
armourReduct = m_min(output.DamageReductionMax, armourReduct)
293292
end
294293
reductMult = (1 - m_max(m_min(output.DamageReductionMax, armourReduct + reduction), 0) / 100) * damageTakenMods
@@ -321,13 +320,13 @@ function calcs.takenHitFromDamage(rawDamage, damageType, actor)
321320
local output = actor.output
322321
local modDB = actor.modDB
323322
local function damageMitigationMultiplierForType(damage, type)
324-
local totalResistMult = output[type .."ResistTakenHitMulti"]
325323
local effectiveAppliedArmour = output[type .."EffectiveAppliedArmour"]
326-
local armourDRPercent = calcs.armourReductionF(effectiveAppliedArmour, damage * totalResistMult)
324+
local armourDRPercent = calcs.armourReductionF(effectiveAppliedArmour, damage)
327325
local flatDRPercent = modDB:Flag(nil, "SelfIgnore".."Base".. type .."DamageReduction") and 0 or output["Base".. type .."DamageReductionWhenHit"] or output["Base".. type .."DamageReduction"]
328326
local totalDRPercent = m_min(output.DamageReductionMax, armourDRPercent + flatDRPercent)
329327
local enemyOverwhelmPercent = modDB:Flag(nil, "SelfIgnore".. type .."DamageReduction") and 0 or output[type .."EnemyOverwhelm"]
330328
local totalDRMulti = 1 - m_max(m_min(output.DamageReductionMax, totalDRPercent - enemyOverwhelmPercent), 0) / 100
329+
local totalResistMult = output[type .."ResistTakenHitMulti"]
331330
return totalResistMult * totalDRMulti
332331
end
333332
local receivedDamageSum = 0
@@ -1983,10 +1982,10 @@ function calcs.buildDefenceEstimations(env, actor)
19831982
end
19841983
output[damageType.."takenFlat"] = takenFlat
19851984
if percentOfArmourApplies > 0 then
1986-
armourReduct = calcs.armourReduction(effectiveAppliedArmour, damage * resMult)
1985+
armourReduct = calcs.armourReduction(effectiveAppliedArmour, damage)
19871986
armourReduct = m_min(output.DamageReductionMax, armourReduct)
19881987
if impaleDamage > 0 then
1989-
impaleArmourReduct = m_min(output.DamageReductionMax, calcs.armourReduction(effectiveAppliedArmour, impaleDamage * resMult))
1988+
impaleArmourReduct = m_min(output.DamageReductionMax, calcs.armourReduction(effectiveAppliedArmour, impaleDamage))
19901989
end
19911990
end
19921991
local totalReduct = m_min(output.DamageReductionMax, armourReduct + reduction)
@@ -1999,15 +1998,15 @@ function calcs.buildDefenceEstimations(env, actor)
19991998
if breakdown then
20001999
breakdown[damageType.."DamageReduction"] = { }
20012000
if armourReduct ~= 0 then
2001+
if percentOfArmourApplies ~= 100 then
2002+
t_insert(breakdown[damageType.."DamageReduction"], s_format("%d%% percent of armour applies", percentOfArmourApplies))
2003+
end
2004+
t_insert(breakdown[damageType.."DamageReduction"], s_format("Reduction from Armour: %d%%", armourReduct))
20022005
if resMult ~= 1 then
20032006
t_insert(breakdown[damageType.."DamageReduction"], s_format("Enemy Hit Damage After Resistance: %d ^8(total incoming damage)", damage * resMult))
20042007
else
20052008
t_insert(breakdown[damageType.."DamageReduction"], s_format("Enemy Hit Damage: %d ^8(total incoming damage)", damage))
20062009
end
2007-
if percentOfArmourApplies ~= 100 then
2008-
t_insert(breakdown[damageType.."DamageReduction"], s_format("%d%% percent of armour applies", percentOfArmourApplies))
2009-
end
2010-
t_insert(breakdown[damageType.."DamageReduction"], s_format("Reduction from Armour: %d%%", armourReduct))
20112010
end
20122011
if reduction ~= 0 then
20132012
t_insert(breakdown[damageType.."DamageReduction"], s_format("Base %s Damage Reduction: %d%%", damageType, reduction))
@@ -2046,24 +2045,10 @@ function calcs.buildDefenceEstimations(env, actor)
20462045
end
20472046
if breakdown then
20482047
breakdown[damageType.."TakenHitMult"] = { }
2049-
if resist ~= 0 then
2050-
t_insert(breakdown[damageType.."TakenHitMult"], s_format("Resistance: %.2f", 1 - resist / 100))
2051-
end
2052-
if enemyPen ~= 0 then
2053-
t_insert(breakdown[damageType.."TakenHitMult"], s_format("+ Enemy Pen: %.2f", enemyPen / 100))
2054-
end
2055-
if resist ~= 0 and enemyPen ~= 0 then
2056-
t_insert(breakdown[damageType.."TakenHitMult"], s_format("= %.2f", resMult))
2057-
end
20582048
if reduction ~= 0 then
20592049
t_insert(breakdown[damageType.."TakenHitMult"], s_format("Base %s Damage Reduction: %.2f", damageType, 1 - reduction / 100))
20602050
end
20612051
if armourReduct ~= 0 then
2062-
if resMult ~= 1 then
2063-
t_insert(breakdown[damageType.."TakenHitMult"], s_format("Enemy Hit Damage After Resistance: %d ^8(total incoming damage)", damage * resMult))
2064-
else
2065-
t_insert(breakdown[damageType.."TakenHitMult"], s_format("Enemy Hit Damage: %d ^8(total incoming damage)", damage))
2066-
end
20672052
if percentOfArmourApplies ~= 100 then
20682053
t_insert(breakdown[damageType.."TakenHitMult"], s_format("%d%% percent of armour applies", percentOfArmourApplies))
20692054
end
@@ -2075,6 +2060,15 @@ function calcs.buildDefenceEstimations(env, actor)
20752060
if reduction ~= 0 or armourReduct ~= 0 or enemyOverwhelm ~= 0 then
20762061
t_insert(breakdown[damageType.."TakenHitMult"], s_format("= %.2f", reductMult))
20772062
end
2063+
if resist ~= 0 then
2064+
t_insert(breakdown[damageType.."TakenHitMult"], s_format("Resistance: %.2f", 1 - resist / 100))
2065+
end
2066+
if enemyPen ~= 0 then
2067+
t_insert(breakdown[damageType.."TakenHitMult"], s_format("+ Enemy Pen: %.2f", enemyPen / 100))
2068+
end
2069+
if resist ~= 0 and enemyPen ~= 0 then
2070+
t_insert(breakdown[damageType.."TakenHitMult"], s_format("= %.2f", resMult))
2071+
end
20782072
if resMult ~= 1 and reductMult ~= 1 then
20792073
t_insert(breakdown[damageType.."TakenHitMult"], s_format("%.2f x %.2f = %.3f", resMult, reductMult, baseMult))
20802074
end
@@ -3198,30 +3192,32 @@ function calcs.buildDefenceEstimations(env, actor)
31983192
local totalResistMult = output[damageConvertedType.."ResistTakenHitMulti"]
31993193

32003194
local reductionPercent = modDB:Flag(nil, "SelfIgnore".."Base"..damageConvertedType.."DamageReduction") and 0 or output["Base"..damageConvertedType.."DamageReductionWhenHit"] or output["Base"..damageConvertedType.."DamageReduction"]
3201-
local flatDR = reductionPercent / 100
32023195
local enemyOverwhelmPercent = modDB:Flag(nil, "SelfIgnore"..damageConvertedType.."DamageReduction") and 0 or output[damageConvertedType.."EnemyOverwhelm"]
3196+
local flatDR = reductionPercent / 100
32033197

32043198
-- We know the damage and armour calculation chain. The important part for max hit calculations is:
3205-
-- dmgAfterRes = RAW * DamageConvertedMulti * ResistanceMulti
3206-
-- armourDR = AppliedArmour / (AppliedArmour + data.misc.ArmourRatio * dmgAfterRes)
3207-
-- totalDR = max(min(armourDR + FlatDR, MaxReduction) - Overwhelm, 0) -- min and max is complicated to actually math out so skip caps first and tack it on later. Result should be close enough
3208-
-- dmgReceived = dmgAfterRes * (1 - totalDR)
3209-
-- damageTaken = (dmgReceived + takenFlat) * TakenMulti
3199+
-- armourDR = AppliedArmour / (AppliedArmour + data.misc.ArmourRatio * RAW * DamageConvertedMulti)
3200+
-- drMulti = 1 - max(min(armourDR + FlatDR, MaxReduction) - Overwhelm, 0) -- min and max is complicated to actually math out so skip caps first and tack it on later. Result should be close enough
3201+
-- dmgAfterRes = RAW * DamageConvertedMulti * drMulti * ResistanceMulti
3202+
-- damageTaken = (dmgAfterRes + takenFlat) * TakenMulti
32103203
-- If we consider damageTaken to be the total hit pool of the actor, we can go backwards in the chain until we find the max hit - the RAW damage.
32113204
-- Unfortunately the above is slightly simplified and is missing a line that *really* complicates stuff for exact calculations:
32123205
-- damageTaken = damageTakenAsPhys + damageTakenAsFire + damageTakenAsCold + damageTakenAsLightning + damageTakenAsChaos
32133206
-- Trying to solve that for RAW might require solving a polynomial equation of 6th degree, so this solution settles for solving the parts independently and then approximating the final result
32143207
--
32153208
-- To solve only one part the above can be expressed as this:
3216-
-- data.misc.ArmourRatio * (1 - FlatDR + Overwhelm) * TakenMulti * ResistanceMulti * ResistanceMulti * DamageConvertedMulti * DamageConvertedMulti * RAW * RAW + ((Overwhelm - FlatDR) * AppliedArmour * TakenMulti
3217-
-- - data.misc.ArmourRatio * (damageTaken - takenFlat * TakenMulti)) * ResistanceMulti * DamageConvertedMulti * RAW - (damageTaken - takenFlat * TakenMulti) * AppliedArmour = 0
3209+
-- RAW * RAW * data.misc.ArmourRatio * DamageConvertedMulti * (1 - FlatDR + Overwhelm)
3210+
-- + RAW * (AppliedArmour * (1 - FlatDR + Overwhelm) - AppliedArmour - (damageTaken / TakenMulti - takenFlat) / (DamageConvertedMulti * ResistanceMulti) * data.misc.ArmourRatio * DamageConvertedMulti)
3211+
-- - (damageTaken / TakenMulti - takenFlat) / (DamageConvertedMulti * ResistanceMulti) * AppliedArmour = 0
32183212
-- Which means that
32193213
-- RAW = [quadratic]
32203214

3221-
local resistXConvert = totalResistMult * damageConvertedMulti
3222-
local a = data.misc.ArmourRatio * (1 - flatDR + enemyOverwhelmPercent / 100) * totalTakenMulti * resistXConvert * resistXConvert
3223-
local b = ((enemyOverwhelmPercent / 100 - flatDR) * effectiveAppliedArmour * totalTakenMulti - data.misc.ArmourRatio * (totalHitPool - takenFlat * totalTakenMulti)) * resistXConvert
3224-
local c = -effectiveAppliedArmour * (totalHitPool - takenFlat * totalTakenMulti)
3215+
local oneMinusFlatPlusOverwhelm = (1 + flatDR - enemyOverwhelmPercent / 100)
3216+
local HP_tTM_tF_DCM_tRM = (totalHitPool / totalTakenMulti - takenFlat) / (damageConvertedMulti * totalResistMult)
3217+
3218+
local a = data.misc.ArmourRatio * damageConvertedMulti * oneMinusFlatPlusOverwhelm
3219+
local b = (effectiveAppliedArmour * oneMinusFlatPlusOverwhelm - effectiveAppliedArmour - HP_tTM_tF_DCM_tRM * data.misc.ArmourRatio * damageConvertedMulti)
3220+
local c = -HP_tTM_tF_DCM_tRM * effectiveAppliedArmour
32253221

32263222
local RAW = (m_sqrt(b * b - 4 * a * c) - b) / (2 * a)
32273223

src/Modules/ModParser.lua

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2202,8 +2202,18 @@ local specialModList = {
22022202
mod("ArmourAppliesToColdDamageTaken", "BASE", num),
22032203
mod("ArmourAppliesToLightningDamageTaken", "BASE", num),
22042204
} end,
2205-
["(%d+)%% of armour also applies to chaos damage taken from hits"] = function(num) return { mod("ArmourAppliesToChaosDamageTaken", "BASE", num) } end,
2206-
["armour also applies to chaos damage taken from hits"] = function(num) return { mod("ArmourAppliesToChaosDamageTaken", "BASE", 100) } end,
2205+
["armour applies to elemental damage"] = {
2206+
mod("ArmourAppliesToFireDamageTaken", "BASE", 100),
2207+
mod("ArmourAppliesToColdDamageTaken", "BASE", 100),
2208+
mod("ArmourAppliesToLightningDamageTaken", "BASE", 100),
2209+
},
2210+
["(%d+)%% of armour applies to elemental damage"] = function(num) return {
2211+
mod("ArmourAppliesToFireDamageTaken", "BASE", num),
2212+
mod("ArmourAppliesToColdDamageTaken", "BASE", num),
2213+
mod("ArmourAppliesToLightningDamageTaken", "BASE", num),
2214+
} end,
2215+
["armour also applies to (%a+) damage taken from hits"] = function(dmgType) return { mod("ArmourAppliesTo"..firstToUpper(dmgType).."DamageTaken", "BASE", 100) } end,
2216+
["(%d+)%% of armour also applies to (%a+) damage taken from hits"] = function(num, _, dmgType) return { mod("ArmourAppliesTo"..firstToUpper(dmgType).."DamageTaken", "BASE", num) } end,
22072217
["maximum damage reduction for any damage type is (%d+)%%"] = function(num) return { mod("DamageReductionMax", "OVERRIDE", num) } end,
22082218
["gain additional elemental damage reduction equal to half your chaos resistance"] = {
22092219
mod("ElementalDamageReduction", "BASE", 1, { type = "PerStat", stat = "ChaosResist", div = 2 })

0 commit comments

Comments
 (0)