From 8ec25d0f260a5d53088d07648c7e4cf952073a25 Mon Sep 17 00:00:00 2001 From: Edvinas Date: Wed, 9 Apr 2025 16:09:49 +0300 Subject: [PATCH 1/2] Add resource lost information to enemy damage breakdown --- src/Modules/CalcDefence.lua | 275 ++++++++++++++++++++++++++---------- 1 file changed, 197 insertions(+), 78 deletions(-) diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 046ddb05fc..7f5018bc16 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -405,7 +405,8 @@ function calcs.takenHitFromDamage(rawDamage, damageType, actor) local takenFlat = output[damageConvertedType.."takenFlat"] if convertPercent > 0 or takenFlat ~= 0 then local convertedDamage = rawDamage * convertPercent / 100 - local reducedDamage = round(m_max(convertedDamage * damageMitigationMultiplierForType(convertedDamage, damageConvertedType) + takenFlat, 0) * output[damageConvertedType .."AfterReductionTakenHitMulti"]) * (1 - output["VaalArcticArmourMitigation"]) + local vaalArctic = m_min(-modDB:Sum("MORE", nil, "VaalArcticArmourMitigation") / 100, 1) + local reducedDamage = round(m_max(convertedDamage * damageMitigationMultiplierForType(convertedDamage, damageConvertedType) + takenFlat, 0) * output[damageConvertedType .."AfterReductionTakenHitMulti"]) * (1 - vaalArctic) receivedDamageSum = receivedDamageSum + reducedDamage damages[damageConvertedType] = (reducedDamage > 0 or convertPercent > 0) and reducedDamage or nil end @@ -436,7 +437,7 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) alliesTakenBeforeYou["frostShield"] = { remaining = output.FrostShieldLife, percent = output.FrostShieldDamageMitigation / 100 } end if output.TotalSpectreLife then - alliesTakenBeforeYou["specters"] = { remaining = output.TotalSpectreLife, percent = output.SpectreAllyDamageMitigation / 100 } + alliesTakenBeforeYou["spectres"] = { remaining = output.TotalSpectreLife, percent = output.SpectreAllyDamageMitigation / 100 } end if output.TotalTotemLife then alliesTakenBeforeYou["totems"] = { remaining = output.TotalTotemLife, percent = output.TotemAllyDamageMitigation / 100 } @@ -481,6 +482,7 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) local LifeLossLostOverTime = poolTbl.LifeLossLostOverTime or 0 local LifeBelowHalfLossLostOverTime = poolTbl.LifeBelowHalfLossLostOverTime or 0 local overkillDamage = 0 + local resourcesLostToTypeDamage = { Physical = { }, Lightning = { }, Cold = { }, Fire = { }, Chaos = { } } local MoMPoolRemaining = m_huge local esPoolRemaining = m_huge @@ -488,12 +490,13 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) for _, damageType in ipairs(dmgTypeList) do local damageRemainder = damageTable[damageType] if damageRemainder then - for _, allyValues in pairs(alliesTakenBeforeYou) do + for ally, allyValues in pairs(alliesTakenBeforeYou) do if not allyValues.damageType or allyValues.damageType == damageType then if allyValues.remaining > 0 then local tempDamage = m_min(damageRemainder * allyValues.percent, allyValues.remaining) allyValues.remaining = allyValues.remaining - tempDamage damageRemainder = damageRemainder - tempDamage + resourcesLostToTypeDamage[damageType][ally] = tempDamage >= 1 and tempDamage or nil end end end @@ -503,31 +506,37 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) local tempDamage = m_min(damageRemainder, aegis[damageType]) aegis[damageType] = aegis[damageType] - tempDamage damageRemainder = damageRemainder - tempDamage + resourcesLostToTypeDamage[damageType].aegis = tempDamage >= 1 and tempDamage or nil end if isElemental[damageType] and aegis.sharedElemental > 0 then local tempDamage = m_min(damageRemainder, aegis.sharedElemental) aegis.sharedElemental = aegis.sharedElemental - tempDamage damageRemainder = damageRemainder - tempDamage + resourcesLostToTypeDamage[damageType].sharedElementalAegis = tempDamage >= 1 and tempDamage or nil end if aegis.shared > 0 then local tempDamage = m_min(damageRemainder, aegis.shared) aegis.shared = aegis.shared - tempDamage damageRemainder = damageRemainder - tempDamage + resourcesLostToTypeDamage[damageType].sharedAegis = tempDamage >= 1 and tempDamage or nil end if guard[damageType] > 0 then local tempDamage = m_min(damageRemainder * output[damageType.."GuardAbsorbRate"] / 100, guard[damageType]) guard[damageType] = guard[damageType] - tempDamage damageRemainder = damageRemainder - tempDamage + resourcesLostToTypeDamage[damageType].guard = tempDamage >= 1 and tempDamage or nil end if guard.shared > 0 then local tempDamage = m_min(damageRemainder * output.sharedGuardAbsorbRate / 100, guard.shared) guard.shared = guard.shared - tempDamage damageRemainder = damageRemainder - tempDamage + resourcesLostToTypeDamage[damageType].sharedGuard = tempDamage >= 1 and tempDamage or nil end if ward > 0 then local tempDamage = m_min(damageRemainder * (1 - (modDB:Sum("BASE", nil, "WardBypass") or 0) / 100), ward) ward = ward - tempDamage damageRemainder = damageRemainder - tempDamage + resourcesLostToTypeDamage[damageType].ward = tempDamage >= 1 and tempDamage or nil end damageRemaindersBeforeES[damageType] = damageRemainder > 0 and damageRemainder or nil end @@ -548,6 +557,7 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) esPoolRemaining = m_min(esPoolRemaining, MoMEBPool - tempDamage * esDamageTypeMultiplier) energyShield = energyShield - tempDamage * esDamageTypeMultiplier damageRemainder = damageRemainder - tempDamage + resourcesLostToTypeDamage[damageType].energyShield = tempDamage >= 1 and tempDamage * esDamageTypeMultiplier or nil end if MoMEffect > 0 and mana > 0 then local MoMDamage = damageRemainder * MoMEffect @@ -555,6 +565,7 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) MoMPoolRemaining = m_min(MoMPoolRemaining, MoMPool - tempDamage) mana = mana - tempDamage damageRemainder = damageRemainder - tempDamage + resourcesLostToTypeDamage[damageType].mana = tempDamage >= 1 and tempDamage or nil else MoMPoolRemaining = 0 end @@ -576,6 +587,8 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) damageRemainder = damageRemainder - damageToSplit LifeLossLostOverTime = LifeLossLostOverTime + preventedLoss life = life - lostLife + resourcesLostToTypeDamage[damageType].life = lostLife + resourcesLostToTypeDamage[damageType].lifeLossPrevented = preventedLoss if life <= halfLife then local unspecificallyLowLifePreventedDamage = damageRemainder * preventPercent LifeLossLostOverTime = LifeLossLostOverTime + unspecificallyLowLifePreventedDamage @@ -583,22 +596,28 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) local specificallyLowLifePreventedDamage = damageRemainder * preventBelowHalfPercent LifeBelowHalfLossLostOverTime = LifeBelowHalfLossLostOverTime + specificallyLowLifePreventedDamage damageRemainder = damageRemainder - specificallyLowLifePreventedDamage + resourcesLostToTypeDamage[damageType].lifeLossPrevented = resourcesLostToTypeDamage[damageType].lifeLossPrevented + unspecificallyLowLifePreventedDamage + specificallyLowLifePreventedDamage end + resourcesLostToTypeDamage[damageType].lifeLossPrevented = resourcesLostToTypeDamage[damageType].lifeLossPrevented >= 1 and resourcesLostToTypeDamage[damageType].lifeLossPrevented or nil else local tempDamage = damageRemainder * output.preventedLifeLoss / 100 LifeLossLostOverTime = LifeLossLostOverTime + tempDamage damageRemainder = damageRemainder - tempDamage + resourcesLostToTypeDamage[damageType].lifeLossPrevented = tempDamage >= 1 and tempDamage or nil end end if life > 0 then local tempDamage = m_min(damageRemainder, life) life = life - tempDamage damageRemainder = damageRemainder - tempDamage + resourcesLostToTypeDamage[damageType].life = (resourcesLostToTypeDamage[damageType].life or 0) + (tempDamage > 0 and tempDamage or 0) end overkillDamage = overkillDamage + damageRemainder + resourcesLostToTypeDamage[damageType].overkill = damageRemainder >= 1 and damageRemainder or nil end end - local hitPoolRemaining = life + (MoMPoolRemaining ~= m_huge and MoMPoolRemaining or 0) + (esPoolRemaining ~= m_huge and esPoolRemaining or 0) + local hitPoolRemaining = calcLifeHitPoolWithLossPrevention(life, output.Life, output.preventedLifeLoss, lifeLossBelowHalfPrevented) + + (MoMPoolRemaining ~= m_huge and MoMPoolRemaining or 0) + (esPoolRemaining ~= m_huge and esPoolRemaining or 0) return { AlliesTakenBeforeYou = alliesTakenBeforeYou, @@ -612,10 +631,76 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) LifeLossLostOverTime = LifeLossLostOverTime, LifeBelowHalfLossLostOverTime = LifeBelowHalfLossLostOverTime, OverkillDamage = overkillDamage, - hitPoolRemaining = hitPoolRemaining + hitPoolRemaining = m_floor(hitPoolRemaining), + resourcesLostToTypeDamage = resourcesLostToTypeDamage } end +---Inserts breakdown of resources drained by a hit +---@param breakdownTable table table to insert items to +---@param poolsRemaining table remaining pools after running reducePoolsByDamage on damage to beak down +---@param output table must already contain things like guard, aegis, ally life... +---@return table breakdownTable with drained resource list +local function incomingDamageBreakdown(breakdownTable, poolsRemaining, output) + --region Breakdown inserts + if output.FrostShieldLife and output.FrostShieldLife > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Frost Shield Life ^7(%d remaining)", output.FrostShieldLife - poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining, poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining)) + end + if output.TotalSpectreLife and output.TotalSpectreLife > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Spectre Life ^7(%d remaining)", output.TotalSpectreLife - poolsRemaining.AlliesTakenBeforeYou["spectres"].remaining, poolsRemaining.AlliesTakenBeforeYou["spectres"].remaining)) + end + if output.TotalTotemLife and output.TotalTotemLife > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Totem Life ^7(%d remaining)", output.TotalTotemLife - poolsRemaining.AlliesTakenBeforeYou["totems"].remaining, poolsRemaining.AlliesTakenBeforeYou["totems"].remaining)) + end + if output.TotalVaalRejuvenationTotemLife and output.TotalVaalRejuvenationTotemLife > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Vaal Rejuvenation Totem Life ^7(%d remaining)", output.TotalVaalRejuvenationTotemLife - poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining, poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining)) + end + if output.TotalRadianceSentinelLife and output.TotalRadianceSentinelLife > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Sentinel of Radiance Life ^7(%d remaining)", output.TotalRadianceSentinelLife - poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining, poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining)) + end + if output.AlliedEnergyShield and output.AlliedEnergyShield > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Allied Energy shield ^7(%d remaining)", output.AlliedEnergyShield - poolsRemaining.AlliesTakenBeforeYou["soulLink"].remaining, poolsRemaining.AlliesTakenBeforeYou["soulLink"].remaining)) + end + for _, damageType in ipairs(dmgTypeList) do + if poolsRemaining.resourcesLostToTypeDamage[damageType].aegis then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."%s Aegis charge ^7(%d remaining)", poolsRemaining.resourcesLostToTypeDamage[damageType].aegis, damageType, poolsRemaining.Aegis[damageType])) + end + end + if output.sharedElementalAegis and output.sharedElementalAegis ~= poolsRemaining.Aegis.sharedElemental then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Elemental Aegis charge ^7(%d remaining)", output.sharedElementalAegis - poolsRemaining.Aegis.sharedElemental, poolsRemaining.Aegis.sharedElemental)) + end + if output.sharedAegis and output.sharedAegis > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Shared Aegis charge ^7(%d remaining)", output.sharedAegis - poolsRemaining.Aegis.shared, poolsRemaining.Aegis.shared)) + end + for _, damageType in ipairs(dmgTypeList) do + if poolsRemaining.resourcesLostToTypeDamage[damageType].guard then + t_insert(breakdownTable, s_format("\n\t%d "..colorCodes.SCOURGE.."%s Guard charge ^7(%d remaining)", poolsRemaining.resourcesLostToTypeDamage[damageType].guard, damageType, poolsRemaining.Guard[damageType])) + end + end + if output.sharedGuardAbsorb and output.sharedGuardAbsorb > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.SCOURGE.."Shared Guard charge ^7(%d remaining)", output.sharedGuardAbsorb - poolsRemaining.Guard.shared, poolsRemaining.Guard.shared)) + end + if output.Ward and output.Ward > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.WARD.."Ward", output.Ward)) + end + if output.EnergyShieldRecoveryCap ~= poolsRemaining.EnergyShield and output.EnergyShieldRecoveryCap and output.EnergyShieldRecoveryCap > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.ES.."Energy Shield ^7(%d remaining)", output.EnergyShieldRecoveryCap - poolsRemaining.EnergyShield, poolsRemaining.EnergyShield)) + end + if output.ManaUnreserved ~= poolsRemaining.Mana and output.ManaUnreserved and output.ManaUnreserved > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.MANA.."Mana ^7(%d remaining)", output.ManaUnreserved - poolsRemaining.Mana, poolsRemaining.Mana)) + end + if poolsRemaining.LifeLossLostOverTime + poolsRemaining.LifeBelowHalfLossLostOverTime > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.LIFE.."Life ^7Loss Prevented", poolsRemaining.LifeLossLostOverTime + poolsRemaining.LifeBelowHalfLossLostOverTime)) + end + t_insert(breakdownTable, s_format("\t%d "..colorCodes.LIFE.."Life ^7(%d remaining)", output.LifeRecoverable - poolsRemaining.Life, poolsRemaining.Life)) + if poolsRemaining.OverkillDamage >= 1 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.NEGATIVE.."Overkill damage", poolsRemaining.OverkillDamage)) + end + --endregion + + return breakdownTable +end + -- Performs all ingame and related defensive calculations function calcs.defence(env, actor) local modDB = actor.modDB @@ -2267,18 +2352,6 @@ function calcs.buildDefenceEstimations(env, actor) if takenMult ~= 1 or takenFlat ~= 0 or spellSuppressMult ~= 1 or impaleDamage ~= 0 then t_insert(breakdown[damageType.."TakenHitMult"], s_format("= %.3f", output[damageType.."TakenHitMult"])) end - breakdown[damageType.."TakenHit"] = { - s_format("Final %s Damage taken:", damageType), - s_format("%.1f incoming damage", damage), - s_format("x %.3f damage mult", output[damageType.."TakenHitMult"]), - s_format("= %.1f", output[damageType.."TakenHit"]), - } - t_insert(breakdown["totalTakenHit"].rowList, { - type = s_format("%s", damageType), - incoming = s_format("%.1f incoming damage", damage), - mult = s_format("x %.3f damage mult", output[damageType.."TakenHitMult"] ), - value = s_format("%d", output[damageType.."TakenHit"]), - }) if output.AnyTakenReflect then breakdown[damageType.."TakenReflectMult"] = { s_format("Resistance: %.3f", 1 - resist / 100), @@ -2667,7 +2740,7 @@ function calcs.buildDefenceEstimations(env, actor) } end - -- from specters + -- from spectres output["SpectreAllyDamageMitigation"] = modDB:Sum("BASE", nil, "takenFromSpectresBeforeYou") if output["SpectreAllyDamageMitigation"] ~= 0 then output["TotalSpectreLife"] = modDB:Sum("BASE", nil, "TotalSpectreLife") @@ -2780,7 +2853,7 @@ function calcs.buildDefenceEstimations(env, actor) alliesTakenBeforeYou["frostShield"] = { remaining = output.FrostShieldLife, percent = output.FrostShieldDamageMitigation / 100 } end if output.TotalSpectreLife then - alliesTakenBeforeYou["specters"] = { remaining = output.TotalSpectreLife, percent = output.SpectreAllyDamageMitigation / 100 } + alliesTakenBeforeYou["spectres"] = { remaining = output.TotalSpectreLife, percent = output.SpectreAllyDamageMitigation / 100 } end if output.TotalTotemLife then alliesTakenBeforeYou["totems"] = { remaining = output.TotalTotemLife, percent = output.TotemAllyDamageMitigation / 100 } @@ -3475,65 +3548,9 @@ function calcs.buildDefenceEstimations(env, actor) t_insert(breakdown[maxHitCurType], s_format("/ %.2f ^8(modifiers to enemy damage)", enemyDamageMult)) end t_insert(breakdown[maxHitCurType], s_format("= %.0f ^8maximum survivable enemy damage%s", finalMaxHit, useConversionSmoothing and " (approximate)" or "")) - - local poolsRemaining = calcs.reducePoolsByDamage(nil, takenDamages, actor) - - t_insert(breakdown[maxHitCurType], s_format("^8Such a hit would drain the following:")) - if output.FrostShieldLife and output.FrostShieldLife > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Frost Shield Life ^7(%d remaining)", output.FrostShieldLife - poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining, poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining)) - end - if output.TotalSpectreLife and output.TotalSpectreLife > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Total Spectre Life ^7(%d remaining)", output.TotalSpectreLife - poolsRemaining.AlliesTakenBeforeYou["specters"].remaining, poolsRemaining.AlliesTakenBeforeYou["specters"].remaining)) - end - if output.TotalTotemLife and output.TotalTotemLife > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Total Totem Life ^7(%d remaining)", output.TotalTotemLife - poolsRemaining.AlliesTakenBeforeYou["totems"].remaining, poolsRemaining.AlliesTakenBeforeYou["totems"].remaining)) - end - if output.TotalVaalRejuvenationTotemLife and output.TotalVaalRejuvenationTotemLife > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Total Vaal Rejuvenation Totem Life ^7(%d remaining)", output.TotalVaalRejuvenationTotemLife - poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining, poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining)) - end - if output.TotalRadianceSentinelLife and output.TotalRadianceSentinelLife > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Total Sentinel of Radiance Life ^7(%d remaining)", output.TotalRadianceSentinelLife - poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining, poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining)) - end - if output.AlliedEnergyShield and output.AlliedEnergyShield > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Total Allied Energy shield ^7(%d remaining)", output.AlliedEnergyShield - poolsRemaining.AlliesTakenBeforeYou["soulLink"].remaining, poolsRemaining.AlliesTakenBeforeYou["soulLink"].remaining)) - end - if output.sharedAegis and output.sharedAegis > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Shared Aegis charge ^7(%d remaining)", output.sharedAegis - poolsRemaining.Aegis.shared, poolsRemaining.Aegis.shared)) - end - local receivedElemental = false - for takenType in pairs(takenDamages) do - receivedElemental = receivedElemental or isElemental[takenType] - if output[takenType.."Aegis"] and output[takenType.."Aegis"] > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."%s Aegis charge ^7(%d remaining)", output[takenType.."Aegis"] - poolsRemaining.Aegis[takenType], takenType, poolsRemaining.Aegis[takenType])) - end - end - if receivedElemental and output.sharedElementalAegis and output.sharedElementalAegis > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Elemental Aegis charge ^7(%d remaining)", output.sharedElementalAegis - poolsRemaining.Aegis.sharedElemental, poolsRemaining.Aegis.sharedElemental)) - end - if output.sharedGuardAbsorb and output.sharedGuardAbsorb > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.SCOURGE.."Shared Guard charge ^7(%d remaining)", output.sharedGuardAbsorb - poolsRemaining.Guard.shared, poolsRemaining.Guard.shared)) - end - for takenType in pairs(takenDamages) do - if output[takenType.."GuardAbsorb"] and output[takenType.."GuardAbsorb"] > 0 then - t_insert(breakdown[maxHitCurType], s_format("\n\t%d "..colorCodes.SCOURGE.."%s Guard charge ^7(%d remaining)", output[takenType.."GuardAbsorb"] - poolsRemaining.Guard[takenType], takenType, poolsRemaining.Guard[takenType])) - end - end - if output.Ward and output.Ward > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.WARD.."Ward", output.Ward)) - end - if output.EnergyShieldRecoveryCap ~= poolsRemaining.EnergyShield and output.EnergyShieldRecoveryCap and output.EnergyShieldRecoveryCap > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.ES.."Energy Shield ^7(%d remaining)", output.EnergyShieldRecoveryCap - poolsRemaining.EnergyShield, poolsRemaining.EnergyShield)) - end - if output.ManaUnreserved ~= poolsRemaining.Mana and output.ManaUnreserved and output.ManaUnreserved > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.MANA.."Mana ^7(%d remaining)", output.ManaUnreserved - poolsRemaining.Mana, poolsRemaining.Mana)) - end - if poolsRemaining.LifeLossLostOverTime + poolsRemaining.LifeBelowHalfLossLostOverTime > 0 then - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.LIFE.."Life ^7Loss Prevented", poolsRemaining.LifeLossLostOverTime + poolsRemaining.LifeBelowHalfLossLostOverTime)) - end - t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.LIFE.."Life ^7(%d remaining)", output.LifeRecoverable - poolsRemaining.Life, poolsRemaining.Life)) - if poolsRemaining.OverkillDamage >= 1 then - t_insert(breakdown[maxHitCurType], s_format("\t%d Overkill damage", poolsRemaining.OverkillDamage)) - end + + t_insert(breakdown[maxHitCurType], "^8Such a hit would drain the following resources:") + breakdown[maxHitCurType] = incomingDamageBreakdown(breakdown[maxHitCurType], calcs.reducePoolsByDamage(nil, takenDamages, actor), output) end end @@ -3967,4 +3984,106 @@ function calcs.buildDefenceEstimations(env, actor) end end end + + --region Add breakdown to enemy incoming damage + if breakdown then + local takenHit = { } + for _, damageType in ipairs(dmgTypeList) do + takenHit[damageType] = output[damageType.."TakenHit"] > 0 and output[damageType.."TakenHit"] or nil + t_insert(breakdown["totalTakenHit"].rowList, { + type = s_format("%s", damageType), + incoming = s_format("%.1f incoming damage", output[damageType.."TakenDamage"]), + mult = s_format("x %.3f damage mult", output[damageType.."TakenHitMult"] ), + value = s_format("%d", m_ceil(output[damageType.."TakenHit"])), + }) + end + local poolsRemaining = calcs.reducePoolsByDamage(nil, takenHit, actor) + + t_insert(breakdown["totalTakenHit"], "Such a hit would drain the following resources:") + breakdown["totalTakenHit"] = incomingDamageBreakdown(breakdown["totalTakenHit"], poolsRemaining, output) + + for _, damageType in ipairs(dmgTypeList) do + local breakdownTable = {} + local resourcesLost = poolsRemaining.resourcesLostToTypeDamage[damageType] + local resourcesLostSum = 0 + + t_insert(breakdownTable, s_format("Final %s Damage taken:", damageType)) + t_insert(breakdownTable, s_format("%.1f incoming damage", output[damageType.."TakenDamage"])) + t_insert(breakdownTable, s_format("x %.3f damage mult", output[damageType.."TakenHitMult"])) + t_insert(breakdownTable, s_format("= %.1f", output[damageType.."TakenHit"])) + + t_insert(breakdownTable, "This part of the hit drains the following resources:") + if resourcesLost.frostShield then + resourcesLostSum = resourcesLostSum + resourcesLost.frostShield + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Frost Shield Life", resourcesLost.frostShield)) + end + if resourcesLost.spectres then + resourcesLostSum = resourcesLostSum + resourcesLost.spectres + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Spectre Life", resourcesLost.spectres)) + end + if resourcesLost.totems then + resourcesLostSum = resourcesLostSum + resourcesLost.totems + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Totem Life", resourcesLost.totems)) + end + if resourcesLost.vaalRejuvenationTotems then + resourcesLostSum = resourcesLostSum + resourcesLost.vaalRejuvenationTotems + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Vaal Rejuvenation Totem Life", resourcesLost.vaalRejuvenationTotems)) + end + if resourcesLost.radianceSentinel then + resourcesLostSum = resourcesLostSum + resourcesLost.radianceSentinel + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Sentinel of Radiance Life", resourcesLost.radianceSentinel)) + end + if resourcesLost.soulLink then + resourcesLostSum = resourcesLostSum + resourcesLost.soulLink + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Allied Energy shield", resourcesLost.soulLink)) + end + if resourcesLost.aegis then + resourcesLostSum = resourcesLostSum + resourcesLost.aegis + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."%s Aegis charge", resourcesLost.aegis, damageType)) + end + if resourcesLost.sharedElementalAegis then + resourcesLostSum = resourcesLostSum + resourcesLost.sharedElementalAegis + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Elemental Aegis charge", resourcesLost.sharedElementalAegis)) + end + if resourcesLost.sharedAegis then + resourcesLostSum = resourcesLostSum + resourcesLost.sharedAegis + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Shared Aegis charge", resourcesLost.sharedAegis)) + end + if resourcesLost.guard then + resourcesLostSum = resourcesLostSum + resourcesLost.guard + t_insert(breakdownTable, s_format("\n\t%d "..colorCodes.SCOURGE.."%s Guard charge", resourcesLost.guard, damageType)) + end + if resourcesLost.sharedGuard then + resourcesLostSum = resourcesLostSum + resourcesLost.sharedGuard + t_insert(breakdownTable, s_format("\t%d "..colorCodes.SCOURGE.."Shared Guard charge", resourcesLost.sharedGuard)) + end + if resourcesLost.ward then + resourcesLostSum = resourcesLostSum + resourcesLost.ward + t_insert(breakdownTable, s_format("\t%d "..colorCodes.WARD.."Ward", resourcesLost.ward)) + end + if resourcesLost.energyShield then + resourcesLostSum = resourcesLostSum + resourcesLost.energyShield + t_insert(breakdownTable, s_format("\t%d "..colorCodes.ES.."Energy Shield", resourcesLost.energyShield)) + end + if resourcesLost.mana then + resourcesLostSum = resourcesLostSum + resourcesLost.mana + t_insert(breakdownTable, s_format("\t%d "..colorCodes.MANA.."Mana", resourcesLost.mana)) + end + if resourcesLost.lifeLossPrevented and resourcesLost.lifeLossPrevented > 0 then + resourcesLostSum = resourcesLostSum + resourcesLost.lifeLossPrevented + t_insert(breakdownTable, s_format("\t%d "..colorCodes.LIFE.."Life ^7Loss Prevented", resourcesLost.lifeLossPrevented)) + end + if resourcesLost.life and resourcesLost.life > 0 then + resourcesLostSum = resourcesLostSum + resourcesLost.life + t_insert(breakdownTable, s_format("\t%d "..colorCodes.LIFE.."Life", resourcesLost.life)) + end + if resourcesLost.overkill then + resourcesLostSum = resourcesLostSum + resourcesLost.overkill + t_insert(breakdownTable, s_format("\t%d "..colorCodes.NEGATIVE.."Overkill damage", resourcesLost.overkill)) + end + t_insert(breakdownTable, s_format("\t^8(%d total)", resourcesLostSum)) + breakdown[damageType.."TakenHit"] = breakdownTable + end + end + --endregion end From 011437f3e2979ed8cb5c1ca5a0fd5d5d7e7ae58e Mon Sep 17 00:00:00 2001 From: Edvinas Date: Wed, 9 Apr 2025 16:14:44 +0300 Subject: [PATCH 2/2] Add resource lost information to enemy damage breakdown --- src/Modules/CalcDefence.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 7f5018bc16..c9d2bf8c0d 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -4063,7 +4063,7 @@ function calcs.buildDefenceEstimations(env, actor) end if resourcesLost.energyShield then resourcesLostSum = resourcesLostSum + resourcesLost.energyShield - t_insert(breakdownTable, s_format("\t%d "..colorCodes.ES.."Energy Shield", resourcesLost.energyShield)) + t_insert(breakdownTable, s_format("\t%d "..colorCodes.ES.."Energy Shield%s", resourcesLost.energyShield, damageType == "Chaos" and "^8 (ES takes double damage from chaos)" or "")) end if resourcesLost.mana then resourcesLostSum = resourcesLostSum + resourcesLost.mana