diff --git a/spec/System/TestDefence_spec.lua b/spec/System/TestDefence_spec.lua index c8a4b23a57..a3a08d2d13 100644 --- a/spec/System/TestDefence_spec.lua +++ b/spec/System/TestDefence_spec.lua @@ -807,4 +807,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) \ No newline at end of file diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 87c0873ecf..0c94cd2ac6 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -214,8 +214,31 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) local LifeLossLostOverTime = poolTbl.LifeLossLostOverTime or 0 local LifeBelowHalfLossLostOverTime = poolTbl.LifeBelowHalfLossLostOverTime or 0 local overkillDamage = 0 - local MoMPoolRemaining = m_huge - local esPoolRemaining = m_huge + + 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 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, damage in pairs(damageTable) do local damageRemainder = damage @@ -260,36 +283,34 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) ward = ward - tempDamage damageRemainder = damageRemainder - tempDamage 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 - 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 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 - else - MoMPoolRemaining = 0 end if output.preventedLifeLossTotal > 0 then local halfLife = output.Life * 0.5 @@ -330,7 +351,14 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) end overkillDamage = overkillDamage + damageRemainder 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 { @@ -344,7 +372,7 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) damageTakenThatCanBeRecouped = damageTakenThatCanBeRecouped, LifeLossLostOverTime = m_ceil(LifeLossLostOverTime), LifeBelowHalfLossLostOverTime = m_ceil(LifeBelowHalfLossLostOverTime), - OverkillDamage = m_ceil(overkillDamage), + OverkillDamage = m_floor(overkillDamage), hitPoolRemaining = m_floor(hitPoolRemaining) } end @@ -2128,43 +2156,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 @@ -2174,44 +2198,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