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
56 changes: 56 additions & 0 deletions spec/System/TestDefence_spec.lua.rej
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
diff a/spec/System/TestDefence_spec.lua b/spec/System/TestDefence_spec.lua (rejected hunks)
@@ -608,6 +608,30 @@ describe("TestDefence", function()
assert.is_true(block.TotalEHP > base.TotalEHP)
end)

+ describe("damage taken from spectres' life before you", function()
+ it("sums spectre life automatically", function()
+ build.skillsTab:PasteSocketGroup("Spectre: Lightless Abomination 20/0 1")
+ build.configTab:BuildModList()
+ build.configTab.modList:NewMod("TakenFromSpectresBeforeYou", "BASE", 15, "Test")
+ build.calcsTab:BuildOutput()
+
+ local output = build.calcsTab.mainOutput
+ assert.are.equals(15, output.SpectreAllyDamageMitigation)
+ local spectreLife = build.calcsTab.mainEnv.player.spectreLifeList[1].life
+ assert.are.equals(spectreLife, output.TotalSpectreLife)
+ end)
+
+ it("uses configured spectre life as an override", function()
+ build.skillsTab:PasteSocketGroup("Spectre: Lightless Abomination 20/0 1")
+ build.configTab.input.TotalSpectreLife = 1000
+ build.configTab:BuildModList()
+ build.configTab.modList:NewMod("TakenFromSpectresBeforeYou", "BASE", 15, "Test")
+ build.calcsTab:BuildOutput()
+
+ assert.are.equals(1000, build.calcsTab.mainOutput.TotalSpectreLife)
+ end)
+ 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"
@@ -688,6 +712,23 @@ describe("TestDefence", function()
assert.are.near(mainSkillCompanionLife, output.TotalCompanionLife, 1)
end)

+ it("stacks Loyalty's redirect from multiple companion skills", function()
+ build.skillsTab:PasteSocketGroup("Companion: Lightless Abomination 20/0 1\nLoyalty 1/0 1")
+ build.skillsTab:PasteSocketGroup("Companion: Lightless Moray 20/0 1\nLoyalty 1/0 1")
+ runCallback("OnFrame")
+
+ assert.are.equals(20, build.calcsTab.calcsOutput.CompanionAllyDamageMitigation)
+ end)
+
+ it("does not count global companion redirect once per companion skill", function()
+ build.configTab.input.customMods = "5% of Damage from Hits is taken from your Damageable Companion's Life before you"
+ build.skillsTab:PasteSocketGroup("Companion: Lightless Abomination 20/0 1")
+ build.skillsTab:PasteSocketGroup("Companion: Lightless Abomination 20/0 1")
+ pob1and2Compat()
+
+ assert.are.equals(5, build.calcsTab.calcsOutput.CompanionAllyDamageMitigation)
+ end)
+
it("has no effect with no companions and no config override", function()
build.configTab.input.enemyIsBoss = "None"
build.configTab.input.customMods = ""
39 changes: 39 additions & 0 deletions src/Data/ModCache.lua.rej
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
diff a/src/Data/ModCache.lua b/src/Data/ModCache.lua (rejected hunks)
@@ -1541,7 +1541,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% 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}
@@ -1740,8 +1740,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="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 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 "}
@@ -2151,7 +2151,7 @@ c["20% more Damage against Heavy Stunned Enemies with Maces"]={{[1]={[1]={actor=
c["20% more Life Cost of Skills"]={{[1]={flags=0,keywordFlags=0,name="LifeCost",type="MORE",value=20}},nil}
c["20% more Stun Buildup with Critical Hits"]={{[1]={[1]={type="Condition",var="CriticalStrike"},flags=0,keywordFlags=0,name="EnemyHeavyStunBuildup",type="MORE",value=20}},nil}
c["20% of Cold Damage taken as Fire Damage"]={{[1]={flags=0,keywordFlags=0,name="ColdDamageTakenAsFire",type="BASE",value=20}},nil}
-c["20% of Damage from Hits is taken from your nearest Totem's Life before you"]={{[1]={[1]={type="Condition",var="HaveTotem"},flags=0,keywordFlags=0,name="takenFromTotemsBeforeYou",type="BASE",value=20}},nil}
+c["20% of Damage from Hits is taken from your nearest Totem's Life before you"]={{[1]={[1]={type="Condition",var="HaveTotem"},flags=0,keywordFlags=0,name="TakenFromTotemsBeforeYou",type="BASE",value=20}},nil}
c["20% of Damage is taken from Mana before Life"]={{[1]={flags=0,keywordFlags=0,name="DamageTakenFromManaBeforeLife",type="BASE",value=20}},nil}
c["20% of Damage taken Recouped as Life"]={{[1]={flags=0,keywordFlags=0,name="LifeRecoup",type="BASE",value=20}},nil}
c["20% of Damage taken Recouped as Mana"]={{[1]={flags=0,keywordFlags=0,name="ManaRecoup",type="BASE",value=20}},nil}
@@ -3083,7 +3083,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="takenFromCompanionBeforeYou",type="BASE",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="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}
10 changes: 10 additions & 0 deletions src/Data/SkillStatMap.lua.rej
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
diff a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua (rejected hunks)
@@ -2528,7 +2528,7 @@ return {
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 }),
+ 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" }) }),
9 changes: 9 additions & 0 deletions src/Modules/CalcActiveSkill.lua
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,15 @@ function calcs.buildActiveSkillModList(env, activeSkill)
if tag.type == "GlobalEffect" then
effectType = tag.effectType
effectName = tag.effectName or activeGrantedEffect.name
if activeSkill.minion and activeSkill.minion.minionData then
if effectName:find("{0}", 1, true) then
effectName = effectName:gsub("{0}", activeSkill.minion.minionData.name)
elseif activeGrantedEffect.minionList and effectName:match("^Companion") then
effectName = "Companion: "..activeSkill.minion.minionData.name
elseif activeGrantedEffect.minionList and effectName:match("^Spectre") then
effectName = "Spectre: "..activeSkill.minion.minionData.name
end
end
effectTag = tag
break
end
Expand Down
39 changes: 39 additions & 0 deletions src/Modules/CalcDefence.lua.rej
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
diff a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua (rejected hunks)
@@ -2924,13 +2924,23 @@ function calcs.buildDefenceEstimations(env, actor)
end

-- from spectres
- output["SpectreAllyDamageMitigation"] = modDB:Sum("BASE", nil, "takenFromSpectresBeforeYou")
+ output["SpectreAllyDamageMitigation"] = modDB:Sum("BASE", nil, "TakenFromSpectresBeforeYou")
if output["SpectreAllyDamageMitigation"] ~= 0 then
- output["TotalSpectreLife"] = modDB:Sum("BASE", nil, "TotalSpectreLife")
+ output["TotalSpectreLife"] = modDB:Override(nil, "TotalSpectreLife") or modDB:Sum("BASE", nil, "TotalSpectreLife")
+ if breakdown then
+ breakdown["TotalSpectreLife"] = { }
+ if modDB:Override(nil, "TotalSpectreLife") then
+ t_insert(breakdown["TotalSpectreLife"], s_format("%d ^8(from config)", output["TotalSpectreLife"]))
+ else
+ for _, spectre in ipairs(actor.spectreLifeList or { }) do
+ t_insert(breakdown["TotalSpectreLife"], s_format("%d ^8(%s)", spectre.life, spectre.name))
+ end
+ end
+ end
end

-- from totems
- output["TotemAllyDamageMitigation"] = modDB:Sum("BASE", nil, "takenFromTotemsBeforeYou")
+ output["TotemAllyDamageMitigation"] = modDB:Sum("BASE", nil, "TakenFromTotemsBeforeYou")
if output["TotemAllyDamageMitigation"] ~= 0 then
output["TotalTotemLife"] = modDB:Sum("BASE", nil, "TotalTotemLife")
end
@@ -2948,8 +2958,8 @@ function calcs.buildDefenceEstimations(env, actor)
end

-- from companions
- local companionMitigation = modDB:Sum("BASE", nil, "takenFromCompanionBeforeYou")
- local companionMitigationFromDeflected = modDB:Sum("BASE", nil, "takenFromCompanionBeforeYouFromDeflected")
+ 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")
112 changes: 107 additions & 5 deletions src/Modules/CalcPerform.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,112 @@ function calcs.actionSpeedMod(actor)
return actionSpeedMod
end

-- Initialises a minion's modifier database with its base stats (life, defences, resists),
-- monster type mods, tamed beast mods and player-granted mods, for the given owning skill
local function initMinionModDB(env, activeSkill)
local modDB = env.modDB
local minion = activeSkill.minion
minion.modDB.multipliers["Level"] = minion.level
calcs.initModDB(env, minion.modDB)
local baseLife = minion.lifeTable[minion.level] * minion.minionData.life
if minion.hostile then
baseLife = baseLife * (env.data.mapLevelLifeMult[env.enemyLevel] or 1)
end
minion.modDB:NewMod("Life", "BASE", m_floor(baseLife), "Base")
if minion.minionData.energyShield then
minion.modDB:NewMod("LifeConvertToEnergyShield", "BASE", minion.minionData.energyShield * 100, "Base")
end
--Armour formula is math.floor((10 + 2 * level) * 1.067 ^ level)
minion.modDB:NewMod("Armour", "BASE", round(env.data.monsterArmourTable[minion.level] * (minion.minionData.armour or 1)), "Base")
--Evasion formula is math.floor((50 + 16 * level + 16 * level * (MonsterType.Evasion / 100)) * (1.0212 ^ level)
minion.modDB:NewMod("Evasion", "BASE", round(env.data.monsterEvasionTable[minion.level] * (minion.minionData.evasion or 1)), "Base")
if modDB:Flag(nil, "MinionAccuracyEqualsAccuracy") then
minion.modDB:NewMod("Accuracy", "BASE", calcLib.val(modDB, "Accuracy") + calcLib.val(modDB, "Dex") * (modDB:Override(nil, "DexAccBonusOverride") or data.misc.AccuracyPerDexBase), "Player")
else
-- Minions no longer need Accuracy as of patch 0.3.0
minion.modDB:NewMod("CannotBeEvaded", "FLAG", 1, "Minion Attacks always hit")
end
minion.modDB:NewMod("CritMultiplier", "BASE", env.data.monsterConstants["base_critical_hit_damage_bonus"] + env.data.playerMinionIntrinsicStats["base_critical_hit_damage_bonus"], "Base")
minion.modDB:NewMod("FireResist", "BASE", minion.minionData.fireResist, "Base")
minion.modDB:NewMod("ColdResist", "BASE", minion.minionData.coldResist, "Base")
minion.modDB:NewMod("LightningResist", "BASE", minion.minionData.lightningResist, "Base")
minion.modDB:NewMod("ChaosResist", "BASE", minion.minionData.chaosResist, "Base")
minion.modDB:NewMod("ProjectileCount", "BASE", 1, "Base")
minion.modDB:NewMod("PhysicalHeavyStunBuildup", "MORE", data.monsterConstants["physical_hit_damage_stun_multiplier_+%_final_from_ot"], "Physical Damage")
minion.modDB:NewMod("EnemyHeavyStunBuildup", "MORE", data.monsterConstants["melee_hit_damage_stun_multiplier_+%_final_from_ot"], "Melee Damage", ModFlag.Melee)
minion.modDB:NewMod("Damage", "MORE", minion.hiddenDamageFixup * 100, "Hidden Level Scaling")
for _, mod in ipairs(minion.minionData.modList) do
minion.modDB:AddMod(mod)
end
for _, mod in ipairs(activeSkill.extraSkillModList) do
minion.modDB:AddMod(mod)
end
if env.talismanModList then
-- Adding mods provided by "Necromantic Talisman"
minion.modDB:AddList(env.talismanModList)
end
if env.theIronMass and minion.type == "RaisedSkeleton" then
minion.modDB:AddList(env.theIronMass)
end
if activeSkill.skillData.minionUseBowAndQuiver then
if env.player.weaponData1.type == "Bow" then
minion.modDB:AddList(env.player.itemList["Weapon 1"].slotModList[1])
end
if env.player.itemList["Weapon 2"] and env.player.itemList["Weapon 2"].type == "Quiver" then
local quiverEffectMod = env.player.modDB:Sum("INC", nil, "EffectOfBonusesFromQuiver") / 100
if quiverEffectMod > 0 then
for _, mod in ipairs(env.player.itemList["Weapon 2"].modList) do
local modCopy = copyTable(mod)
modCopy.source = "Many Sources:" .. tostring(quiverEffectMod * 100) .. "% Quiver Bonus Effect"
minion.modDB:ScaleAddMod(modCopy, quiverEffectMod)
end
end
end
end
if minion.itemSet or minion.uses then
for slotName, slot in pairs(env.build.itemsTab.slots) do
if minion.uses[slotName] then
local item
if minion.itemSet then
if slot.weaponSet == 1 and minion.itemSet.useSecondWeaponSet then
slotName = slotName .. " Swap"
end
item = env.build.itemsTab.items[minion.itemSet[slotName].selItemId]
else
item = env.player.itemList[slotName]
end
if item then
minion.itemList[slotName] = item
minion.modDB:AddList(item.modList or item.slotModList[slot.slotNum])
end
end
end
end
if modDB:Flag(nil, "StrengthAddedToMinions") then
minion.modDB:NewMod("Str", "BASE", round(calcLib.val(modDB, "Str")), "Player")
end
if modDB:Flag(nil, "StrengthAddedToCompanions") and activeSkill.skillTypes[SkillType.Companion] then
minion.modDB:NewMod("Str", "BASE", round(calcLib.val(modDB, "Str")), "Sturdy Ally")
end
if modDB:Flag(nil, "HalfStrengthAddedToMinions") then
minion.modDB:NewMod("Str", "BASE", round(calcLib.val(modDB, "Str") * 0.5), "Player")
end
if modDB:Flag(nil, "DexterityAddedToMinions") then
minion.modDB:NewMod("Dex", "BASE", round(calcLib.val(modDB, "Dex")), "Dead can Dance")
end
if modDB:Flag(nil, "DexterityAddedToCompanions") and activeSkill.skillTypes[SkillType.Companion] then
minion.modDB:NewMod("Dex", "BASE", round(calcLib.val(modDB, "Dex")), "Tandem Assault")
end
end

local function addMinionModifiers(modList, skillCfg, minion)
for _, value in ipairs(modList:List(skillCfg, "MinionModifier")) do
if not value.type or minion.type == value.type then
minion.modDB:AddMod(value.mod)
end
end
end

-- Finalises the environment and performs the stat calculations:
-- 1. Merges keystone modifiers
-- 2. Initialises minion skills
Expand Down Expand Up @@ -3195,11 +3301,7 @@ function calcs.perform(env, skipEHP)
modDB.multipliers["BuffOnSelf"] = (modDB.multipliers["BuffOnSelf"] or 0) + 1
end
if env.minion then
for _, value in ipairs(modList:List(env.player.mainSkill.skillCfg, "MinionModifier")) do
if not value.type or env.minion.type == value.type then
env.minion.modDB:AddMod(value.mod)
end
end
addMinionModifiers(modList, env.player.mainSkill.skillCfg, env.minion)
end
end
if env.minion then
Expand Down
Loading