Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions spec/System/TestDefence_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -588,4 +588,98 @@ describe("TestDefence", function()
assertClose(block.EffectiveBlockChance, 10)
assert.is_true(block.TotalEHP > base.TotalEHP)
end)

describe("damage taken from companion's life before you", function()
it("redirects damage to the configured companion life pool", function()
build.configTab.input.enemyIsBoss = "None"
build.configTab.input.customMods = ""
pob1and2Compat()
local baseMaxHit = build.calcsTab.calcsOutput.PhysicalMaximumHitTaken

build.configTab.input.customMods = "15% of Damage from Hits is taken from your Damageable Companion's Life before you"
build.configTab.input.TotalCompanionLife = 1000
pob1and2Compat()

local output = build.calcsTab.calcsOutput
assert.are.equals(15, output.CompanionAllyDamageMitigation)
assert.are.equals(1000, output.TotalCompanionLife)
assert.is_true(output.PhysicalMaximumHitTaken > baseMaxHit)

local totalTaken = takenHitFromTypeMaxHit("Physical")
local pools = poolsRemainingAfterTypeMaxHit("Physical")
local drained = 1000 - pools.AlliesTakenBeforeYou["companion"].remaining
assert.are.near(totalTaken * 0.15, drained, 1)
end)

it("stacks redirect sources additively", function()
build.configTab.input.enemyIsBoss = "None"
build.configTab.input.customMods = "\z
5% of Damage from Hits is taken from your Damageable Companion's Life before you\n\z
15% of Damage from Hits is taken from your Damageable Companion's Life before you\n\z
"
build.configTab.input.TotalCompanionLife = 100
pob1and2Compat()

assert.are.equals(20, build.calcsTab.calcsOutput.CompanionAllyDamageMitigation)
end)

it("scales the deflected-hits redirect by deflect chance", function()
build.configTab.input.enemyIsBoss = "None"
build.configTab.input.customMods = "\z
10% of Damage from Deflected Hits is taken from Damageable Companion's Life before you\n\z
+1000 to Deflection Rating\n\z
"
build.configTab.input.TotalCompanionLife = 500
pob1and2Compat()

local output = build.calcsTab.calcsOutput
assert.is_true(output.DeflectChance > 0)
assert.are.near(10 * output.DeflectChance / 100, output.CompanionAllyDamageMitigation, 0.001)
end)

it("sums companion life automatically and applies Loyalty's redirect and life penalty", function()
build.skillsTab:PasteSocketGroup("Companion: Lightless Abomination 20/0 1")
runCallback("OnFrame")
local unsupportedLife = build.calcsTab.calcsEnv.minion.output.Life

newBuild()
build.skillsTab:PasteSocketGroup("Companion: Lightless Abomination 20/0 1\nLoyalty 1/0 1")
runCallback("OnFrame")

local output = build.calcsTab.calcsOutput
local companionLife = build.calcsTab.calcsEnv.minion.output.Life
assert.are.equals(10, output.CompanionAllyDamageMitigation)
assert.are.equals(companionLife, output.TotalCompanionLife)
assert.are.near(unsupportedLife * 0.7, companionLife, 1)
end)

it("sums companion life when the companion is not the main skill", function()
build.skillsTab:PasteSocketGroup("Companion: Lightless Abomination 20/0 1\nLoyalty 1/0 1")
runCallback("OnFrame")
local mainSkillCompanionLife = build.calcsTab.calcsOutput.TotalCompanionLife

newBuild()
build.skillsTab:PasteSocketGroup("Quarterstaff Strike 20/0 1")
build.skillsTab:PasteSocketGroup("Companion: Lightless Abomination 20/0 1\nLoyalty 1/0 1")
build.mainSocketGroup = 1
runCallback("OnFrame")

local output = build.calcsTab.calcsOutput
assert.are.equals(10, output.CompanionAllyDamageMitigation)
assert.are.near(mainSkillCompanionLife, output.TotalCompanionLife, 1)
end)

it("has no effect with no companions and no config override", function()
build.configTab.input.enemyIsBoss = "None"
build.configTab.input.customMods = ""
pob1and2Compat()
local baseMaxHit = build.calcsTab.calcsOutput.PhysicalMaximumHitTaken

build.configTab.input.customMods = "15% of Damage from Hits is taken from your Damageable Companion's Life before you"
pob1and2Compat()

assert.are.equals(0, build.calcsTab.calcsOutput.TotalCompanionLife)
assert.are.equals(baseMaxHit, build.calcsTab.calcsOutput.PhysicalMaximumHitTaken)
end)
end)
end)
8 changes: 4 additions & 4 deletions src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1538,6 +1538,7 @@ c["13% increased Skill Speed"]={{[1]={flags=0,keywordFlags=0,name="Speed",type="
c["13% increased Spell damage for each 200 total Mana you have Spent Recently"]={{[1]={[1]={div=200,type="Multiplier",var="ManaSpentRecently"},flags=2,keywordFlags=0,name="Damage",type="INC",value=13}},nil}
c["13% increased maximum Life"]={{[1]={flags=0,keywordFlags=0,name="Life",type="INC",value=13}},nil}
c["13% increased maximum Mana"]={{[1]={flags=0,keywordFlags=0,name="Mana",type="INC",value=13}},nil}
c["13% of Damage from Deflected Hits is taken from Damageable Companion's Life before you"]={{[1]={flags=0,keywordFlags=0,name="takenFromCompanionBeforeYouFromDeflected",type="BASE",value=13}},nil}
c["13% reduced Attack Speed"]={{[1]={flags=1,keywordFlags=0,name="Speed",type="INC",value=-13}},nil}
c["13% reduced Attack and Cast Speed"]={{[1]={flags=0,keywordFlags=0,name="Speed",type="INC",value=-13}},nil}
c["13% reduced Charges per use"]={{[1]={flags=0,keywordFlags=0,name="FlaskChargesUsed",type="INC",value=-13}},nil}
Expand Down Expand Up @@ -1736,8 +1737,8 @@ c["15% less maximum Mana"]={{[1]={flags=0,keywordFlags=0,name="Mana",type="MORE"
c["15% more Damage against Enemies affected by Blood Boils"]={{[1]={flags=0,keywordFlags=0,name="Damage",type="MORE",value=15}}," against Enemies affected by Blood Boils "}
c["15% more Damage against Enemies affected by Blood Boils Grants Skill: Blood Boil"]={{[1]={[1]={includeTransfigured=true,skillName="Blood Boil",type="SkillName"},flags=0,keywordFlags=0,name="Damage",type="MORE",value=15}}," against Enemies affected by Blood Boils Grants Skill:"}
c["15% more Maximum Life"]={{[1]={flags=0,keywordFlags=0,name="Life",type="MORE",value=15}},nil}
c["15% of Damage from Deflected Hits is taken from Damageable Companion's Life before you"]={{[1]={flags=0,keywordFlags=0,name="Damage",type="BASE",value=15}}," from Deflected Hits is taken from Damageable Companion's Life before you "}
c["15% of Damage from Hits is taken from your Damageable Companion's Life before you"]={{[1]={flags=0,keywordFlags=0,name="Damage",type="BASE",value=15}}," from Hits is taken from your Damageable Companion's Life before you "}
c["15% of Damage from Deflected Hits is taken from Damageable Companion's Life before you"]={{[1]={flags=0,keywordFlags=0,name="takenFromCompanionBeforeYouFromDeflected",type="BASE",value=15}},nil}
c["15% of Damage from Hits is taken from your Damageable Companion's Life before you"]={{[1]={flags=0,keywordFlags=0,name="takenFromCompanionBeforeYou",type="BASE",value=15}},nil}
c["15% of Damage is taken from Mana before Life"]={{[1]={flags=0,keywordFlags=0,name="DamageTakenFromManaBeforeLife",type="BASE",value=15}},nil}
c["15% of Damage taken Recouped as Life"]={{[1]={flags=0,keywordFlags=0,name="LifeRecoup",type="BASE",value=15}},nil}
c["15% of Damage taken from Deflected Hits Recouped as Life"]={{[1]={flags=0,keywordFlags=0,name="DamageTaken",type="BASE",value=15}}," from Deflected Hits Recouped as Life "}
Expand Down Expand Up @@ -3074,8 +3075,7 @@ c["5% increased Stun Threshold"]={{[1]={flags=0,keywordFlags=0,name="StunThresho
c["5% increased Stun Threshold per 25 Tribute"]={{[1]={[1]={actor="parent",div=25,stat="Tribute",type="PerStat"},flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=5}},nil}
c["5% increased effect of Archon Buffs on you"]={{[1]={flags=0,keywordFlags=0,name="LocalEffect",type="INC",value=5}}," of Archon Buffs on you "}
c["5% increased total Power counted by Warcries"]={{[1]={flags=0,keywordFlags=0,name="WarcryPower",type="INC",value=5}},nil}
c["5% of Damage from Hits is taken from your Damageable Companion's Life before you"]={{[1]={flags=0,keywordFlags=0,name="Damage",type="BASE",value=5}}," from Hits is taken from your Damageable Companion's Life before you "}
c["5% of Damage from Hits is taken from your Damageable Companion's Life before you 20% increased Armour, Evasion and Energy Shield while your Companion is in your Presence"]={{[1]={[1]={type="Condition",var="CompanionInPresence"},flags=0,keywordFlags=0,name="Damage",type="BASE",value=5}}," from Hits is taken from your Damageable Companion's Life before you 20% increased Armour, Evasion and Energy Shield "}
c["5% of Damage from Hits is taken from your Damageable Companion's Life before you"]={{[1]={flags=0,keywordFlags=0,name="takenFromCompanionBeforeYou",type="BASE",value=5}},nil}
c["5% of Damage taken Recouped as Life"]={{[1]={flags=0,keywordFlags=0,name="LifeRecoup",type="BASE",value=5}},nil}
c["5% of Damage taken bypasses Energy Shield"]={{[1]={flags=0,keywordFlags=0,name="PhysicalEnergyShieldBypass",type="BASE",value=5},[2]={flags=0,keywordFlags=0,name="LightningEnergyShieldBypass",type="BASE",value=5},[3]={flags=0,keywordFlags=0,name="ColdEnergyShieldBypass",type="BASE",value=5},[4]={flags=0,keywordFlags=0,name="FireEnergyShieldBypass",type="BASE",value=5},[5]={flags=0,keywordFlags=0,name="ChaosEnergyShieldBypass",type="BASE",value=5}},nil}
c["5% of Maximum Life Converted to Energy Shield"]={{[1]={flags=0,keywordFlags=0,name="LifeConvertToEnergyShield",type="BASE",value=5}},nil}
Expand Down
3 changes: 3 additions & 0 deletions src/Data/SkillStatMap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2521,6 +2521,9 @@ return {
["companions_are_gigantic"] = {
mod("MinionModifier", "LIST", { mod = flag("Gigantic") }),
},
["companion_takes_%_damage_before_you_from_support"] = {
mod("takenFromCompanionBeforeYou", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", unscalable = true }),
},
["minion_damage_+%_final_per_different_elemental_ailment_on_target"] = {
mod("MinionModifier", "LIST", { mod = mod("Damage", "MORE", nil, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Electrocuted" }) }),
mod("MinionModifier", "LIST", { mod = mod("Damage", "MORE", nil, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Frozen" }) }),
Expand Down
43 changes: 43 additions & 0 deletions src/Modules/CalcDefence.lua
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,9 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor)
if output.TotalRadianceSentinelLife then
alliesTakenBeforeYou["radianceSentinel"] = { remaining = output.TotalRadianceSentinelLife, percent = output.RadianceSentinelAllyDamageMitigation / 100 }
end
if output.TotalCompanionLife then
alliesTakenBeforeYou["companion"] = { remaining = output.TotalCompanionLife, percent = output.CompanionAllyDamageMitigation / 100 }
end
if output.AlliedEnergyShield then
alliesTakenBeforeYou["soulLink"] = { remaining = output.AlliedEnergyShield, percent = output.SoulLinkMitigation / 100 }
end
Expand Down Expand Up @@ -698,6 +701,9 @@ local function incomingDamageBreakdown(breakdownTable, poolsRemaining, output)
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.TotalCompanionLife and output.TotalCompanionLife > 0 then
t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Companion Life ^7(%d remaining)", output.TotalCompanionLife - poolsRemaining.AlliesTakenBeforeYou["companion"].remaining, poolsRemaining.AlliesTakenBeforeYou["companion"].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
Expand Down Expand Up @@ -2921,6 +2927,31 @@ function calcs.buildDefenceEstimations(env, actor)
output["TotalRadianceSentinelLife"] = modDB:Sum("BASE", nil, "TotalRadianceSentinelLife")
end

-- from companions
local companionMitigation = modDB:Sum("BASE", nil, "takenFromCompanionBeforeYou")
local companionMitigationFromDeflected = modDB:Sum("BASE", nil, "takenFromCompanionBeforeYouFromDeflected")
output["CompanionAllyDamageMitigation"] = companionMitigation + companionMitigationFromDeflected * (output.DeflectChance or 0) / 100
if output["CompanionAllyDamageMitigation"] ~= 0 then
output["TotalCompanionLife"] = modDB:Override(nil, "TotalCompanionLife") or modDB:Sum("BASE", nil, "TotalCompanionLife")
if breakdown then
breakdown["TotalCompanionLife"] = { }
if modDB:Override(nil, "TotalCompanionLife") then
t_insert(breakdown["TotalCompanionLife"], s_format("%d ^8(from config)", output["TotalCompanionLife"]))
else
for _, companion in ipairs(actor.companionLifeList or { }) do
t_insert(breakdown["TotalCompanionLife"], s_format("%d ^8(%s)", companion.life, companion.name))
end
end
if companionMitigationFromDeflected ~= 0 then
breakdown["CompanionAllyDamageMitigation"] = {
s_format("%d%% ^8(taken from hits)", companionMitigation),
s_format("+ %d%% x %.2f ^8(taken from deflected hits, scaled by deflect chance)", companionMitigationFromDeflected, (output.DeflectChance or 0) / 100),
s_format("= %.1f%%", output["CompanionAllyDamageMitigation"]),
}
end
end
end

-- from Allied Energy Shield
output["SoulLinkMitigation"] = modDB:Sum("BASE", nil, "TakenFromParentESBeforeYou")
if output["SoulLinkMitigation"] ~= 0 then
Expand Down Expand Up @@ -3023,6 +3054,9 @@ function calcs.buildDefenceEstimations(env, actor)
if output.TotalRadianceSentinelLife then
alliesTakenBeforeYou["radianceSentinel"] = { remaining = output.TotalRadianceSentinelLife, percent = output.RadianceSentinelAllyDamageMitigation / 100 }
end
if output.TotalCompanionLife then
alliesTakenBeforeYou["companion"] = { remaining = output.TotalCompanionLife, percent = output.CompanionAllyDamageMitigation / 100 }
end
if output.AlliedEnergyShield then
alliesTakenBeforeYou["soulLink"] = { remaining = output.AlliedEnergyShield, percent = output.SoulLinkMitigation / 100 }
end
Expand Down Expand Up @@ -3588,6 +3622,15 @@ function calcs.buildDefenceEstimations(env, actor)
local poolProtected = output["TotalRadianceSentinelLife"] / (output["RadianceSentinelAllyDamageMitigation"] / 100) * (1 - output["RadianceSentinelAllyDamageMitigation"] / 100)
output[damageType.."TotalHitPool"] = m_max(output[damageType.."TotalHitPool"] - poolProtected, 0) + m_min(output[damageType.."TotalHitPool"], poolProtected) / (1 - output["RadianceSentinelAllyDamageMitigation"] / 100)
end
-- companions
if output["TotalCompanionLife"] and output["TotalCompanionLife"] > 0 then
if output["CompanionAllyDamageMitigation"] >= 100 then
output[damageType.."TotalHitPool"] = output[damageType.."TotalHitPool"] + output["TotalCompanionLife"]
else
local poolProtected = output["TotalCompanionLife"] / (output["CompanionAllyDamageMitigation"] / 100) * (1 - output["CompanionAllyDamageMitigation"] / 100)
output[damageType.."TotalHitPool"] = m_max(output[damageType.."TotalHitPool"] - poolProtected, 0) + m_min(output[damageType.."TotalHitPool"], poolProtected) / (1 - output["CompanionAllyDamageMitigation"] / 100)
end
end
-- soul link
if output["AlliedEnergyShield"] and output["AlliedEnergyShield"] > 0 then
local poolProtected = output["AlliedEnergyShield"] / (output["SoulLinkMitigation"] / 100) * (1 - output["SoulLinkMitigation"] / 100)
Expand Down
Loading
Loading