Skip to content

Commit 7804a85

Browse files
Fix "NaN" EHP error and crash when setting nemy level too high (#4591)
* Some code clean up, fixing typos * Fix default EHP state by initializing enemy stats * Update CalcDefence.lua * Fix arithmetic operation on string value * Cap placeholder enemyLevel to characterLevel * Apply characterLevel cap to normal monster enemyLevel * Check placeholder type directly instead of by value * Update ConfigOptions.lua * Apply characterLevel cap to standard bosses too * Fix spelling Co-authored-by: LocalIdentity <31035929+LocalIdentity@users.noreply.github.com>
1 parent 9fda6cb commit 7804a85

File tree

4 files changed

+75
-59
lines changed

4 files changed

+75
-59
lines changed

src/Classes/EditControl.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ function EditClass:OnKeyUp(key)
649649
self:SetText(tostring(cur + (self.numberInc or 1)), true)
650650
else
651651
if self.placeholder then
652-
self:SetText(tostring(self.placeholder + (self.numberInc or 1)), true)
652+
self:SetText(tostring((tonumber(self.placeholder) or 0) + (self.numberInc or 1)), true)
653653
else
654654
self:SetText("1", true)
655655
end
@@ -659,7 +659,7 @@ function EditClass:OnKeyUp(key)
659659
self:SetText(tostring(cur - (self.numberInc or 1)), true)
660660
else
661661
if self.placeholder then
662-
self:SetText(tostring(self.placeholder - (self.numberInc or 1)), true)
662+
self:SetText(tostring((tonumber(self.placeholder) or 0) - (self.numberInc or 1)), true)
663663
else
664664
self:SetText("0", true)
665665
end

src/Modules/CalcDefence.lua

Lines changed: 57 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -871,19 +871,25 @@ function calcs.defence(env, actor)
871871
local enemyCritDamage = env.configInput["enemyCritDamage"] or env.configPlaceholder["enemyCritDamage"] or 0
872872
output["EnemyCritEffect"] = 1 + enemyCritChance / 100 * (enemyCritDamage / 100) * (1 - output.CritExtraDamageReduction / 100)
873873
for _, damageType in ipairs(dmgTypeList) do
874-
local enemyDamageMult = calcLib.mod(enemyDB, nil, "Damage", damageType.."Damage", isElemental[damageType] and "ElementalDamage" or nil) --missing taunt from allies
875-
local enemyDamage = env.configInput["enemy"..damageType.."Damage"]
876-
local enemyPen = env.configInput["enemy"..damageType.."Pen"]
874+
local enemyDamageMult = calcLib.mod(enemyDB, nil, "Damage", damageType.."Damage", isElemental[damageType] and "ElementalDamage" or nil) -- missing taunt from allies
875+
local enemyDamage = tonumber(env.configInput["enemy"..damageType.."Damage"])
876+
local enemyPen = tonumber(env.configInput["enemy"..damageType.."Pen"])
877877
local sourceStr = enemyDamage == nil and "Default" or "Config"
878-
879-
if enemyDamage == nil and env.configPlaceholder["enemy"..damageType.."Damage"] then
880-
enemyDamage = env.configPlaceholder["enemy"..damageType.."Damage"]
878+
879+
if enemyDamage == nil then
880+
if tonumber(env.configPlaceholder["enemy"..damageType.."Damage"]) ~= nil then
881+
enemyDamage = tonumber(env.configPlaceholder["enemy"..damageType.."Damage"])
882+
elseif damageType == "Physical" then
883+
enemyDamage = round(data.monsterDamageTable[m_min(env.build.characterLevel, 83)] * 1.5)
884+
else
885+
enemyDamage = 0
886+
end
881887
end
882-
if enemyPen == nil and env.configPlaceholder["enemy"..damageType.."Pen"] then
883-
enemyPen = env.configPlaceholder["enemy"..damageType.."Pen"]
888+
if enemyPen == nil then
889+
enemyPen = tonumber(env.configPlaceholder["enemy"..damageType.."Pen"]) or 0
884890
end
885-
enemyDamage = enemyDamage or 0
886-
output[damageType.."EnemyPen"] = enemyPen or 0
891+
892+
output[damageType.."EnemyPen"] = enemyPen
887893
output["totalEnemyDamageIn"] = output["totalEnemyDamageIn"] + enemyDamage
888894
output[damageType.."EnemyDamage"] = enemyDamage * enemyDamageMult * output["EnemyCritEffect"]
889895
output["totalEnemyDamage"] = output["totalEnemyDamage"] + output[damageType.."EnemyDamage"]
@@ -1410,7 +1416,7 @@ function calcs.defence(env, actor)
14101416
end
14111417
end
14121418

1413-
-- helper function that itterativly reduces pools untill life hits 0 to determine the number of hits it would take with given damage to die
1419+
-- helper function that iteratively reduces pools until life hits 0 to determine the number of hits it would take with given damage to die
14141420
function numberOfHitsToDie(DamageIn)
14151421
local numHits = 0
14161422
DamageIn["cycles"] = DamageIn["cycles"] or 1
@@ -1438,10 +1444,10 @@ function calcs.defence(env, actor)
14381444
restoreWard = 0
14391445
end
14401446
local frostShield = output["FrostShieldLife"] or 0
1441-
local aegis = {}
1447+
local aegis = { }
14421448
aegis["shared"] = output["sharedAegis"] or 0
14431449
aegis["sharedElemental"] = output["sharedElementalAegis"] or 0
1444-
local guard = {}
1450+
local guard = { }
14451451
guard["shared"] = output.sharedGuardAbsorb or 0
14461452
for _, damageType in ipairs(dmgTypeList) do
14471453
aegis[damageType] = output[damageType.."Aegis"] or 0
@@ -1454,25 +1460,25 @@ function calcs.defence(env, actor)
14541460
DamageIn["LifeLossBelowHalfLost"] = DamageIn["LifeLossBelowHalfLost"] or 0
14551461
DamageIn["WardBypass"] = DamageIn["WardBypass"] or modDB:Sum("BASE", nil, "WardBypass") or 0
14561462

1457-
local itterationMultiplier = 1
1463+
local iterationMultiplier = 1
14581464
local maxHits = data.misc.ehpCalcMaxHitsToCalc
14591465
maxHits = maxHits / DamageIn["cycles"]
14601466
while life > 0 and numHits < maxHits do
1461-
numHits = numHits + itterationMultiplier
1462-
local Damage = {}
1467+
numHits = numHits + iterationMultiplier
1468+
local Damage = { }
14631469
for _, damageType in ipairs(dmgTypeList) do
1464-
Damage[damageType] = DamageIn[damageType] * itterationMultiplier
1470+
Damage[damageType] = DamageIn[damageType] * iterationMultiplier
14651471
end
1466-
if DamageIn.GainWhenHit and (itterationMultiplier > 1 or DamageIn["cycles"] > 1) then
1467-
local gainMult = itterationMultiplier * DamageIn["cycles"]
1472+
if DamageIn.GainWhenHit and (iterationMultiplier > 1 or DamageIn["cycles"] > 1) then
1473+
local gainMult = iterationMultiplier * DamageIn["cycles"]
14681474
life = m_min(life + DamageIn.LifeWhenHit * (gainMult - 1), gainMult * (output.LifeRecoverable or 0))
14691475
mana = m_min(mana + DamageIn.ManaWhenHit * (gainMult - 1), gainMult * (output.ManaUnreserved or 0))
14701476
energyShield = m_min(energyShield + DamageIn.EnergyShieldWhenHit * (gainMult - 1), gainMult * output.EnergyShieldRecoveryCap)
14711477
end
14721478
for _, damageType in ipairs(dmgTypeList) do
14731479
if Damage[damageType] > 0 then
14741480
if frostShield > 0 then
1475-
local tempDamage = m_min(Damage[damageType] * output["FrostShieldDamageMitigation"] / 100 / itterationMultiplier, frostShield)
1481+
local tempDamage = m_min(Damage[damageType] * output["FrostShieldDamageMitigation"] / 100 / iterationMultiplier, frostShield)
14761482
frostShield = frostShield - tempDamage
14771483
Damage[damageType] = Damage[damageType] - tempDamage
14781484
end
@@ -1492,12 +1498,12 @@ function calcs.defence(env, actor)
14921498
Damage[damageType] = Damage[damageType] - tempDamage
14931499
end
14941500
if guard[damageType] > 0 then
1495-
local tempDamage = m_min(Damage[damageType] * output[damageType.."GuardAbsorbRate"] / 100 / itterationMultiplier, guard[damageType])
1501+
local tempDamage = m_min(Damage[damageType] * output[damageType.."GuardAbsorbRate"] / 100 / iterationMultiplier, guard[damageType])
14961502
guard[damageType] = guard[damageType] - tempDamage
14971503
Damage[damageType] = Damage[damageType] - tempDamage
14981504
end
14991505
if guard["shared"] > 0 then
1500-
local tempDamage = m_min(Damage[damageType] * output["sharedGuardAbsorbRate"] / 100 / itterationMultiplier, guard["shared"])
1506+
local tempDamage = m_min(Damage[damageType] * output["sharedGuardAbsorbRate"] / 100 / iterationMultiplier, guard["shared"])
15011507
guard["shared"] = guard["shared"] - tempDamage
15021508
Damage[damageType] = Damage[damageType] - tempDamage
15031509
end
@@ -1545,18 +1551,18 @@ function calcs.defence(env, actor)
15451551
mana = m_min(mana + DamageIn.ManaWhenHit, output.ManaUnreserved or 0)
15461552
energyShield = m_min(energyShield + DamageIn.EnergyShieldWhenHit, output.EnergyShieldRecoveryCap)
15471553
end
1548-
itterationMultiplier = 1
1549-
--To speed it up, run recurivly but speed up
1554+
iterationMultiplier = 1
1555+
-- to speed it up, run recursively but accelerated
15501556
local maxDepth = data.misc.ehpCalcMaxDepth
15511557
local speedUp = data.misc.ehpCalcSpeedUp
15521558
DamageIn["cyclesRan"] = DamageIn["cyclesRan"] or false
15531559
if not DamageIn["cyclesRan"] and life > 0 and DamageIn["cycles"] < maxDepth then
1554-
Damage = {}
1560+
Damage = { }
15551561
for _, damageType in ipairs(dmgTypeList) do
15561562
Damage[damageType] = DamageIn[damageType] * speedUp
15571563
end
15581564
Damage["cycles"] = DamageIn["cycles"] * speedUp
1559-
itterationMultiplier = m_max((numberOfHitsToDie(Damage) - 1) * speedUp - 1, 1)
1565+
iterationMultiplier = m_max((numberOfHitsToDie(Damage) - 1) * speedUp - 1, 1)
15601566
DamageIn["cyclesRan"] = true
15611567
end
15621568
end
@@ -1566,9 +1572,9 @@ function calcs.defence(env, actor)
15661572
return numHits
15671573
end
15681574

1569-
--number of damaging hits needed to be taken to die
1575+
-- number of damaging hits needed to be taken to die
15701576
do
1571-
local DamageIn = {}
1577+
local DamageIn = { }
15721578
for _, damageType in ipairs(dmgTypeList) do
15731579
DamageIn[damageType] = output[damageType.."TakenHit"]
15741580
end
@@ -1577,21 +1583,21 @@ function calcs.defence(env, actor)
15771583

15781584

15791585
do
1580-
local DamageIn = {}
1586+
local DamageIn = { }
15811587
local BlockChance = 0
15821588
local blockEffect = 1
15831589
local suppressChance = 0
15841590
local suppressionEffect = 1
15851591
local ExtraAvoidChance = 0
15861592
local averageAvoidChance = 0
15871593
local worstOf = env.configInput.EHPUnluckyWorstOf or 1
1588-
--block effect
1594+
-- block effect
15891595
if damageCategoryConfig == "Melee" then
15901596
BlockChance = output.BlockChance / 100
15911597
else
15921598
BlockChance = output[damageCategoryConfig.."BlockChance"] / 100
15931599
end
1594-
--unlucky config to lower the value of block, dodge, evade etc for ehp
1600+
-- unlucky config to lower the value of block, dodge, evade etc for ehp
15951601
if worstOf > 1 then
15961602
BlockChance = BlockChance * BlockChance
15971603
if worstOf == 4 then
@@ -1609,11 +1615,11 @@ function calcs.defence(env, actor)
16091615
DamageIn.EnergyShieldWhenHit = DamageIn.EnergyShieldWhenHit + output.EnergyShieldOnSpellBlock / 2 * BlockChance
16101616
end
16111617
end
1612-
--supression
1618+
-- supression
16131619
if damageCategoryConfig == "Spell" or damageCategoryConfig == "SpellProjectile" or damageCategoryConfig == "Average" then
16141620
suppressChance = output.SpellSuppressionChance / 100
16151621
end
1616-
--unlucky config to lower the value of block, dodge, evade etc for ehp
1622+
-- unlucky config to lower the value of block, dodge, evade etc for ehp
16171623
if worstOf > 1 then
16181624
suppressChance = suppressChance * suppressChance
16191625
if worstOf == 4 then
@@ -1624,13 +1630,13 @@ function calcs.defence(env, actor)
16241630
suppressChance = suppressChance / 2
16251631
end
16261632
suppressionEffect = 1 - suppressChance * output.SpellSuppressionEffect / 100
1627-
--extra avoid chance
1633+
-- extra avoid chance
16281634
if damageCategoryConfig == "Projectile" or damageCategoryConfig == "SpellProjectile" then
16291635
ExtraAvoidChance = ExtraAvoidChance + output.AvoidProjectilesChance
16301636
elseif damageCategoryConfig == "Average" then
16311637
ExtraAvoidChance = ExtraAvoidChance + output.AvoidProjectilesChance / 2
16321638
end
1633-
--gain when hit (currently just gain on block)
1639+
-- gain when hit (currently just gain on block)
16341640
if not env.configInput.DisableEHPGainOnBlock then
16351641
if DamageIn.LifeWhenHit ~= 0 or DamageIn.ManaWhenHit ~= 0 or DamageIn.EnergyShieldWhenHit ~= 0 then
16361642
DamageIn.GainWhenHit = true
@@ -1642,7 +1648,7 @@ function calcs.defence(env, actor)
16421648
DamageIn[damageType.."EnergyShieldBypass"] = output[damageType.."EnergyShieldBypass"] * (1 - BlockChance)
16431649
end
16441650
local AvoidChance = m_min(output["Avoid"..damageType.."DamageChance"] + ExtraAvoidChance, data.misc.AvoidChanceCap)
1645-
--unlucky config to lower the value of block, dodge, evade etc for ehp
1651+
-- unlucky config to lower the value of block, dodge, evade etc for ehp
16461652
if worstOf > 1 then
16471653
AvoidChance = AvoidChance / 100 * AvoidChance
16481654
if worstOf == 4 then
@@ -1652,7 +1658,7 @@ function calcs.defence(env, actor)
16521658
averageAvoidChance = averageAvoidChance + AvoidChance
16531659
DamageIn[damageType] = output[damageType.."TakenHit"] * (blockEffect * suppressionEffect * (1 - AvoidChance / 100))
16541660
end
1655-
--petrified blood degen initialisation
1661+
-- petrified blood degen initialisation
16561662
if output["preventedLifeLoss"] > 0 then
16571663
output["LifeLossBelowHalfLost"] = 0
16581664
DamageIn["LifeLossBelowHalfLost"] = modDB:Sum("BASE", nil, "LifeLossBelowHalfLost") / 100
@@ -1677,7 +1683,7 @@ function calcs.defence(env, actor)
16771683
end
16781684
end
16791685

1680-
--chance to not be hit
1686+
-- chance to not be hit
16811687
do
16821688
local worstOf = env.configInput.EHPUnluckyWorstOf or 1
16831689
output.MeleeNotHitChance = 100 - (1 - output.MeleeEvadeChance / 100) * (1 - output.AttackDodgeChance / 100) * 100
@@ -1686,7 +1692,7 @@ function calcs.defence(env, actor)
16861692
output.SpellProjectileNotHitChance = output.SpellNotHitChance
16871693
output.AverageNotHitChance = (output.MeleeNotHitChance + output.ProjectileNotHitChance + output.SpellNotHitChance + output.SpellProjectileNotHitChance) / 4
16881694
output.ConfiguredNotHitChance = output[damageCategoryConfig.."NotHitChance"]
1689-
--unlucky config to lower the value of block, dodge, evade etc for ehp
1695+
-- unlucky config to lower the value of block, dodge, evade etc for ehp
16901696
if worstOf > 1 then
16911697
output.ConfiguredNotHitChance = output.ConfiguredNotHitChance / 100 * output.ConfiguredNotHitChance
16921698
if worstOf == 4 then
@@ -1717,7 +1723,7 @@ function calcs.defence(env, actor)
17171723
end
17181724
end
17191725

1720-
--effective hit pool
1726+
-- effective hit pool
17211727
output["TotalEHP"] = output["TotalNumberOfHits"] * output["totalEnemyDamageIn"]
17221728
if breakdown then
17231729
breakdown["TotalEHP"] = {
@@ -1727,7 +1733,7 @@ function calcs.defence(env, actor)
17271733
}
17281734
end
17291735

1730-
--survival time
1736+
-- survival time
17311737
do
17321738
local enemySkillTime = env.configInput.enemySpeed or env.configPlaceholder.enemySpeed or 700
17331739
local enemyActionSpeed = calcs.actionSpeedMod(actor.enemy)
@@ -1742,7 +1748,7 @@ function calcs.defence(env, actor)
17421748
end
17431749
end
17441750

1745-
--petrified blood "degen"
1751+
-- petrified blood "degen"
17461752
if output.preventedLifeLoss > 0 then
17471753
local LifeLossBelowHalfLost = modDB:Sum("BASE", nil, "LifeLossBelowHalfLost") / 100
17481754
output["LifeLossBelowHalfLostMax"] = output["LifeLossBelowHalfLost"] * LifeLossBelowHalfLost / 4
@@ -1764,7 +1770,7 @@ function calcs.defence(env, actor)
17641770

17651771
end
17661772

1767-
--effective health pool vs dots
1773+
-- effective health pool vs dots
17681774
for _, damageType in ipairs(dmgTypeList) do
17691775
output[damageType.."DotEHP"] = output[damageType.."TotalPool"] / output[damageType.."TakenDotMult"]
17701776
if breakdown then
@@ -1776,7 +1782,7 @@ function calcs.defence(env, actor)
17761782
end
17771783
end
17781784

1779-
-- Degens
1785+
-- degens
17801786
for _, damageType in ipairs(dmgTypeList) do
17811787
local baseVal = modDB:Sum("BASE", nil, damageType.."Degen")
17821788
if baseVal > 0 then
@@ -1912,15 +1918,15 @@ function calcs.defence(env, actor)
19121918
end
19131919

19141920

1915-
--maximum hit taken
1921+
-- maximum hit taken
19161922
-- this is not done yet, using old max hit taken
1917-
--fix total pools, as they arnt used anymore
1923+
-- fix total pools, as they aren't used anymore
19181924
for _, damageType in ipairs(dmgTypeList) do
1919-
--base + petrified blood
1925+
-- base + petrified blood
19201926
if output["preventedLifeLoss"] > 0 then
19211927
output[damageType.."TotalPool"] = output[damageType.."TotalPool"] / (1 - output["preventedLifeLoss"] / 100)
19221928
end
1923-
--ward
1929+
-- ward
19241930
local wardBypass = modDB:Sum("BASE", nil, "WardBypass") or 0
19251931
if wardBypass > 0 then
19261932
local poolProtected = output.Ward / (1 - wardBypass / 100) * (wardBypass / 100)
@@ -1930,9 +1936,9 @@ function calcs.defence(env, actor)
19301936
else
19311937
output[damageType.."TotalPool"] = output[damageType.."TotalPool"] + output.Ward or 0
19321938
end
1933-
--aegis
1939+
-- aegis
19341940
output[damageType.."TotalHitPool"] = output[damageType.."TotalPool"] + output[damageType.."Aegis"] or 0 + output[damageType.."sharedAegis"] or 0 + isElemental[damageType] and output[damageType.."sharedElementalAegis"] or 0
1935-
--guardskill
1941+
-- guard skill
19361942
local GuardAbsorbRate = output["sharedGuardAbsorbRate"] or 0 + output[damageType.."GuardAbsorbRate"] or 0
19371943
if GuardAbsorbRate > 0 then
19381944
local GuardAbsorb = output["sharedGuardAbsorb"] or 0 + output[damageType.."GuardAbsorb"] or 0
@@ -1943,7 +1949,7 @@ function calcs.defence(env, actor)
19431949
output[damageType.."TotalHitPool"] = m_max(output[damageType.."TotalHitPool"] - poolProtected, 0) + m_min(output[damageType.."TotalHitPool"], poolProtected) / (1 - GuardAbsorbRate / 100)
19441950
end
19451951
end
1946-
--frost shield
1952+
-- frost shield
19471953
if output["FrostShieldLife"] > 0 then
19481954
local poolProtected = output["FrostShieldLife"] / (output["FrostShieldDamageMitigation"] / 100) * (1 - output["FrostShieldDamageMitigation"] / 100)
19491955
output[damageType.."TotalHitPool"] = m_max(output[damageType.."TotalHitPool"] - poolProtected, 0) + m_min(output[damageType.."TotalHitPool"], poolProtected) / (1 - output["FrostShieldDamageMitigation"] / 100)

src/Modules/CalcSetup.lua

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,17 @@ function calcs.initEnv(build, mode, override, specEnv)
290290
env.enemyDB = enemyDB
291291
env.itemModDB = new("ModDB")
292292

293-
env.enemyLevel = m_max(1, m_min(100, env.configInput.enemyLevel and env.configInput.enemyLevel or env.configPlaceholder["enemyLevel"] or m_min(env.build.characterLevel, data.misc.MaxEnemyLevel)))
293+
if env.configInput.enemyLevel then
294+
env.enemyLevel = m_min(data.misc.MaxEnemyLevel, env.configInput.enemyLevel)
295+
elseif env.configPlaceholder["enemyLevel"] then
296+
if env.configInput.enemyIsBoss == "None" or env.configInput.enemyIsBoss == "Standard Boss" then
297+
env.enemyLevel = m_min(data.misc.MaxEnemyLevel, env.build.characterLevel, env.configPlaceholder["enemyLevel"])
298+
else
299+
env.enemyLevel = m_min(data.misc.MaxEnemyLevel, env.configPlaceholder["enemyLevel"])
300+
end
301+
else
302+
env.enemyLevel = m_min(data.misc.MaxEnemyLevel, env.build.characterLevel)
303+
end
294304

295305
-- Create player/enemy actors
296306
env.player = {

0 commit comments

Comments
 (0)