From 0c9d00a3b18e8bff782a35130d45686a4757ecd9 Mon Sep 17 00:00:00 2001 From: komarukun <144673064+komarukun@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:36:40 +0200 Subject: [PATCH 1/5] Calculate actor resistances before life --- src/Modules/CalcDefence.lua | 70 ++++++++++++++++++++----------------- src/Modules/CalcPerform.lua | 2 ++ 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index b9a5060600..939f1f8562 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -257,40 +257,9 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) } end --- Performs all ingame and related defensive calculations -function calcs.defence(env, actor) +function calcs.resistances(actor) local modDB = actor.modDB - local enemyDB = actor.enemy.modDB local output = actor.output - local breakdown = actor.breakdown - - local condList = modDB.conditions - - -- Action Speed - output.ActionSpeedMod = calcs.actionSpeedMod(actor) - - -- Armour defence types for conditionals - for _, slot in pairs({"Helmet","Gloves","Boots","Body Armour","Weapon 2","Weapon 3"}) do - local armourData = actor.itemList[slot] and actor.itemList[slot].armourData - if armourData then - wardBase = armourData.Ward or 0 - if wardBase > 0 then - output["WardOn"..slot] = wardBase - end - energyShieldBase = armourData.EnergyShield or 0 - if energyShieldBase > 0 then - output["EnergyShieldOn"..slot] = energyShieldBase - end - armourBase = armourData.Armour or 0 - if armourBase > 0 then - output["ArmourOn"..slot] = armourBase - end - evasionBase = armourData.Evasion or 0 - if evasionBase > 0 then - output["EvasionOn"..slot] = evasionBase - end - end - end -- Resistances output["PhysicalResist"] = 0 @@ -402,6 +371,43 @@ function calcs.defence(env, actor) } end end +end + +-- Performs all ingame and related defensive calculations +function calcs.defence(env, actor) + local modDB = actor.modDB + local enemyDB = actor.enemy.modDB + local output = actor.output + local breakdown = actor.breakdown + + local condList = modDB.conditions + + -- Action Speed + output.ActionSpeedMod = calcs.actionSpeedMod(actor) + + -- Armour defence types for conditionals + for _, slot in pairs({"Helmet","Gloves","Boots","Body Armour","Weapon 2","Weapon 3"}) do + local armourData = actor.itemList[slot] and actor.itemList[slot].armourData + if armourData then + wardBase = armourData.Ward or 0 + if wardBase > 0 then + output["WardOn"..slot] = wardBase + end + energyShieldBase = armourData.EnergyShield or 0 + if energyShieldBase > 0 then + output["EnergyShieldOn"..slot] = energyShieldBase + end + armourBase = armourData.Armour or 0 + if armourBase > 0 then + output["ArmourOn"..slot] = armourBase + end + evasionBase = armourData.Evasion or 0 + if evasionBase > 0 then + output["EvasionOn"..slot] = evasionBase + end + end + end + -- Block output.BlockChanceMax = modDB:Sum("BASE", nil, "BlockChanceMax") diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 7290eb86fa..24553d1dd9 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -1418,6 +1418,7 @@ function calcs.perform(env, fullDPSSkipEHP) -- Calculate attributes and life/mana pools doActorAttribsConditions(env, env.player) + calcs.resistances(env.player) doActorLifeMana(env.player) if env.minion then for _, value in ipairs(env.player.mainSkill.skillModList:List(env.player.mainSkill.skillCfg, "MinionModifier")) do @@ -2798,6 +2799,7 @@ function calcs.perform(env, fullDPSSkipEHP) calcs.offence(env, env.player, env.player.mainSkill) if env.minion then + calcs.resistances(env.minion) doActorLifeMana(env.minion) doActorLifeManaReservation(env.minion) From b652454db464239292b95da400dcc920bc1ca0d0 Mon Sep 17 00:00:00 2001 From: komarukun <144673064+komarukun@users.noreply.github.com> Date: Tue, 12 Sep 2023 14:01:19 +0200 Subject: [PATCH 2/5] Add support for Fleshcrafter minion life convert --- src/Data/ModCache.lua | 3 +-- src/Modules/Build.lua | 3 +++ src/Modules/CalcPerform.lua | 12 ++++++++++-- src/Modules/ModParser.lua | 3 +++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index 05ca4d52e6..2165fa6595 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -8647,8 +8647,7 @@ c["Minimum Power Charges equal to Maximum while stationary"]={{[1]={[1]={type="C c["Minion Instability"]={{[1]={flags=0,keywordFlags=0,name="Keystone",type="LIST",value="Minion Instability"}},nil} c["Minion Life is increased by their Overcapped Fire Resistance"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={div=1,stat="FireResistOverCap",type="PerStat"},flags=0,keywordFlags=0,name="Life",type="INC",value=1}}}},nil} c["Minions Attacks Overwhelm 20% Physical Damage Reduction"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={skillType=1,type="SkillType"},flags=0,keywordFlags=0,name="EnemyPhysicalDamageReduction",type="BASE",value=-20}}}},nil} -c["Minions Convert 2% of their Maximum Life to Maximum Energy Shield per 1% Chaos Resistance they have"]={nil,"Convert 2% of their Maximum Life to Maximum Energy Shield per 1% Chaos Resistance they have "} -c["Minions Convert 2% of their Maximum Life to Maximum Energy Shield per 1% Chaos Resistance they have Chaos Damage taken does not bypass Minions' Energy Shield"]={nil,"Convert 2% of their Maximum Life to Maximum Energy Shield per 1% Chaos Resistance they have Chaos Damage taken does not bypass Minions' Energy Shield "} +c["Minions Convert 2% of their Maximum Life to Maximum Energy Shield per 1% Chaos Resistance they have"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={div=1,stat="ChaosResist",type="PerStat"},flags=0,keywordFlags=0,name="LifeConvertToEnergyShield",type="BASE",value=2}}}},nil} c["Minions Explode when reduced to Low Life, dealing 33% of their Life as Fire Damage to surrounding Enemies"]={{[1]={flags=0,keywordFlags=0,name="ExtraMinionSkill",type="LIST",value={skillId="MinionInstability"}}},nil} c["Minions Leech 0.4% of Damage as Life"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="DamageLifeLeech",type="BASE",value=0.4}}}},nil} c["Minions Leech 1% of Damage as Life"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="DamageLifeLeech",type="BASE",value=1}}}},nil} diff --git a/src/Modules/Build.lua b/src/Modules/Build.lua index 88b6cbccb9..10c5c4de93 100644 --- a/src/Modules/Build.lua +++ b/src/Modules/Build.lua @@ -1444,6 +1444,9 @@ function buildMode:AddDisplayStatList(statList, actor) if actor.output.VixensTooMuchCastSpeedWarn then InsertIfNew(self.controls.warnings.lines, "You may have too much cast speed or too little cooldown reduction to effectively use Vixen's Curse replacement") end + if actor.minionData and actor.output.MinionLifeConvertedWarning then + InsertIfNew(self.controls.warnings.lines, "Your ".. actor.minionData.name .." minion has converted too much life to energy shield") + end end function buildMode:InsertItemWarnings() diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 24553d1dd9..65205a0c55 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -78,7 +78,13 @@ local function doActorLifeMana(actor) local inc = modDB:Sum("INC", nil, "Life") local more = modDB:More(nil, "Life") local conv = modDB:Sum("BASE", nil, "LifeConvertToEnergyShield") - output.Life = m_max(round(base * (1 + inc/100) * more * (1 - conv/100)), 1) + -- Minions can have all of their life pool converted (ex: Fleshcrafter) + if actor.minionData and conv >= 100 then + output.Life = 0 + output.MinionLifeConvertedWarning = conv + else + output.Life = m_max(round(base * (1 + inc/100) * more * (1 - conv/100)), 1) + end if breakdown then if inc ~= 0 or more ~= 1 or conv ~= 0 then breakdown.Life = { } @@ -2804,7 +2810,9 @@ function calcs.perform(env, fullDPSSkipEHP) doActorLifeManaReservation(env.minion) calcs.defence(env, env.minion) - if not fullDPSSkipEHP then -- main.build.calcsTab.input.showMinion and -- should be disabled unless "calcsTab.input.showMinion" is true + -- main.build.calcsTab.input.showMinion and should be disabled unless "calcsTab.input.showMinion" is true + -- Skip defense estimations if minions have 0 life + if not fullDPSSkipEHP and not env.minion.output.MinionLifeConvertedWarning then calcs.buildDefenceEstimations(env, env.minion) end calcs.offence(env, env.minion, env.minion.mainSkill) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 83a94b43cc..3078eb143b 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -3673,6 +3673,9 @@ local specialModList = { }, ["chaos damage t?a?k?e?n? ?does not bypass minions' energy shield"] = { mod("MinionModifier", "LIST", { mod = flag("ChaosNotBypassEnergyShield") }) }, ["while minions have energy shield, their hits ignore monster elemental resistances"] = { mod("MinionModifier", "LIST", { mod = flag("IgnoreElementalResistances", { type = "StatThreshold", stat = "EnergyShield", threshold = 1 }) }) }, + ["minions convert (%d+)%% of their maximum life to maximum energy shield per (%d+)%% chaos resistance they have"] = function(num, _, div) return { + mod("MinionModifier", "LIST", { mod = mod("LifeConvertToEnergyShield", "BASE", num, { type = "PerStat", stat = "ChaosResist", div = tonumber(div) }) }) + } end, ["summoned arbalists' projectiles pierce (%d+) additional targets"] = function(num) return { mod("MinionModifier", "LIST", { mod = mod("PierceCount", "BASE", num) }, { type = "SkillName", skillName = "Summon Arbalists" }) } end, ["summoned arbalists' projectiles fork"] = { mod("MinionModifier", "LIST", { mod = flag("ForkOnce") }, { type = "SkillName", skillName = "Summon Arbalists" }), From 2b6a600a7391e2159e52db3458ad7660b5d0f5c0 Mon Sep 17 00:00:00 2001 From: komarukun <144673064+komarukun@users.noreply.github.com> Date: Tue, 12 Sep 2023 14:02:20 +0200 Subject: [PATCH 3/5] Fix typo in minion mod --- src/Modules/ModParser.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 3078eb143b..c127c163ee 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -3619,7 +3619,7 @@ local specialModList = { }, ["minions deal no non%-lightning damage"] = { mod("MinionModifier", "LIST", { mod = flag("DealNoPhysical") }), - mod("MinionModifier", "LIST", { mod = flag("DealNoLCold") }), + mod("MinionModifier", "LIST", { mod = flag("DealNoCold") }), mod("MinionModifier", "LIST", { mod = flag("DealNoFire") }), mod("MinionModifier", "LIST", { mod = flag("DealNoChaos") }), }, From 961c13ea1c2fcc030cb395e655a57a0c01c4714b Mon Sep 17 00:00:00 2001 From: komarukun <144673064+komarukun@users.noreply.github.com> Date: Tue, 12 Sep 2023 14:29:16 +0200 Subject: [PATCH 4/5] Move player resistance calculations after auras --- src/Modules/CalcPerform.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 65205a0c55..a83f086c97 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -1424,7 +1424,6 @@ function calcs.perform(env, fullDPSSkipEHP) -- Calculate attributes and life/mana pools doActorAttribsConditions(env, env.player) - calcs.resistances(env.player) doActorLifeMana(env.player) if env.minion then for _, value in ipairs(env.player.mainSkill.skillModList:List(env.player.mainSkill.skillCfg, "MinionModifier")) do @@ -2796,6 +2795,7 @@ function calcs.perform(env, fullDPSSkipEHP) end -- Defence/offence calculations + calcs.resistances(env.player) calcs.defence(env, env.player) if not fullDPSSkipEHP then calcs.buildDefenceEstimations(env, env.player) @@ -2805,6 +2805,7 @@ function calcs.perform(env, fullDPSSkipEHP) calcs.offence(env, env.player, env.player.mainSkill) if env.minion then + -- Minions require resistance calculations before life for uniques like Formless Inferno and Fleshcrafter calcs.resistances(env.minion) doActorLifeMana(env.minion) doActorLifeManaReservation(env.minion) From f98c2cbf7f314701cd6c50f184f4374d8e0d4b3b Mon Sep 17 00:00:00 2001 From: komarukun <144673064+komarukun@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:12:25 +0200 Subject: [PATCH 5/5] Move resistance calculation back to calcs.defence --- src/Modules/CalcDefence.lua | 1 + src/Modules/CalcPerform.lua | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 939f1f8562..cbe8521848 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -408,6 +408,7 @@ function calcs.defence(env, actor) end end + calcs.resistances(actor) -- Block output.BlockChanceMax = modDB:Sum("BASE", nil, "BlockChanceMax") diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index a83f086c97..ca5256484b 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -2795,7 +2795,6 @@ function calcs.perform(env, fullDPSSkipEHP) end -- Defence/offence calculations - calcs.resistances(env.player) calcs.defence(env, env.player) if not fullDPSSkipEHP then calcs.buildDefenceEstimations(env, env.player)