Improve MoM+EB(+ES bypass) calculations (#8590)

This commit is contained in:
Edvinas-Smita
2025-06-11 06:55:57 +03:00
committed by GitHub
parent 91c1b5805c
commit 1559937723
2 changed files with 275 additions and 83 deletions

View File

@@ -840,4 +840,188 @@ describe("TestDefence", function()
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
end)
it("MoM + EB", function()
build.configTab.input.enemyIsBoss = "None"
-- enough mana and es, 0% and 100% bypass
build.configTab.input.customMods = [[
50% of damage is taken from mana before life
energy shield protects mana instead of life
+40 to maximum life
+1960 to mana
+2000 to energy shield
You have no intelligence
+60% to all resistances
]]
build.configTab:BuildModList()
runCallback("OnFrame")
assert.are.equals(200, build.calcsTab.calcsOutput.FireMaximumHitTaken)
assert.are.equals(200, build.calcsTab.calcsOutput.ChaosMaximumHitTaken)
local poolsRemaining = poolsRemainingAfterTypeMaxHit("Chaos")
assert.are.equals(2000, round(poolsRemaining.EnergyShield))
assert.are.equals(1900, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
poolsRemaining = poolsRemainingAfterTypeMaxHit("Fire")
assert.are.equals(1900, round(poolsRemaining.EnergyShield))
assert.are.equals(2000, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
-- enough mana and es, 50% bypass
build.configTab.input.customMods = [[
50% of damage is taken from mana before life
energy shield protects mana instead of life
50% of non-chaos damage taken bypasses energy shield
+40 to maximum life
+1960 to mana
+2000 to energy shield
You have no intelligence
+60% to all resistances
]]
build.configTab:BuildModList()
runCallback("OnFrame")
assert.are.equals(200, build.calcsTab.calcsOutput.FireMaximumHitTaken)
poolsRemaining = poolsRemainingAfterTypeMaxHit("Fire")
assert.are.equals(1950, round(poolsRemaining.EnergyShield))
assert.are.equals(1950, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
-- es bottleneck, 0% and 100% bypass
build.configTab.input.customMods = [[
50% of damage is taken from mana before life
energy shield protects mana instead of life
+40 to maximum life
+1960 to mana
+50 to energy shield
You have no intelligence
+60% to all resistances
]]
build.configTab:BuildModList()
runCallback("OnFrame")
assert.are.equals(200, build.calcsTab.calcsOutput.FireMaximumHitTaken)
assert.are.equals(200, build.calcsTab.calcsOutput.ChaosMaximumHitTaken)
poolsRemaining = poolsRemainingAfterTypeMaxHit("Chaos")
assert.are.equals(50, round(poolsRemaining.EnergyShield))
assert.are.equals(1900, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
poolsRemaining = poolsRemainingAfterTypeMaxHit("Fire")
assert.are.equals(0, round(poolsRemaining.EnergyShield))
assert.are.equals(1950, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
-- es bottleneck, 50% bypass
build.configTab.input.customMods = [[
50% of damage is taken from mana before life
energy shield protects mana instead of life
50% of non-chaos damage taken bypasses energy shield
+40 to maximum life
+1960 to mana
+40 to energy shield
You have no intelligence
+60% to all resistances
]]
build.configTab:BuildModList()
runCallback("OnFrame")
assert.are.equals(200, build.calcsTab.calcsOutput.FireMaximumHitTaken)
poolsRemaining = poolsRemainingAfterTypeMaxHit("Fire")
assert.are.equals(0, round(poolsRemaining.EnergyShield))
assert.are.equals(1940, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
-- mana bottleneck, 0% and 100% bypass
build.configTab.input.customMods = [[
50% of damage is taken from mana before life
energy shield protects mana instead of life
+40 to maximum life
+2000 to energy shield
You have no intelligence
+60% to all resistances
]]
build.configTab:BuildModList()
runCallback("OnFrame")
assert.are.equals(200, build.calcsTab.calcsOutput.FireMaximumHitTaken)
assert.are.equals(140, build.calcsTab.calcsOutput.ChaosMaximumHitTaken)
poolsRemaining = poolsRemainingAfterTypeMaxHit("Chaos")
assert.are.equals(2000, round(poolsRemaining.EnergyShield))
assert.are.equals(0, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
poolsRemaining = poolsRemainingAfterTypeMaxHit("Fire")
assert.are.equals(1900, round(poolsRemaining.EnergyShield))
assert.are.equals(40, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
-- mana bottleneck, 50% bypass
-- taking 160 damage in this scenario:
-- 160 damage is split to 80 damage straight to life, 80 damage to MoM pools
-- 50% of the 80 MoM pool damage is taken by ES and 50% bypasses
-- pool of 20 mana takes 40 damage, gets depleted and the remaining damage continues on to life, for a total of 100 damage to life
build.configTab.input.customMods = [[
50% of damage is taken from mana before life
energy shield protects mana instead of life
50% of non-chaos damage taken bypasses energy shield
+40 to maximum life
-20 to mana
+2000 to energy shield
You have no intelligence
+60% to all resistances
]]
build.configTab:BuildModList()
runCallback("OnFrame")
assert.are.equals(160, build.calcsTab.calcsOutput.FireMaximumHitTaken)
poolsRemaining = poolsRemainingAfterTypeMaxHit("Fire")
assert.are.equals(1960, round(poolsRemaining.EnergyShield))
assert.are.equals(0, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
-- mana+es bottleneck, 0% and 100% bypass
build.configTab.input.customMods = [[
50% of damage is taken from mana before life
energy shield protects mana instead of life
+940 to maximum life
+50 to energy shield
You have no intelligence
+60% to all resistances
]]
build.configTab:BuildModList()
runCallback("OnFrame")
assert.are.equals(1090, build.calcsTab.calcsOutput.FireMaximumHitTaken)
assert.are.equals(1040, build.calcsTab.calcsOutput.ChaosMaximumHitTaken)
poolsRemaining = poolsRemainingAfterTypeMaxHit("Chaos")
assert.are.equals(50, round(poolsRemaining.EnergyShield))
assert.are.equals(0, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
poolsRemaining = poolsRemainingAfterTypeMaxHit("Fire")
assert.are.equals(0, round(poolsRemaining.EnergyShield))
assert.are.equals(0, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
-- mana+es bottleneck, 50% bypass
build.configTab.input.customMods = [[
50% of damage is taken from mana before life
energy shield protects mana instead of life
50% of non-chaos damage taken bypasses energy shield
+940 to maximum life
+50 to energy shield
You have no intelligence
+60% to all resistances
]]
build.configTab:BuildModList()
runCallback("OnFrame")
assert.are.equals(1090, build.calcsTab.calcsOutput.FireMaximumHitTaken)
poolsRemaining = poolsRemainingAfterTypeMaxHit("Fire")
assert.are.equals(0, round(poolsRemaining.EnergyShield))
assert.are.equals(0, round(poolsRemaining.Mana))
assert.are.equals(0, floor(poolsRemaining.Life))
assert.are.equals(0, floor(poolsRemaining.OverkillDamage))
end)
end)

View File

@@ -215,10 +215,33 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor)
local LifeLossLostOverTime = poolTbl.LifeLossLostOverTime or 0
local LifeBelowHalfLossLostOverTime = poolTbl.LifeBelowHalfLossLostOverTime or 0
local overkillDamage = 0
ward = ward >= 0 and ward or 0
energyShield = energyShield >= 0 and energyShield or 0
mana = mana >= 0 and mana or 0
life = life >= 0 and life or 0
-- Initializing MoM(+EB(+Bypass)) pools here saves logic later to avoid overusing pools for every damageType
local resourcesLostToTypeDamage = { Physical = { }, Lightning = { }, Cold = { }, Fire = { }, Chaos = { } }
local MoMPoolRemaining = m_huge
local esPoolRemaining = m_huge
local lifeHitPoolInitial = calcLifeHitPoolWithLossPrevention(life, output.Life, output.preventedLifeLoss, lifeLossBelowHalfPrevented)
local MoMPoolsRemaining = { }
local esPoolsRemaining = { }
for damageType, _ in pairs(damageTable) do
local MoMEffect = m_min(output.sharedMindOverMatter + output[damageType.."MindOverMatter"], 100) / 100
local maxMoM = lifeHitPoolInitial / (1 - MoMEffect) - lifeHitPoolInitial
local MoMPool = MoMEffect < 1 and m_min(maxMoM, mana) or mana
local lifePlusMoMHitPool = lifeHitPoolInitial + MoMPool
local esBypass = output[damageType.."EnergyShieldBypass"] / 100 or 0
local esPool = esBypass > 0 and m_min(lifePlusMoMHitPool / esBypass - lifePlusMoMHitPool, energyShield) or energyShield
if modDB:Flag(nil, "EnergyShieldProtectsMana") and esBypass < 1 then
esPoolsRemaining[damageType] = m_floor(m_min(maxMoM * (1 - esBypass), energyShield, lifePlusMoMHitPool / (1 - (1 - esBypass) * MoMEffect) - lifePlusMoMHitPool))
MoMPoolsRemaining[damageType] = m_floor(m_min(maxMoM - esPoolsRemaining[damageType], MoMPool))
else
esPoolsRemaining[damageType] = m_floor(esPool)
MoMPoolsRemaining[damageType] = m_floor(MoMPool)
end
end
for _, damageType in ipairs(dmgTypeList) do
local damageRemainder = damageTable[damageType]
if damageRemainder then
@@ -270,39 +293,37 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor)
damageRemainder = damageRemainder - tempDamage
resourcesLostToTypeDamage[damageType].ward = tempDamage >= 1 and tempDamage or nil
end
local esBypass = output[damageType.."EnergyShieldBypass"] / 100 or 0
local lifeHitPool = calcLifeHitPoolWithLossPrevention(life, output.Life, output.preventedLifeLoss, lifeLossBelowHalfPrevented)
local MoMEffect = m_min(output.sharedMindOverMatter + output[damageType.."MindOverMatter"], 100) / 100
local MoMPool = MoMEffect < 1 and m_min(lifeHitPool / (1 - MoMEffect) - lifeHitPool, mana) or mana
local lifePlusMoMHitPool = lifeHitPool + MoMPool
local esBypass = output[damageType.."EnergyShieldBypass"] / 100 or 0
local esPool = esPoolsRemaining[damageType]
if energyShield > 0 and not modDB:Flag(nil, "EnergyShieldProtectsMana") and esBypass < 1 then
local esPool = esBypass > 0 and m_min(lifePlusMoMHitPool / esBypass - lifePlusMoMHitPool, energyShield) or energyShield
local tempDamage = m_min(damageRemainder * (1 - esBypass), esPool)
esPoolRemaining = m_min(esPoolRemaining, esPool - tempDamage)
for damageType2, _ in pairs(damageTable) do
esPoolsRemaining[damageType2] = m_max(esPoolsRemaining[damageType2] - tempDamage, 0)
end
energyShield = energyShield - tempDamage
damageRemainder = damageRemainder - tempDamage
resourcesLostToTypeDamage[damageType].energyShield = tempDamage >= 1 and tempDamage or nil
elseif esBypass == 1 then
esPoolRemaining = 0
end
if MoMEffect > 0 and mana > 0 then
local MoMDamage = damageRemainder * MoMEffect
if MoMEffect > 0 then
local MoMDamage = m_ceil(damageRemainder * MoMEffect)
if modDB:Flag(nil, "EnergyShieldProtectsMana") and energyShield > 0 and esBypass < 1 then
local MoMEBPool = esBypass > 0 and m_min(MoMPool / esBypass - MoMPool, energyShield) or energyShield
local tempDamage = m_min(MoMDamage * (1 - esBypass), MoMEBPool)
esPoolRemaining = m_min(esPoolRemaining, MoMEBPool - tempDamage)
local tempDamage = m_ceil(m_min(MoMDamage * (1 - esBypass), esPool))
for damageType2, _ in pairs(damageTable) do
esPoolsRemaining[damageType2] = m_floor(m_max(esPoolsRemaining[damageType2] - tempDamage, 0))
end
energyShield = energyShield - tempDamage
damageRemainder = damageRemainder - tempDamage
MoMDamage = MoMDamage - tempDamage
resourcesLostToTypeDamage[damageType].energyShield = tempDamage >= 1 and tempDamage or nil
end
local tempDamage = m_min(MoMDamage, MoMPool)
MoMPoolRemaining = m_min(MoMPoolRemaining, MoMPool - tempDamage)
local tempDamage = m_ceil(m_min(MoMDamage, MoMPoolsRemaining[damageType]))
for damageType2, _ in pairs(damageTable) do
MoMPoolsRemaining[damageType2] = m_floor(m_max(MoMPoolsRemaining[damageType2] - tempDamage, 0))
end
mana = mana - tempDamage
damageRemainder = damageRemainder - tempDamage
resourcesLostToTypeDamage[damageType].mana = tempDamage >= 1 and tempDamage or nil
else
MoMPoolRemaining = 0
end
if output.preventedLifeLossTotal > 0 then
local halfLife = output.Life * 0.5
@@ -351,7 +372,14 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor)
resourcesLostToTypeDamage[damageType].overkill = damageRemainder >= 1 and damageRemainder or nil
end
end
local hitPoolRemaining = calcLifeHitPoolWithLossPrevention(life, output.Life, output.preventedLifeLoss, lifeLossBelowHalfPrevented) +
local MoMPoolRemaining = m_huge
local esPoolRemaining = m_huge
for damageType, _ in pairs(damageTable) do
MoMPoolRemaining = m_min(MoMPoolRemaining, MoMPoolsRemaining[damageType])
esPoolRemaining = m_min(esPoolRemaining, esPoolsRemaining[damageType])
end
local hitPoolRemaining = (life >= 1 and calcLifeHitPoolWithLossPrevention(life, output.Life, output.preventedLifeLoss, lifeLossBelowHalfPrevented) or 0) +
(MoMPoolRemaining ~= m_huge and MoMPoolRemaining or 0) + (esPoolRemaining ~= m_huge and esPoolRemaining or 0)
return {
@@ -2210,43 +2238,39 @@ function calcs.buildDefenceEstimations(env, actor)
output.OnlySharedMindOverMatter = false
output.AnySpecificMindOverMatter = false
output["sharedMindOverMatter"] = m_min(modDB:Sum("BASE", nil, "DamageTakenFromManaBeforeLife"), 100)
local function calcMoMEBPool(lifePool, MoMEffect, esBypass)
local mana = m_max(output.ManaUnreserved or 0, 0)
local maxMoMPool = MoMEffect < 1 and lifePool / (1 - MoMEffect) - lifePool or m_huge
local maxManaUsable = m_floor(m_min(mana, maxMoMPool))
local maxESUsable = modDB:Flag(nil, "EnergyShieldProtectsMana") and esBypass < 1 and
m_floor(m_min(
output.EnergyShieldRecoveryCap,
maxMoMPool * (1 - esBypass),
(lifePool + maxManaUsable) / (1 - (1 - esBypass) * MoMEffect) - (lifePool + maxManaUsable)
)) or 0
local manaUsed = m_floor(m_min(maxMoMPool - maxESUsable, maxManaUsable))
return lifePool + manaUsed + maxESUsable, maxManaUsable, manaUsed, maxESUsable
end
if output["sharedMindOverMatter"] > 0 then
output.OnlySharedMindOverMatter = true
local sourcePool = m_max(output.ManaUnreserved or 0, 0)
local sourceHitPool = sourcePool
local manatext = "unreserved mana"
local MindOverMatter = output["sharedMindOverMatter"] / 100
local esBypass = output.MinimumBypass / 100
if modDB:Flag(nil, "EnergyShieldProtectsMana") and esBypass < 1 then
manatext = manatext.." + non-bypassed energy shield"
if esBypass > 0 then
local manaProtected = m_min(sourcePool / esBypass - sourcePool, output.EnergyShieldRecoveryCap)
sourcePool = m_max(sourcePool - manaProtected, -output.LifeRecoverable) + m_min(sourcePool + output.LifeRecoverable, manaProtected) / esBypass
sourceHitPool = m_max(sourceHitPool - manaProtected, -output.LifeHitPool) + m_min(sourceHitPool + output.LifeHitPool, manaProtected) / esBypass
else
sourcePool = sourcePool + output.EnergyShieldRecoveryCap
sourceHitPool = sourcePool
end
end
local poolProtected = sourcePool / (output["sharedMindOverMatter"] / 100) * (1 - output["sharedMindOverMatter"] / 100)
local hitPoolProtected = sourceHitPool / (output["sharedMindOverMatter"] / 100) * (1 - output["sharedMindOverMatter"] / 100)
if output["sharedMindOverMatter"] >= 100 then
poolProtected = m_huge
output["sharedManaEffectiveLife"] = output.LifeRecoverable + sourcePool
output["sharedMoMHitPool"] = output.LifeHitPool + sourceHitPool
else
output["sharedManaEffectiveLife"] = m_max(output.LifeRecoverable - poolProtected, 0) + m_min(output.LifeRecoverable, poolProtected) / (1 - output["sharedMindOverMatter"] / 100)
output["sharedMoMHitPool"] = m_max(output.LifeHitPool - hitPoolProtected, 0) + m_min(output.LifeHitPool, hitPoolProtected) / (1 - output["sharedMindOverMatter"] / 100)
end
local sharedMoMPool, breakdownMaxMana, breakdownMana, breakdownES = calcMoMEBPool(output.LifeRecoverable, MindOverMatter, esBypass)
output["sharedManaEffectiveLife"] = sharedMoMPool
output["sharedMoMHitPool"] = calcMoMEBPool(output.LifeHitPool, MindOverMatter, esBypass)
if breakdown then
if output["sharedMindOverMatter"] then
local lifeProtected = (breakdownMana + breakdownES) / MindOverMatter - (breakdownMana + breakdownES)
breakdown["sharedMindOverMatter"] = {
s_format("Total life protected:"),
s_format("%d ^8(%s)", sourcePool, manatext),
s_format("/ %.2f ^8(portion taken from mana)", output["sharedMindOverMatter"] / 100),
s_format("x %.2f ^8(portion taken from life)", 1 - output["sharedMindOverMatter"] / 100),
s_format("= %d", poolProtected),
s_format("Effective life: %d", output["sharedManaEffectiveLife"])
s_format("Effective life from Mind over Matter:"),
s_format("%d life (%d life is protected)", output.LifeRecoverable, lifeProtected),
s_format("%d mana%s", breakdownMana, breakdownMana == breakdownMaxMana and "" or s_format(" (%d mana shadowed by energy shield)", breakdownMaxMana - breakdownMana)),
}
if modDB:Flag(nil, "EnergyShieldProtectsMana") then t_insert(breakdown["sharedMindOverMatter"], s_format("%d energy shield", breakdownES)) end
t_insert(breakdown["sharedMindOverMatter"], s_format("%d + %d %s= %d", output.LifeRecoverable, breakdownMana,
modDB:Flag(nil, "EnergyShieldProtectsMana") and s_format("+ %d ", breakdownES) or "", sharedMoMPool)
)
end
end
else
@@ -2256,44 +2280,28 @@ function calcs.buildDefenceEstimations(env, actor)
for _, damageType in ipairs(dmgTypeList) do
output[damageType.."MindOverMatter"] = m_min(modDB:Sum("BASE", nil, damageType.."DamageTakenFromManaBeforeLife"), 100 - output["sharedMindOverMatter"])
if output[damageType.."MindOverMatter"] > 0 or (output[damageType.."EnergyShieldBypass"] > output.MinimumBypass and output["sharedMindOverMatter"] > 0) then
local MindOverMatter = output[damageType.."MindOverMatter"] + output["sharedMindOverMatter"]
output.ehpSectionAnySpecificTypes = true
output.AnySpecificMindOverMatter = true
output.OnlySharedMindOverMatter = false
local sourcePool = m_max(output.ManaUnreserved or 0, 0)
local sourceHitPool = sourcePool
local manatext = "unreserved mana"
if modDB:Flag(nil, "EnergyShieldProtectsMana") and output[damageType.."EnergyShieldBypass"] < 100 then
manatext = manatext.." + non-bypassed energy shield"
if output[damageType.."EnergyShieldBypass"] > 0 then
local manaProtected = output.EnergyShieldRecoveryCap / (1 - output[damageType.."EnergyShieldBypass"] / 100) * (output[damageType.."EnergyShieldBypass"] / 100)
sourcePool = m_max(sourcePool - manaProtected, -output.LifeRecoverable) + m_min(sourcePool + output.LifeRecoverable, manaProtected) / (output[damageType.."EnergyShieldBypass"] / 100)
sourceHitPool = m_max(sourceHitPool - manaProtected, -output.LifeHitPool) + m_min(sourceHitPool + output.LifeHitPool, manaProtected) / (output[damageType.."EnergyShieldBypass"] / 100)
else
sourcePool = sourcePool + output.EnergyShieldRecoveryCap
sourceHitPool = sourcePool
end
end
local poolProtected = sourcePool / (MindOverMatter / 100) * (1 - MindOverMatter / 100)
local hitPoolProtected = sourceHitPool / (MindOverMatter / 100) * (1 - MindOverMatter / 100)
if MindOverMatter >= 100 then
poolProtected = m_huge
output[damageType.."ManaEffectiveLife"] = output.LifeRecoverable + sourcePool
output[damageType.."MoMHitPool"] = output.LifeHitPool + sourceHitPool
else
output[damageType.."ManaEffectiveLife"] = m_max(output.LifeRecoverable - poolProtected, 0) + m_min(output.LifeRecoverable, poolProtected) / (1 - MindOverMatter / 100)
output[damageType.."MoMHitPool"] = m_max(output.LifeHitPool - hitPoolProtected, 0) + m_min(output.LifeHitPool, hitPoolProtected) / (1 - MindOverMatter / 100)
end
local MindOverMatter = (output[damageType.."MindOverMatter"] + output["sharedMindOverMatter"]) / 100
local esBypass = output[damageType.."EnergyShieldBypass"] / 100
local typedMoMPool, breakdownMaxMana, breakdownMana, breakdownES = calcMoMEBPool(output.LifeRecoverable, MindOverMatter, esBypass)
output[damageType.."ManaEffectiveLife"] = typedMoMPool
output[damageType.."MoMHitPool"] = calcMoMEBPool(output.LifeHitPool, MindOverMatter, esBypass)
if breakdown then
if output[damageType.."MindOverMatter"] then
local lifeProtected = (breakdownMana + breakdownES) / MindOverMatter - (breakdownMana + breakdownES)
breakdown[damageType.."MindOverMatter"] = {
s_format("Total life protected:"),
s_format("%d ^8(%s)", sourcePool, manatext),
s_format("/ %.2f ^8(portion taken from mana)", MindOverMatter / 100),
s_format("x %.2f ^8(portion taken from life)", 1 - MindOverMatter / 100),
s_format("= %d", poolProtected),
s_format("Effective life: %d", output[damageType.."ManaEffectiveLife"])
s_format("Effective life from Mind over Matter:"),
s_format("%d life (%d life is protected)", output.LifeRecoverable, lifeProtected),
s_format("%d mana%s", breakdownMana, breakdownMana == breakdownMaxMana and "" or s_format(" (%d mana shadowed by energy shield)", breakdownMaxMana - breakdownMana)),
}
if modDB:Flag(nil, "EnergyShieldProtectsMana") then t_insert(breakdown[damageType.."MindOverMatter"], s_format("%d energy shield", breakdownES)) end
t_insert(breakdown[damageType.."MindOverMatter"], s_format("%d + %d %s= %d", output.LifeRecoverable, breakdownMana,
modDB:Flag(nil, "EnergyShieldProtectsMana") and s_format("+ %d ", breakdownES) or "", typedMoMPool)
)
end
end
else