From ff2e094ccf804145806e49deb0a70a5e856901c9 Mon Sep 17 00:00:00 2001 From: Default global Date: Sun, 19 Jan 2025 14:26:18 -0800 Subject: [PATCH 01/23] Add notes for poe2 ailment threshold implementation, remove poe1 scorch --- src/Modules/CalcOffence.lua | 67 +++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index f9f43438c0..7f4fe781bb 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3791,10 +3791,44 @@ function calcs.offence(env, actor, activeSkill) skillFlags.impale = false --Calculate ailments and debuffs (poison, bleed, ignite, impale, exposure, etc) + local enemyAilmentThreshold = data.monsterAilmentThresholdTable[env.enemyLevel] for _, pass in ipairs(passList) do globalOutput, globalBreakdown = output, breakdown local source, output, cfg, breakdown = pass.source, pass.output, pass.cfg, pass.breakdown + -- -- (PoE2) -- + -- Ailments that require chance and ignore threshold: + -- Bleeding + -- Poison + + -- Ailments that use enemy ailment threshold (1% chance per 4% ailment threshold dealt): + -- Ignite + -- Shock + + -- Ailments that "require a minimum threshold" (unknown number): + -- Chill + + -- Ailments that use buildup mechanic: + -- Stun + -- Electrocute + -- Freeze + + -- Possible direct (ie not about damage hit modifier) crit effects on ailments (as of Jan 19 2025) + + -- Increased magnitude of damaging ailments inflicted with critical hits + -- -- (Notable) Shredding Force + -- -- (Notable) Cruel Fate + -- -- (Small) Spell Critical Chance and Critical Ailment Effect + + -- Increased magnitude of non-damaging ailments inflicted with critical hits + -- -- (Notable) Tainted Strike + + -- 100% poison chance + -- -- (Helmet) Atsak's Sight Veiled Mask + + -- Aggravate Bleeding on targets you Critically Hit with Attacks + -- -- (Helmet) The Smiling Knight Cowled Helm + -- Calculate chance to inflict secondary dots/status effects cfg.skillCond["CriticalStrike"] = true if not skillFlags.hit or skillModList:Flag(cfg, "CannotBleed") then @@ -3802,27 +3836,32 @@ function calcs.offence(env, actor, activeSkill) else output.BleedChanceOnCrit = m_min(100, skillModList:Sum("BASE", cfg, "BleedChance") + enemyDB:Sum("BASE", nil, "SelfBleedChance")) end + if not skillFlags.hit or skillModList:Flag(cfg, "CannotPoison") then output.PoisonChanceOnCrit = 0 else output.PoisonChanceOnCrit = m_min(100, skillModList:Sum("BASE", cfg, "PoisonChance") + enemyDB:Sum("BASE", nil, "SelfPoisonChance")) end + if not skillFlags.hit then output.ImpaleChanceOnCrit = 0 else output.ImpaleChanceOnCrit = env.mode_effective and m_min(100, skillModList:Sum("BASE", cfg, "ImpaleChance")) or 0 end + if not skillFlags.hit or skillModList:Flag(cfg, "CannotKnockback") then output.KnockbackChanceOnCrit = 0 else output.KnockbackChanceOnCrit = skillModList:Sum("BASE", cfg, "EnemyKnockbackChance") end cfg.skillCond["CriticalStrike"] = false + if not skillFlags.hit or skillModList:Flag(cfg, "CannotBleed") then output.BleedChanceOnHit = 0 else output.BleedChanceOnHit = m_min(100, skillModList:Sum("BASE", cfg, "BleedChance") + enemyDB:Sum("BASE", nil, "SelfBleedChance")) end + if not skillFlags.hit or skillModList:Flag(cfg, "CannotPoison") then output.PoisonChanceOnHit = 0 output.ChaosPoisonChance = 0 @@ -3830,20 +3869,23 @@ function calcs.offence(env, actor, activeSkill) output.PoisonChanceOnHit = m_min(100, skillModList:Sum("BASE", cfg, "PoisonChance") + enemyDB:Sum("BASE", nil, "SelfPoisonChance")) output.ChaosPoisonChance = m_min(100, skillModList:Sum("BASE", cfg, "ChaosPoisonChance")) end + for _, ailment in ipairs(elementalAilmentTypeList) do - local chance = skillModList:Sum("BASE", cfg, "Enemy"..ailment.."Chance") + enemyDB:Sum("BASE", nil, "Self"..ailment.."Chance") + local poe1_chance = skillModList:Sum("BASE", cfg, "Enemy"..ailment.."Chance") + enemyDB:Sum("BASE", nil, "Self"..ailment.."Chance") + if ailment == "Chill" then - chance = 100 - end - -- Warden's Oath of Summer Scorch Chance - if ailment == "Ignite" and env.modDB:Flag(nil, "IgniteCanScorch") then - output["ScorchChance"] = m_min(100, chance) - skillModList:NewMod("EnemyScorchChance", "BASE", chance, "Ignite Chance") + poe1_chance = 100 end if skillFlags.hit and not skillModList:Flag(cfg, "Cannot"..ailment) then - output[ailment.."ChanceOnHit"] = m_min(100, chance) - if skillModList:Flag(cfg, "CritsDontAlways"..ailment) -- e.g. Painseeker - or (ailmentData[ailment] and ailmentData[ailment].alt and not skillModList:Flag(cfg, "CritAlwaysAltAilments")) then -- e.g. Secrets of Suffering + output[ailment.."ChanceOnHit"] = m_min(100, poe1_chance) + if ( + skillModList:Flag(cfg, "CritsDontAlways"..ailment) -- e.g. Painseeker + or ( + ailmentData[ailment] + and ailmentData[ailment].alt + and not skillModList:Flag(cfg, "CritAlwaysAltAilments") + ) + ) then -- e.g. Secrets of Suffering output[ailment.."ChanceOnCrit"] = output[ailment.."ChanceOnHit"] else output[ailment.."ChanceOnCrit"] = 100 @@ -3852,14 +3894,11 @@ function calcs.offence(env, actor, activeSkill) output[ailment.."ChanceOnHit"] = 0 output[ailment.."ChanceOnCrit"] = 0 end - -- Warden's Oath of Summer Scorch on Crit Chance - if ailment == "Scorch" and env.modDB:Flag(nil, "IgniteCanScorch") then - output["ScorchChanceOnCrit"] = 100 - end if (output[ailment.."ChanceOnHit"] + (skillModList:Flag(cfg, "NeverCrit") and 0 or output[ailment.."ChanceOnCrit"])) > 0 then skillFlags["inflict"..ailment] = true end end + if not skillFlags.hit or skillModList:Flag(cfg, "CannotKnockback") then output.KnockbackChanceOnHit = 0 else From 86b763dc887b387f6e33d6e9bdf6ad125c1e835e Mon Sep 17 00:00:00 2001 From: Default global Date: Sun, 19 Jan 2025 16:59:10 -0800 Subject: [PATCH 02/23] Partial progress towards ailment threshold - canDoAilment is currently unconditionally returning false - possible bug with calcAverageSourceDamage ? --- src/Modules/CalcOffence.lua | 429 +++++++++++++++++++----------------- 1 file changed, 222 insertions(+), 207 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 7f4fe781bb..7531f09424 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3790,151 +3790,103 @@ function calcs.offence(env, actor, activeSkill) end skillFlags.impale = false - --Calculate ailments and debuffs (poison, bleed, ignite, impale, exposure, etc) - local enemyAilmentThreshold = data.monsterAilmentThresholdTable[env.enemyLevel] - for _, pass in ipairs(passList) do - globalOutput, globalBreakdown = output, breakdown - local source, output, cfg, breakdown = pass.source, pass.output, pass.cfg, pass.breakdown - - -- -- (PoE2) -- - -- Ailments that require chance and ignore threshold: - -- Bleeding - -- Poison - - -- Ailments that use enemy ailment threshold (1% chance per 4% ailment threshold dealt): - -- Ignite - -- Shock - - -- Ailments that "require a minimum threshold" (unknown number): - -- Chill + -- Ailment notes - -- Ailments that use buildup mechanic: - -- Stun - -- Electrocute - -- Freeze + -- -- (PoE2) -- + -- "Flat chance ailments" + -- [Ailments that require chance and ignore threshold] + -- Bleed (damaging) + -- Poison (damaging) - -- Possible direct (ie not about damage hit modifier) crit effects on ailments (as of Jan 19 2025) + -- "Scaling threshold ailments" + -- [Ailments that use enemy ailment threshold (1% chance per 4% ailment threshold dealt)] + -- Ignite (damaging) + -- Shock (non-damaging) - -- Increased magnitude of damaging ailments inflicted with critical hits - -- -- (Notable) Shredding Force - -- -- (Notable) Cruel Fate - -- -- (Small) Spell Critical Chance and Critical Ailment Effect + -- "Minimum threshold ailments" + -- [Ailments that "require a minimum threshold" (unknown number) but then always apply] + -- Chill (non-damaging) - -- Increased magnitude of non-damaging ailments inflicted with critical hits - -- -- (Notable) Tainted Strike + -- "Buildup ailments" + -- [Ailments that use buildup mechanic] + -- Electrocute (non-damaging) + -- Freeze (non-damaging) + -- Stun (non-damaging - note that I think the game doesn't consider this an "ailment") - -- 100% poison chance - -- -- (Helmet) Atsak's Sight Veiled Mask + -- Possible direct (ie not about damage hit modifier) crit effects on ailments (as of Jan 19 2025) - -- Aggravate Bleeding on targets you Critically Hit with Attacks - -- -- (Helmet) The Smiling Knight Cowled Helm + -- Increased magnitude of damaging ailments inflicted with critical hits + -- -- (Notable) Shredding Force + -- -- (Notable) Cruel Fate + -- -- (Small) Spell Critical Chance and Critical Ailment Effect - -- Calculate chance to inflict secondary dots/status effects - cfg.skillCond["CriticalStrike"] = true - if not skillFlags.hit or skillModList:Flag(cfg, "CannotBleed") then - output.BleedChanceOnCrit = 0 - else - output.BleedChanceOnCrit = m_min(100, skillModList:Sum("BASE", cfg, "BleedChance") + enemyDB:Sum("BASE", nil, "SelfBleedChance")) - end + -- Increased magnitude of non-damaging ailments inflicted with critical hits + -- -- (Notable) Tainted Strike - if not skillFlags.hit or skillModList:Flag(cfg, "CannotPoison") then - output.PoisonChanceOnCrit = 0 - else - output.PoisonChanceOnCrit = m_min(100, skillModList:Sum("BASE", cfg, "PoisonChance") + enemyDB:Sum("BASE", nil, "SelfPoisonChance")) - end - - if not skillFlags.hit then - output.ImpaleChanceOnCrit = 0 - else - output.ImpaleChanceOnCrit = env.mode_effective and m_min(100, skillModList:Sum("BASE", cfg, "ImpaleChance")) or 0 - end - - if not skillFlags.hit or skillModList:Flag(cfg, "CannotKnockback") then - output.KnockbackChanceOnCrit = 0 - else - output.KnockbackChanceOnCrit = skillModList:Sum("BASE", cfg, "EnemyKnockbackChance") - end - cfg.skillCond["CriticalStrike"] = false - - if not skillFlags.hit or skillModList:Flag(cfg, "CannotBleed") then - output.BleedChanceOnHit = 0 - else - output.BleedChanceOnHit = m_min(100, skillModList:Sum("BASE", cfg, "BleedChance") + enemyDB:Sum("BASE", nil, "SelfBleedChance")) - end - - if not skillFlags.hit or skillModList:Flag(cfg, "CannotPoison") then - output.PoisonChanceOnHit = 0 - output.ChaosPoisonChance = 0 - else - output.PoisonChanceOnHit = m_min(100, skillModList:Sum("BASE", cfg, "PoisonChance") + enemyDB:Sum("BASE", nil, "SelfPoisonChance")) - output.ChaosPoisonChance = m_min(100, skillModList:Sum("BASE", cfg, "ChaosPoisonChance")) - end - - for _, ailment in ipairs(elementalAilmentTypeList) do - local poe1_chance = skillModList:Sum("BASE", cfg, "Enemy"..ailment.."Chance") + enemyDB:Sum("BASE", nil, "Self"..ailment.."Chance") - - if ailment == "Chill" then - poe1_chance = 100 - end - if skillFlags.hit and not skillModList:Flag(cfg, "Cannot"..ailment) then - output[ailment.."ChanceOnHit"] = m_min(100, poe1_chance) - if ( - skillModList:Flag(cfg, "CritsDontAlways"..ailment) -- e.g. Painseeker - or ( - ailmentData[ailment] - and ailmentData[ailment].alt - and not skillModList:Flag(cfg, "CritAlwaysAltAilments") - ) - ) then -- e.g. Secrets of Suffering - output[ailment.."ChanceOnCrit"] = output[ailment.."ChanceOnHit"] - else - output[ailment.."ChanceOnCrit"] = 100 - end - else - output[ailment.."ChanceOnHit"] = 0 - output[ailment.."ChanceOnCrit"] = 0 - end - if (output[ailment.."ChanceOnHit"] + (skillModList:Flag(cfg, "NeverCrit") and 0 or output[ailment.."ChanceOnCrit"])) > 0 then - skillFlags["inflict"..ailment] = true - end - end + -- 100% poison chance + -- -- (Helmet) Atsak's Sight Veiled Mask - if not skillFlags.hit or skillModList:Flag(cfg, "CannotKnockback") then - output.KnockbackChanceOnHit = 0 - else - output.KnockbackChanceOnHit = skillModList:Sum("BASE", cfg, "EnemyKnockbackChance") - end - output.ImpaleChance = env.mode_effective and m_min(100, skillModList:Sum("BASE", cfg, "ImpaleChance")) or 0 - if skillModList:Sum("BASE", cfg, "FireExposureChance") > 0 then - skillFlags.applyFireExposure = true - end - if skillModList:Sum("BASE", cfg, "ColdExposureChance") > 0 then - skillFlags.applyColdExposure = true - end - if skillModList:Sum("BASE", cfg, "LightningExposureChance") > 0 then - skillFlags.applyLightningExposure = true - end + -- Aggravate Bleeding on targets you Critically Hit with Attacks + -- -- (Helmet) The Smiling Knight Cowled Helm - for _, ailment in ipairs(ailmentTypeList) do - local mult = (1 + modDB:Sum("INC", skillCfg, "AilmentChance") / 100) - if env.mode_effective then - mult = mult * (enemyDB:Flag(nil, ailment.."Immune") and 0 or 1 - enemyDB:Sum("BASE", nil, "Avoid"..ailment) / 100) - end - output[ailment.."ChanceOnHit"] = m_min(100, output[ailment.."ChanceOnHit"] * mult) - output[ailment.."ChanceOnCrit"] = m_min(100, output[ailment.."ChanceOnCrit"] * mult) - if ailment == "Poison" then - output.ChaosPoisonChance = m_min(100, output.ChaosPoisonChance * mult) - end - end + -- Calculate ailment thresholds + local enemyAilmentThreshold = data.monsterAilmentThresholdTable[env.enemyLevel] + local isBoss = env.configInput["enemyIsBoss"] ~= "None" + local enemyMapLifeMult = 1 + local enemyMapAilmentMult = 1 + if env.enemyLevel >= 66 then + enemyMapLifeMult = isBoss and data.mapLevelBossLifeMult[env.enemyLevel] or data.mapLevelLifeMult[env.enemyLevel] + enemyMapAilmentMult = isBoss and data.mapLevelBossAilmentMult[env.enemyLevel] or enemyMapAilmentMult + end + local enemyTypeMult = isBoss and 7.68 or 1 + local enemyThreshold = enemyAilmentThreshold * enemyTypeMult * enemyMapLifeMult * enemyDB:More(nil, "Life") * enemyMapAilmentMult * enemyDB:More(nil, "AilmentThreshold") + + local damagingAilmentConfig = { + ["Bleed"] = { + ["DamageDealtType"] = "Physical", + ["ScalesFrom"] = { + ["Physical"] = 0.15, + } + }, + ["Poison"] = { + ["DamageDealtType"] = "Chaos", + ["ScalesFrom"] = { + ["Physical"] = 0.2, + ["Chaos"] = 0.2, + } + }, + ["Ignite"] = { + ["DamageDealtType"] = "Fire", + ["ScalesFrom"] = { + ["Fire"] = 0.2, + } + }, + } + local scalingThresholdAilmentConfig = { + ["Bleed"] = { + ["Physical"] = true + }, + ["Shock"] = { + ["Lightning"] = true + } + } - local ailmentMode = env.configInput.ailmentMode or "AVERAGE" - if ailmentMode == "CRIT" or modDB:Flag(nil, "AilmentsOnlyFromCrit") then - for _, ailment in ipairs(ailmentTypeList) do - output[ailment.."ChanceOnHit"] = 0 - end - end + -- Calculate ailments and debuffs (poison, bleed, ignite, impale, exposure, etc) + for _, pass in ipairs(passList) do + globalOutput, globalBreakdown = output, breakdown + local source, output, cfg, breakdown = pass.source, pass.output, pass.cfg, pass.breakdown - -- address Weapon1H interaction with Ailment for nodes like Sleight of Hand + -- Legacy PoE1 ailments (to be removed later) + -- No more "alt" ailments: Scorched, Brittle, Sapped + -- No more Impale + output.ImpaleChance = 0 + output.ImpaleChanceOnCrit = 0 + output.ScorchChance = 0 + output.BrittleChance = 0 + output.SappedChance = 0 + output.ChaosPoisonChance = 0 + + -- address Weapon1H interaction with Ailment for nodes like Coated Arms (PoE1: Sleight of Hand) -- bit-and on cfg.flags confirms if the skill has the 1H flag -- if so bit-or on the targetCfg (e.g. dotCfg) to guarantee for calculations like Sum("INC") and breakdown local function checkWeapon1HFlags(targetCfg) @@ -3962,9 +3914,13 @@ function calcs.offence(env, actor, activeSkill) ---@param ailment string ---@return number, number @average hit damage, average crit damage local function calcAverageSourceDamage(ailment) + -- requires: + -- output.HitAverage + -- output.CritAverage local canCrit = not skillModList:Flag(cfg, "AilmentsAreNeverFromCrit") local sourceHitDmg, sourceCritDmg = 0, 0 for _, type in ipairs(dmgTypeList) do + ConPrintf("canDoAilment(%s, %s) = %s", ailment, type, canDoAilment(ailment, type)) if canDoAilment(ailment, type) then sourceHitDmg = sourceHitDmg + output[type.."HitAverage"] if canCrit then @@ -3977,6 +3933,11 @@ function calcs.offence(env, actor, activeSkill) -- Calculates damage to be used in damaging ailment calculations local function calcAilmentSourceDamage(ailment, defaultDamageTypes) + -- requires: + -- output.StoredHitMin + -- output.StoredHitMax + -- output.StoredCritMin + -- output.StoredCritMax local canCrit = not skillModList:Flag(cfg, "AilmentsAreNeverFromCrit") local hitMin, hitMax = 0, 0 local critMin, critMax = 0, 0 @@ -4000,20 +3961,24 @@ function calcs.offence(env, actor, activeSkill) end -- Calculate the inflict chance and base damage of a secondary effect (bleed/poison/ignite/shock/freeze) - local function calcAilmentDamage(type, sourceCritChance, sourceHitDmg, sourceCritDmg, hideFromBreakdown) - local chanceOnHit, chanceOnCrit = output[type.."ChanceOnHit"], output[type.."ChanceOnCrit"] + local function calcAilmentDamage(ailment, sourceCritChance, sourceHitDmg, sourceCritDmg, hideFromBreakdown) + -- requires: + -- output.ChanceOnHit + -- output.ChanceOnCrit + + local chanceOnHit, chanceOnCrit = output[ailment.."ChanceOnHit"], output[ailment.."ChanceOnCrit"] -- Use sourceCritChance to factor in chance a critical ailment is present local chanceFromHit = chanceOnHit * (1 - sourceCritChance / 100) local chanceFromCrit = chanceOnCrit * sourceCritChance / 100 local chance = chanceFromHit + chanceFromCrit - output[type.."Chance"] = chance + output[ailment.."Chance"] = chance local baseFromHit = sourceHitDmg * chanceFromHit / (chanceFromHit + chanceFromCrit) local baseFromCrit = sourceCritDmg * chanceFromCrit / (chanceFromHit + chanceFromCrit) local baseVal = baseFromHit + baseFromCrit - local sourceMult = skillModList:More(cfg, type.."AsThoughDealing") + local sourceMult = skillModList:More(cfg, ailment.."AsThoughDealing") if breakdown and chance ~= 0 and not hideFromBreakdown then - local breakdownChance = breakdown[type.."Chance"] or { } - breakdown[type.."Chance"] = breakdownChance + local breakdownChance = breakdown[ailment.."Chance"] or { } + breakdown[ailment.."Chance"] = breakdownChance if breakdownChance[1] then t_insert(breakdownChance, "") end @@ -4031,8 +3996,8 @@ function calcs.offence(env, actor, activeSkill) end end if breakdown and baseVal > 0 and not hideFromBreakdown then - local breakdownDPS = breakdown[type.."DPS"] or { } - breakdown[type.."DPS"] = breakdownDPS + local breakdownDPS = breakdown[ailment.."DPS"] or { } + breakdown[ailment.."DPS"] = breakdownDPS if breakdownDPS[1] then t_insert(breakdownDPS, "") end @@ -4083,6 +4048,13 @@ function calcs.offence(env, actor, activeSkill) -- Chaos/Fire/Physical -- Chaos+Physical/Fire/Physical local function calcDamagingAilment(ailment, ailmentDamageType, defaultDamageTypes) + -- requires: + -- output.ChanceOnHit + -- output.ChanceOnCrit + -- output.CritChance + -- output.HitChance + -- output.Cooldown -> output.HitTime or output.Time + if not canDeal[ailmentDamageType] then return end @@ -4394,6 +4366,112 @@ function calcs.offence(env, actor, activeSkill) end end + -- Knockback (not sure why this is in ailment calc, but I'll calculate it anyway) + output.KnockbackChanceOnHit = 0 + output.KnockbackChanceOnCrit = 0 + local knockbackWithHitsCloseRange = modDB:Sum("INC", skillCfg, "KnockbackWithHitsCloseRange") + if ( -- (Notable) Clear Space + skillFlags.hit + and not skillModList:Flag(cfg, "CannotKnockback") + and modDB:Flag(nil, "conditionAtCloseRange") + and knockbackWithHitsCloseRange > 0 + ) then + output.KnockbackChanceOnHit = knockbackWithHitsCloseRange + end + if skillModList:Flag(cfg, "Knockback") then -- From what I could see, all skills are 0% or 100%, with no enemy mitigation + output.KnockbackChanceOnHit = 100 + output.KnockbackChanceOnCrit = 100 + end + + -- Calculate flat chance ailment (Poison, Bleed) chance on crit + for _, flatAilment in ipairs({"Bleed", "Poison"}) do + if not skillFlags.hit or skillModList:Flag(cfg, "Cannot"..flatAilment) then + output[flatAilment.."ChanceOnHit"] = 0 + output[flatAilment.."ChanceOnCrit"] = 0 + skillFlags["inflict"..flatAilment] = false + else + local flatChance = m_min(100, skillModList:Sum("BASE", cfg, flatAilment.."Chance") + enemyDB:Sum("BASE", nil, "Self"..flatAilment.."Chance")) + output[flatAilment.."ChanceOnHit"] = flatChance + output[flatAilment.."ChanceOnCrit"] = flatChance + skillFlags["inflict"..flatAilment] = true + end + end + + -- TODO: Placeholder values until proper numbers are figured out + -- For Chill in-game tooltip says: + -- "All Hits that have any Contribution to Chill Magnitude can Chill, without requiring an explicit chance to inflict, + -- provided the Magnitudes meets a minimum threshold. So low damage Hits may still fail to Chill." + local dealtCold = calcAverageSourceDamage("Chill") + ConPrintf(dealtCold) + ConPrintf(enemyThreshold) + ConPrintf(output["ColdHitAverage"]) + if dealtCold > enemyThreshold * 0.04 then -- Assume 1% is sufficient + output["ChillChanceOnHit"] = 100 + output["ChillChanceOnCrit"] = 100 + skillFlags["inflictChill"] = true + else + output["ChillChanceOnHit"] = 0 + output["ChillChanceOnCrit"] = 0 + skillFlags["inflictChill"] = false + end + -- TODO: Freeze and Electrocute are unhandled, should use similar system as Stun + output["FreezeChanceOnHit"] = 0 + output["FreezeChanceOnCrit"] = 0 + skillFlags["inflictFreeze"] = false + output["ElectrocuteChanceOnHit"] = 0 + output["ElectrocuteChanceOnCrit"] = 0 + skillFlags["inflictElectrocute"] = false + + -- Calculate scaling threshold ailment chance + for _, ailment in ipairs({"Ignite", "Shock"}) do + local hitMin, hitMax, critMin, critMax = calcAilmentSourceDamage(ailment, scalingThresholdAilmentConfig[ailment]) + -- TODO: average for now, can do more complicated calculation later + local hitAvg = hitMin + (hitMax - hitMin) / 2 + local critAvg = critMin + (critMax - critMin) / 2 + local hitElementalAilmentChance = (hitAvg / enemyThreshold) / 0.04 + local critElementalAilmentChance = (critAvg / enemyThreshold) / 0.04 + + if skillFlags.hit and not skillModList:Flag(cfg, "Cannot"..ailment) then + output[ailment.."ChanceOnHit"] = m_min(100, hitElementalAilmentChance) + output[ailment.."ChanceOnCrit"] = m_min(100, critElementalAilmentChance) + else + output[ailment.."ChanceOnHit"] = 0 + output[ailment.."ChanceOnCrit"] = 0 + end + + local anyChanceToAilment = output[ailment.."ChanceOnHit"] + (skillModList:Flag(cfg, "NeverCrit") and 0 or output[ailment.."ChanceOnCrit"]) + if anyChanceToAilment > 0 then + skillFlags["inflict"..ailment] = true + end + end + + -- Apply elemental exposure from skill + for _, element in ipairs({"Fire", "Cold", "Lightning"}) do + if skillModList:Sum("BASE", cfg, element.."ExposureChance") > 0 then + skillFlags["apply"..element.."Exposure"] = true + end + end + + -- Apply increased ailment chance mods + for _, ailment in ipairs(ailmentTypeList) do + local mult = (1 + modDB:Sum("INC", skillCfg, "AilmentChance") / 100) + if env.mode_effective then + mult = mult * (enemyDB:Flag(nil, ailment.."Immune") and 0 or 1 - enemyDB:Sum("BASE", nil, "Avoid"..ailment) / 100) + end + output[ailment.."ChanceOnHit"] = m_min(100, output[ailment.."ChanceOnHit"] * mult) + output[ailment.."ChanceOnCrit"] = m_min(100, output[ailment.."ChanceOnCrit"] * mult) + end + + -- Apply user damage type config + local ailmentMode = env.configInput.ailmentMode or "AVERAGE" + if ailmentMode == "CRIT" then + for _, ailment in ipairs(ailmentTypeList) do + output[ailment.."ChanceOnHit"] = 0 + end + end + + -- FIXME: use damagingAilmentConfig + -- FIXME: Handle Blood Mage -> Blood Barbs calcDamagingAilment("Bleed", "Physical", { ["Physical"] = true, }) @@ -4408,23 +4486,12 @@ function calcs.offence(env, actor, activeSkill) }) -- Calculate non-damaging ailments effect and duration modifiers - local isBoss = env.configInput["enemyIsBoss"] ~= "None" - local enemyAilmentThreshold = data.monsterAilmentThresholdTable[env.enemyLevel] - local enemyMapLifeMult = 1 - local enemyMapAilmentMult = 1 - if env.enemyLevel >= 66 then - enemyMapLifeMult = isBoss and data.mapLevelBossLifeMult[env.enemyLevel] or data.mapLevelLifeMult[env.enemyLevel] - enemyMapAilmentMult = isBoss and data.mapLevelBossAilmentMult[env.enemyLevel] or enemyMapAilmentMult - end - local enemyTypeMult = isBoss and 7.68 or 1 - local enemyThreshold = enemyAilmentThreshold * enemyTypeMult * enemyMapLifeMult * enemyDB:More(nil, "Life") * enemyMapAilmentMult * enemyDB:More(nil, "AilmentThreshold") - - local ailments = { + local nonDamagingAilmentsConfig = { ["Chill"] = { effList = { 10, 20 }, effect = function(damage, effectMod) return 50 * ((damage / enemyThreshold) ^ 0.4) * effectMod end, thresh = function(damage, value, effectMod) return damage * ((50 * effectMod / value) ^ 2.5) end, - ramping = output.HasBonechill or false, + ramping = false, }, ["Shock"] = { effList = { 10, 20, 40 }, @@ -4467,7 +4534,7 @@ function calcs.offence(env, actor, activeSkill) end end end - for ailment, val in pairs(ailments) do + for ailment, val in pairs(nonDamagingAilmentsConfig) do if (output[ailment.."ChanceOnHit"] + output[ailment.."ChanceOnCrit"]) > 0 then if globalBreakdown then globalBreakdown[ailment.."EffectMod"] = { @@ -4638,58 +4705,6 @@ function calcs.offence(env, actor, activeSkill) end end - -- Calculate impale chance and modifiers - if canDeal.Physical and (output.ImpaleChance + output.ImpaleChanceOnCrit) > 0 then - skillFlags.impale = true - local critChance = output.CritChance / 100 - local impaleChance = (m_min(output.ImpaleChance/100, 1) * (1 - critChance) + m_min(output.ImpaleChanceOnCrit/100, 1) * critChance) - local maxStacks = skillModList:Sum("BASE", cfg, "ImpaleStacksMax") * (1 + skillModList:Sum("BASE", cfg, "ImpaleAdditionalDurationChance") / 100) - local configStacks = enemyDB:Sum("BASE", cfg, "Multiplier:ImpaleStacks") - local impaleStacks = m_min(maxStacks, configStacks) - - local baseStoredDamage = data.misc.ImpaleStoredDamageBase - local storedExpectedDamageIncOnBleed = skillModList:Sum("INC", cfg, "ImpaleEffectOnBleed")*skillModList:Sum("BASE", cfg, "BleedChance")/100 - local storedExpectedDamageInc = (skillModList:Sum("INC", cfg, "ImpaleEffect") + storedExpectedDamageIncOnBleed)/100 - local storedExpectedDamageMore = round(skillModList:More(cfg, "ImpaleEffect"), 2) - local storedExpectedDamageModifier = (1 + storedExpectedDamageInc) * storedExpectedDamageMore - local impaleStoredDamage = baseStoredDamage * storedExpectedDamageModifier - local impaleHitDamageMod = impaleStoredDamage * impaleStacks -- Source: https://www.reddit.com/r/pathofexile/comments/chgqqt/impale_and_armor_interaction/ - - local enemyArmour = m_max(calcLib.val(enemyDB, "Armour"), 0) - local impaleArmourReduction = calcs.armourReductionF(enemyArmour, impaleHitDamageMod * output.PhysicalStoredCombinedAvg) - local impaleResist = m_min(m_max(0, enemyDB:Sum("BASE", nil, "PhysicalDamageReduction") + skillModList:Sum("BASE", cfg, "EnemyImpalePhysicalDamageReduction") + impaleArmourReduction), data.misc.DamageReductionCap) - if skillModList:Flag(cfg, "IgnoreEnemyImpalePhysicalDamageReduction") then - impaleResist = 0 - end - local impaleTakenCfg = { flags = ModFlag.Hit } - local impaleTaken = (1 + enemyDB:Sum("INC", impaleTakenCfg, "DamageTaken", "PhysicalDamageTaken", "ReflectedDamageTaken") / 100) - * enemyDB:More(impaleTakenCfg, "DamageTaken", "PhysicalDamageTaken", "ReflectedDamageTaken") - local impaleDMGModifier = impaleHitDamageMod * (1 - impaleResist / 100) * impaleChance * impaleTaken - - globalOutput.ImpaleStacksMax = maxStacks - globalOutput.ImpaleStacks = impaleStacks - --ImpaleStoredDamage should be named ImpaleEffect or similar - --Using the variable name ImpaleEffect breaks the calculations sidebar (?!) - output.ImpaleStoredDamage = impaleStoredDamage * 100 - output.ImpaleModifier = 1 + impaleDMGModifier - - if breakdown then - breakdown.ImpaleStoredDamage = {} - t_insert(breakdown.ImpaleStoredDamage, "10% ^8(base value)") - t_insert(breakdown.ImpaleStoredDamage, s_format("x %.2f ^8(increased effectiveness)", storedExpectedDamageModifier)) - t_insert(breakdown.ImpaleStoredDamage, s_format("= %.1f%%", output.ImpaleStoredDamage)) - - breakdown.ImpaleModifier = {} - t_insert(breakdown.ImpaleModifier, s_format("%d ^8(number of stacks, can be overridden in the Configuration tab)", impaleStacks)) - t_insert(breakdown.ImpaleModifier, s_format("x %.3f ^8(stored damage)", impaleStoredDamage)) - t_insert(breakdown.ImpaleModifier, s_format("x %.2f ^8(impale chance)", impaleChance)) - t_insert(breakdown.ImpaleModifier, s_format("x %.2f ^8(impale enemy physical damage reduction)", (1 - impaleResist / 100))) - if impaleTaken ~= 1 then - t_insert(breakdown.ImpaleModifier, s_format("x %.2f ^8(impale enemy damage taken)", impaleTaken)) - end - t_insert(breakdown.ImpaleModifier, s_format("= %.3f ^8(impale damage multiplier)", impaleDMGModifier)) - end - end end -- Combine secondary effect stats From 189cc9f4b254a355f041469399962a6c6ce04309 Mon Sep 17 00:00:00 2001 From: Default global Date: Sun, 19 Jan 2025 18:39:25 -0800 Subject: [PATCH 03/23] Fix bugs in last commit, reorganize calc tab, temporarily remove per stack value (didn't match breakdown values) --- src/Modules/CalcOffence.lua | 118 ++++++++++++++++----------- src/Modules/CalcSections.lua | 149 ++++++++++++++++++----------------- 2 files changed, 149 insertions(+), 118 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 7531f09424..6fc390560f 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3829,6 +3829,8 @@ function calcs.offence(env, actor, activeSkill) -- Aggravate Bleeding on targets you Critically Hit with Attacks -- -- (Helmet) The Smiling Knight Cowled Helm + -- Various tree nodes for bleed chance on crit + -- Calculate ailment thresholds local enemyAilmentThreshold = data.monsterAilmentThresholdTable[env.enemyLevel] local isBoss = env.configInput["enemyIsBoss"] ~= "None" @@ -3840,35 +3842,51 @@ function calcs.offence(env, actor, activeSkill) end local enemyTypeMult = isBoss and 7.68 or 1 local enemyThreshold = enemyAilmentThreshold * enemyTypeMult * enemyMapLifeMult * enemyDB:More(nil, "Life") * enemyMapAilmentMult * enemyDB:More(nil, "AilmentThreshold") + output['EnemyAilmentThreshold'] = enemyThreshold - local damagingAilmentConfig = { + -- TODO: Should probably be in Data.lua instead, or pulled from export data + local defaultAilmentDamageTypes = { + -- damaging ["Bleed"] = { - ["DamageDealtType"] = "Physical", ["ScalesFrom"] = { - ["Physical"] = 0.15, - } + ["Physical"] = true, + }, + ["DamageType"] = "Physical", }, ["Poison"] = { - ["DamageDealtType"] = "Chaos", ["ScalesFrom"] = { - ["Physical"] = 0.2, - ["Chaos"] = 0.2, - } + ["Physical"] = true, + ["Chaos"] = true, + }, + ["DamageType"] = "Chaos", }, ["Ignite"] = { - ["DamageDealtType"] = "Fire", ["ScalesFrom"] = { - ["Fire"] = 0.2, + ["Fire"] = true, + }, + ["DamageType"] = "Fire", + }, + -- non-damaging + ["Shock"] = { + ["ScalesFrom"] = { + ["Lightning"] = true, } }, - } - local scalingThresholdAilmentConfig = { - ["Bleed"] = { - ["Physical"] = true + ["Chill"] = { + ["ScalesFrom"] = { + ["Cold"] = true, + } + }, + ["Freeze"] = { + ["ScalesFrom"] = { + ["Cold"] = true, + } + }, + ["Electrocute"] = { + ["ScalesFrom"] = { + ["Lightning"] = true, + } }, - ["Shock"] = { - ["Lightning"] = true - } } -- Calculate ailments and debuffs (poison, bleed, ignite, impale, exposure, etc) @@ -3894,37 +3912,45 @@ function calcs.offence(env, actor, activeSkill) end -- Check if the skill can inflict a given ailment - local function canDoAilment(type, damageType, defaultDamageTypes) + local function canDoAilment(ailmentType, damageType, defaultDamageTypes) if not canDeal[damageType] then return false end - if (defaultDamageTypes and defaultDamageTypes[damageType]) or (ailmentData[type] and type == ailmentData[type].associatedType) then - if skillModList:Flag(cfg, damageType.."Cannot"..type) then + + -- check against input valid types + if ( + (defaultDamageTypes and defaultDamageTypes[damageType]) + or (ailmentData[ailmentType] and damageType == ailmentData[ailmentType].associatedType) + ) then + if skillModList:Flag(cfg, damageType.."Cannot"..ailmentType) then return false end return true end - if skillModList:Flag(cfg, damageType.."Can"..type) then + + -- Process overrides eg. LightningCanFreeze + if skillModList:Flag(cfg, damageType.."Can"..ailmentType) then return true end + return false end ---Calculates normal and crit damage to be used in non-damaging ailment calculations ---@param ailment string ---@return number, number @average hit damage, average crit damage - local function calcAverageSourceDamage(ailment) + local function calcAverageUnmitigatedSourceDamage(ailment, defaultDamageTypes) -- requires: -- output.HitAverage -- output.CritAverage local canCrit = not skillModList:Flag(cfg, "AilmentsAreNeverFromCrit") local sourceHitDmg, sourceCritDmg = 0, 0 - for _, type in ipairs(dmgTypeList) do - ConPrintf("canDoAilment(%s, %s) = %s", ailment, type, canDoAilment(ailment, type)) - if canDoAilment(ailment, type) then - sourceHitDmg = sourceHitDmg + output[type.."HitAverage"] + for _, dmg_type in ipairs(dmgTypeList) do + ConPrintf("canDoAilment(%s, %s) = %s", ailment, dmg_type, canDoAilment(ailment, dmg_type, defaultDamageTypes)) + if canDoAilment(ailment, dmg_type, defaultDamageTypes) then + sourceHitDmg = sourceHitDmg + output[dmg_type.."HitAverage"] if canCrit then - sourceCritDmg = sourceCritDmg + output[type.."CritAverage"] + sourceCritDmg = sourceCritDmg + output[dmg_type.."CritAverage"] end end end @@ -4401,11 +4427,13 @@ function calcs.offence(env, actor, activeSkill) -- For Chill in-game tooltip says: -- "All Hits that have any Contribution to Chill Magnitude can Chill, without requiring an explicit chance to inflict, -- provided the Magnitudes meets a minimum threshold. So low damage Hits may still fail to Chill." - local dealtCold = calcAverageSourceDamage("Chill") + local dealtCold = calcAverageUnmitigatedSourceDamage("Chill", defaultAilmentDamageTypes["Chill"]["ScalesFrom"]) ConPrintf(dealtCold) ConPrintf(enemyThreshold) ConPrintf(output["ColdHitAverage"]) - if dealtCold > enemyThreshold * 0.04 then -- Assume 1% is sufficient + local chillAilmentThresholdGuess = enemyThreshold * 0.04 * 15 -- Assume 15% is sufficient + output['ChillAilmentThresholdGuess'] = chillAilmentThresholdGuess + if dealtCold > chillAilmentThresholdGuess then output["ChillChanceOnHit"] = 100 output["ChillChanceOnCrit"] = 100 skillFlags["inflictChill"] = true @@ -4424,12 +4452,14 @@ function calcs.offence(env, actor, activeSkill) -- Calculate scaling threshold ailment chance for _, ailment in ipairs({"Ignite", "Shock"}) do - local hitMin, hitMax, critMin, critMax = calcAilmentSourceDamage(ailment, scalingThresholdAilmentConfig[ailment]) + local hitMin, hitMax, critMin, critMax = calcAilmentSourceDamage(ailment, defaultAilmentDamageTypes[ailment]["ScalesFrom"]) -- TODO: average for now, can do more complicated calculation later local hitAvg = hitMin + (hitMax - hitMin) / 2 local critAvg = critMin + (critMax - critMin) / 2 local hitElementalAilmentChance = (hitAvg / enemyThreshold) / 0.04 - local critElementalAilmentChance = (critAvg / enemyThreshold) / 0.04 + local critElementalAilmentChance = (critAvg / enemyThreshold) / 0.04 + ConPrintf("raw %s hitElementalAilmentChance: %s", ailment, hitElementalAilmentChance) + ConPrintf("raw %s critElementalAilmentChance: %s", ailment, critElementalAilmentChance) if skillFlags.hit and not skillModList:Flag(cfg, "Cannot"..ailment) then output[ailment.."ChanceOnHit"] = m_min(100, hitElementalAilmentChance) @@ -4470,20 +4500,14 @@ function calcs.offence(env, actor, activeSkill) end end - -- FIXME: use damagingAilmentConfig - -- FIXME: Handle Blood Mage -> Blood Barbs - calcDamagingAilment("Bleed", "Physical", { - ["Physical"] = true, - }) - - calcDamagingAilment("Poison", "Chaos", { - ["Physical"] = true, - ["Chaos"] = true, - }) - - calcDamagingAilment("Ignite", "Fire", { - ["Fire"] = true, - }) + -- Calculate damaging ailment values + for _, damagingAilment in ipairs({"Bleed", "Poison", "Ignite"}) do + calcDamagingAilment( + damagingAilment, + defaultAilmentDamageTypes[damagingAilment]["DamageType"], + defaultAilmentDamageTypes[damagingAilment]["ScalesFrom"] + ) + end -- Calculate non-damaging ailments effect and duration modifiers local nonDamagingAilmentsConfig = { @@ -4524,7 +4548,7 @@ function calcs.offence(env, actor, activeSkill) s_format("Ailment mode: %s ^8(can be changed in the Configuration tab)", ailmentMode == "CRIT" and "Crits Only" or "Average Damage") } end - local baseVal = calcAilmentDamage("Freeze", output.CritChance, calcAverageSourceDamage("Freeze")) * skillModList:More(cfg, "FreezeAsThoughDealing") + local baseVal = calcAilmentDamage("Freeze", output.CritChance, calcAverageUnmitigatedSourceDamage("Freeze", defaultAilmentDamageTypes["Freeze"]["ScalesFrom"])) * skillModList:More(cfg, "FreezeAsThoughDealing") if baseVal > 0 then skillFlags.freeze = true output.FreezeDurationMod = 1 + skillModList:Sum("INC", cfg, "EnemyFreezeDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration") / 100 + enemyDB:Sum("INC", nil, "SelfFreezeDuration", "SelfElementalAilmentDuration", "SelfAilmentDuration", "HoarfrostFreezeDuration") / 100 @@ -4541,7 +4565,7 @@ function calcs.offence(env, actor, activeSkill) s_format("Ailment mode: %s ^8(can be changed in the Configuration tab)", ailmentMode == "CRIT" and "Crits Only" or "Average Damage") } end - local damage = calcAilmentDamage(ailment, output.CritChance, calcAverageSourceDamage(ailment)) * skillModList:More(cfg, ailment.."AsThoughDealing") + local damage = calcAilmentDamage(ailment, output.CritChance, calcAverageUnmitigatedSourceDamage(ailment, defaultAilmentDamageTypes[ailment]["ScalesFrom"])) * skillModList:More(cfg, ailment.."AsThoughDealing") if damage > 0 then skillFlags[string.lower(ailment)] = true local incDur = skillModList:Sum("INC", cfg, "Enemy"..ailment.."Duration", "EnemyElementalAilmentDuration", "EnemyAilmentDuration") + enemyDB:Sum("INC", nil, "Self"..ailment.."Duration", "SelfElementalAilmentDuration", "SelfAilmentDuration") diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index dbaa9731a9..70335af3a4 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -885,19 +885,8 @@ return { { 1, "Bleed", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Bleed", data = { extra = "{0:output:BleedChance}% {1:output:BleedDPS} {2:output:BleedDuration}s", flag = "bleed", - { label = "Max Bleed Stacks", { format = "{0:output:BleedStacksMax}", { modName = "BleedStacksMax" } }, }, - { label = "Stack Potential", { format = "{2:output:BleedStackPotentialPercent}%", { breakdown = "BleedStackPotential" } }}, - { label = "Average Bleed Roll", { format = "{2:output:BleedRollAverage}%", { breakdown = "BleedRollAverage" } }}, - { label = "Chance to Bleed", { format = "{0:output:BleedChance}%", - { breakdown = "MainHand.BleedChance" }, - { breakdown = "OffHand.BleedChance" }, - { breakdown = "BleedChance" }, - { label = "Main Hand", flag = "weapon1Attack", modName = "BleedChance", modType = "BASE", cfg = "weapon1" }, - { label = "Off Hand", flag = "weapon2Attack", modName = "BleedChance", modType = "BASE", cfg = "weapon2" }, - { label = "Enemy modifiers", modName = "SelfBleedChance", modType = "BASE", enemy = true }, - { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, - }, }, - { label = "Magnitude Effect", { format = "x {2:output:BleedMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "bleed" }, }, }, + { label = "Enemy Ail. Thresh.", { format = "{0:output:EnemyAilmentThreshold}", { modname = "EnemyAilmentThreshold" }, }, }, + { label = "Source Physical", textSize = 12, notFlag = "attack", haveOutput = "BleedPhysicalMax", { format = "{0:output:BleedPhysicalMin} to {0:output:BleedPhysicalMax}", { breakdown = "BleedPhysical" }, }, }, { label = "MH Source Physical", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.BleedPhysicalMax", { format = "{0:output:MainHand.BleedPhysicalMin} to {0:output:MainHand.BleedPhysicalMax}", { breakdown = "MainHand.BleedPhysical" }, }, }, { label = "OH Source Physical", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.BleedPhysicalMax", { format = "{0:output:OffHand.BleedPhysicalMin} to {0:output:OffHand.BleedPhysicalMax}", { breakdown = "OffHand.BleedPhysical" }, }, }, @@ -913,40 +902,41 @@ return { { label = "Source Chaos", textSize = 12, notFlag = "attack", haveOutput = "BleedChaosMax", { format = "{0:output:BleedChaosMin} to {0:output:BleedChaosMax}", { breakdown = "BleedChaos" }, }, }, { label = "MH Source Chaos", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.BleedChaosMax", { format = "{0:output:MainHand.BleedChaosMin} to {0:output:MainHand.BleedChaosMax}", { breakdown = "MainHand.BleedChaos" }, }, }, { label = "OH Source Chaos", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.BleedChaosMax", { format = "{0:output:OffHand.BleedChaosMin} to {0:output:OffHand.BleedChaosMax}", { breakdown = "OffHand.BleedChaos" }, }, }, - { label = "Effective DPS Mod", flag = "effective", { format = "x {3:output:BleedEffMult}", { breakdown = "BleedEffMult" }, { label = "Enemy modifiers", modName = { "DamageTaken", "DamageTakenOverTime", "PhysicalDamageTaken", "PhysicalDamageTakenOverTime", "PhysicalDamageReduction" }, enemy = true, cfg = "bleed" }, }, }, - { label = "Bleed DPS", { format = "{1:output:BleedDPS}", - { breakdown = "BleedDPS" }, - { breakdown = "MainHand.BleedDPS" }, - { breakdown = "OffHand.BleedDPS" }, + + { label = "Chance to Bleed", { format = "{0:output:BleedChance}%", + { breakdown = "MainHand.BleedChance" }, + { breakdown = "OffHand.BleedChance" }, + { breakdown = "BleedChance" }, + { label = "Main Hand", flag = "weapon1Attack", modName = "BleedChance", modType = "BASE", cfg = "weapon1" }, + { label = "Off Hand", flag = "weapon2Attack", modName = "BleedChance", modType = "BASE", cfg = "weapon2" }, + { label = "Enemy modifiers", modName = "SelfBleedChance", modType = "BASE", enemy = true }, + { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, }, }, + { label = "Max Bleed Stacks", { format = "{0:output:BleedStacksMax}", { modName = "BleedStacksMax" } }, }, { label = "Bleed Duration", { format = "{2:output:BleedDuration}s", { breakdown = "BleedDuration" }, { label = "Player modifiers", modName = { "EnemyBleedDuration", "EnemyAilmentDuration", "SkillAndDamagingAilmentDuration", "BleedFaster" }, cfg = "bleed" }, { label = "Enemy modifiers", modName = { "SelfBleedDuration", "SelfAilmentDuration", "SelfBleedFaster", "BleedExpireRate" }, enemy = true }, }, }, + { label = "Stack Potential", { format = "{2:output:BleedStackPotentialPercent}%", { breakdown = "BleedStackPotential" } }}, + { label = "Average Bleed Roll", { format = "{2:output:BleedRollAverage}%", { breakdown = "BleedRollAverage" } }}, + { label = "Magnitude Effect", { format = "x {2:output:BleedMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "bleed" }, }, }, + { label = "Effective DPS Mod", flag = "effective", { format = "x {3:output:BleedEffMult}", { breakdown = "BleedEffMult" }, { label = "Enemy modifiers", modName = { "DamageTaken", "DamageTakenOverTime", "PhysicalDamageTaken", "PhysicalDamageTakenOverTime", "PhysicalDamageReduction" }, enemy = true, cfg = "bleed" }, }, }, + { label = "Bleed DPS", { format = "{1:output:BleedDPS}", + { breakdown = "BleedDPS" }, + { breakdown = "MainHand.BleedDPS" }, + { breakdown = "OffHand.BleedDPS" }, + }, }, { label = "Dmg. of all Bleeds", { format = "{1:output:BleedDamage}", { breakdown = "MainHand.BleedDamage" }, { breakdown = "OffHand.BleedDamage" }, { breakdown = "BleedDamage" }, - }, }, + } }, } } } }, { 1, "Poison", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Poison", data = { extra = "{0:output:PoisonChance}% {1:output:PoisonDPS} {2:output:PoisonDuration}s", flag = "poison", - { label = "Max Poison Stacks", { format = "{1:output:PoisonStacksMax}", { modName = "PoisonStacks" }, }, }, - { label = "Stack Potential", { format = "{2:output:PoisonStackPotentialPercent}%", { breakdown = "PoisonStackPotential" } }}, - { label = "Average Poison Roll", { format = "{2:output:PoisonRollAverage}%", { breakdown = "PoisonRollAverage" } }}, - { label = "Chance to Poison", { format = "{0:output:PoisonChance}%", - { breakdown = "MainHand.PoisonChance" }, - { breakdown = "OffHand.PoisonChance" }, - { breakdown = "PoisonChance" }, - { notFlag = "attack", modName = "PoisonChance", modType = "BASE", cfg = "skill" }, - { label = "Main Hand", flag = "weapon1Attack", modName = "PoisonChance", modType = "BASE", cfg = "weapon1" }, - { label = "Off Hand", flag = "weapon2Attack", modName = "PoisonChance", modType = "BASE", cfg = "weapon2" }, - { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, - }, }, - { label = "Magnitude Effect", { format = "x {2:output:PoisonMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "poison" }, }, }, { label = "Source Physical", textSize = 12, notFlag = "attack", haveOutput = "PoisonPhysicalMax", { format = "{0:output:PoisonPhysicalMin} to {0:output:PoisonPhysicalMax}", { breakdown = "PoisonPhysical" }, }, }, { label = "MH Source Physical", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.PoisonPhysicalMax", { format = "{0:output:MainHand.PoisonPhysicalMin} to {0:output:MainHand.PoisonPhysicalMax}", { breakdown = "MainHand.PoisonPhysical" }, }, }, { label = "OH Source Physical", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.PoisonPhysicalMax", { format = "{0:output:OffHand.PoisonPhysicalMin} to {0:output:OffHand.PoisonPhysicalMax}", { breakdown = "OffHand.PoisonPhysical" }, }, }, @@ -962,6 +952,25 @@ return { { label = "Source Chaos", textSize = 12, notFlag = "attack", haveOutput = "PoisonChaosMax", { format = "{0:output:PoisonChaosMin} to {0:output:PoisonChaosMax}", { breakdown = "PoisonChaos" }, }, }, { label = "MH Source Chaos", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.PoisonChaosMax", { format = "{0:output:MainHand.PoisonChaosMin} to {0:output:MainHand.PoisonChaosMax}", { breakdown = "MainHand.PoisonChaos" }, }, }, { label = "OH Source Chaos", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.PoisonChaosMax", { format = "{0:output:OffHand.PoisonChaosMin} to {0:output:OffHand.PoisonChaosMax}", { breakdown = "OffHand.PoisonChaos" }, }, }, + + { label = "Chance to Poison", { format = "{0:output:PoisonChance}%", + { breakdown = "MainHand.PoisonChance" }, + { breakdown = "OffHand.PoisonChance" }, + { breakdown = "PoisonChance" }, + { notFlag = "attack", modName = "PoisonChance", modType = "BASE", cfg = "skill" }, + { label = "Main Hand", flag = "weapon1Attack", modName = "PoisonChance", modType = "BASE", cfg = "weapon1" }, + { label = "Off Hand", flag = "weapon2Attack", modName = "PoisonChance", modType = "BASE", cfg = "weapon2" }, + { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, + }, }, + { label = "Max Poison Stacks", { format = "{1:output:PoisonStacksMax}", { modName = "PoisonStacks" }, }, }, + { label = "Poison Duration", { format = "{2:output:PoisonDuration}s", + { breakdown = "PoisonDuration" }, + { label = "Player modifiers", modName = { "EnemyPoisonDuration", "EnemyAilmentDuration", "SkillAndDamagingAilmentDuration", "PoisonFaster" }, cfg = "poison" }, + { label = "Enemy modifiers", modName = { "SelfPoisonDuration", "SelfAilmentDuration", "SelfPoisonFaster" }, enemy = true }, + }, }, + { label = "Stack Potential", { format = "{2:output:PoisonStackPotentialPercent}%", { breakdown = "PoisonStackPotential" } }}, + { label = "Average Poison Roll", { format = "{2:output:PoisonRollAverage}%", { breakdown = "PoisonRollAverage" } }}, + { label = "Magnitude Effect", { format = "x {2:output:PoisonMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "poison" }, }, }, { label = "Effective DPS Mod", flag = "effective", { format = "x {3:output:PoisonEffMult}", { breakdown = "PoisonEffMult" }, { label = "Enemy modifiers", modName = { "ChaosResist", "DamageTaken", "DamageTakenOverTime", "ChaosDamageTaken", "ChaosDamageTakenOverTime" }, enemy = true }, @@ -972,11 +981,6 @@ return { { breakdown = "OffHand.PoisonDPS" }, }, }, { label = "Caustic Ground", haveOutput = "CausticGroundFromPoison", { format = "{0:output:CausticGroundDPS}", { breakdown = "CausticGroundDPS" } } }, - { label = "Poison Duration", { format = "{2:output:PoisonDuration}s", - { breakdown = "PoisonDuration" }, - { label = "Player modifiers", modName = { "EnemyPoisonDuration", "EnemyAilmentDuration", "SkillAndDamagingAilmentDuration", "PoisonFaster" }, cfg = "poison" }, - { label = "Enemy modifiers", modName = { "SelfPoisonDuration", "SelfAilmentDuration", "SelfPoisonFaster" }, enemy = true }, - }, }, { label = "Dmg. of all Poisons", { format = "{1:output:PoisonDamage}", { breakdown = "MainHand.PoisonDamage" }, { breakdown = "OffHand.PoisonDamage" }, @@ -987,18 +991,8 @@ return { { 1, "Ignite", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Ignite", data = { extra = "{0:output:IgniteChancePerHit}% {1:output:IgniteDPS} {2:output:IgniteDuration}s", flag = "ignite", - { label = "Max Ignite Stacks", { format = "{1:output:IgniteStacksMax}", { modName = "IgniteStacks" }, }, }, - { label = "Stack Potential", { format = "{2:output:IgniteStackPotentialPercent}%", { breakdown = "IgniteStackPotential" } }}, - { label = "Average Ignite Roll", { format = "{2:output:IgniteRollAverage}%", { breakdown = "IgniteRollAverage" } }}, - { label = "Chance to Ignite", { format = "{0:output:IgniteChancePerHit}%", - { breakdown = "MainHand.IgniteChance" }, - { breakdown = "OffHand.IgniteChance" }, - { breakdown = "IgniteChance" }, - { label = "Player modifiers", modName = "EnemyIgniteChance", cfg = "skill" }, - { label = "Enemy modifiers", modName = "SelfIgniteChance", enemy = true }, - { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, - }, }, - { label = "Magnitude Effect", { format = "x {2:output:IgniteMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "ignite" }, }, }, + { label = "Enemy Ail. Thresh.", { format = "{0:output:EnemyAilmentThreshold}", { modname = "EnemyAilmentThreshold" }, }, }, + { label = "Source Physical", textSize = 12, notFlag = "attack", haveOutput = "IgnitePhysicalMax", { format = "{0:output:IgnitePhysicalMin} to {0:output:IgnitePhysicalMax}", { breakdown = "IgnitePhysical" }, }, }, { label = "MH Source Physical", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.IgnitePhysicalMax", { format = "{0:output:MainHand.IgnitePhysicalMin} to {0:output:MainHand.IgnitePhysicalMax}", { breakdown = "MainHand.IgnitePhysical" }, }, }, { label = "OH Source Physical", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.IgnitePhysicalMax", { format = "{0:output:OffHand.IgnitePhysicalMin} to {0:output:OffHand.IgnitePhysicalMax}", { breakdown = "OffHand.IgnitePhysical" }, }, }, @@ -1014,6 +1008,24 @@ return { { label = "Source Chaos", textSize = 12, notFlag = "attack", haveOutput = "IgniteChaosMax", { format = "{0:output:IgniteChaosMin} to {0:output:IgniteChaosMax}", { breakdown = "IgniteChaos" }, }, }, { label = "MH Source Chaos", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.IgniteChaosMax", { format = "{0:output:MainHand.IgniteChaosMin} to {0:output:MainHand.IgniteChaosMax}", { breakdown = "MainHand.IgniteChaos" }, }, }, { label = "OH Source Chaos", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.IgniteChaosMax", { format = "{0:output:OffHand.IgniteChaosMin} to {0:output:OffHand.IgniteChaosMax}", { breakdown = "OffHand.IgniteChaos" }, }, }, + + { label = "Chance to Ignite", { format = "{0:output:IgniteChancePerHit}%", + { breakdown = "MainHand.IgniteChance" }, + { breakdown = "OffHand.IgniteChance" }, + { breakdown = "IgniteChance" }, + { label = "Player modifiers", modName = "EnemyIgniteChance", cfg = "skill" }, + { label = "Enemy modifiers", modName = "SelfIgniteChance", enemy = true }, + { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, + }, }, + { label = "Max Ignite Stacks", { format = "{1:output:IgniteStacksMax}", { modName = "IgniteStacks" }, }, }, + { label = "Ignite Duration", { format = "{2:output:IgniteDuration}s", + { breakdown = "IgniteDuration" }, + { label = "Player modifiers", modName = { "EnemyIgniteDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration", "SkillAndDamagingAilmentDuration", "IgniteFaster", "IgniteSlower" }, cfg = "skill" }, + { label = "Enemy modifiers", modName = {"SelfIgniteDuration", "SelfAilmentDuration", "SelfElementalAilmentDuration", "SelfIgniteFaster"}, enemy = true }, + }, }, + { label = "Stack Potential", { format = "{2:output:IgniteStackPotentialPercent}%", { breakdown = "IgniteStackPotential" } }}, + { label = "Average Ignite Roll", { format = "{2:output:IgniteRollAverage}%", { breakdown = "IgniteRollAverage" } }}, + { label = "Magnitude Effect", { format = "x {2:output:IgniteMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "ignite" }, }, }, { label = "Effective DPS Mod", flag = "effective", notFlag = "igniteToChaos", { format = "x {3:output:IgniteEffMult}", { breakdown = "IgniteEffMult" }, { label = "Enemy modifiers", modName = { "FireResist", "ElementalResist", "DamageTaken", "DamageTakenOverTime", "FireDamageTaken", "FireDamageTakenOverTime", "ElementalDamageTaken" }, enemy = true }, @@ -1028,11 +1040,6 @@ return { { breakdown = "OffHand.IgniteDPS" }, }, }, { label = "Burning Ground", haveOutput = "BurningGroundFromIgnite", { format = "{0:output:BurningGroundDPS}", { breakdown = "BurningGroundDPS" } } }, - { label = "Ignite Duration", { format = "{2:output:IgniteDuration}s", - { breakdown = "IgniteDuration" }, - { label = "Player modifiers", modName = { "EnemyIgniteDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration", "SkillAndDamagingAilmentDuration", "IgniteFaster", "IgniteSlower" }, cfg = "skill" }, - { label = "Enemy modifiers", modName = {"SelfIgniteDuration", "SelfAilmentDuration", "SelfElementalAilmentDuration", "SelfIgniteFaster"}, enemy = true }, - }, }, { label = "Dmg. of all Ignites", { format = "{1:output:IgniteDamage}", { breakdown = "MainHand.IgniteDamage" }, { breakdown = "OffHand.IgniteDamage" }, @@ -1195,6 +1202,13 @@ return { { label = "Total Scorch", modName = "ElementalResistByScorch", enemy = true, cfg = "skill" }, }, }, { label = "Effect of Chill", bgCol = colorCodes.CHILLBG, flag = "chill", haveOutput = "ChillSourceEffect", { format = "{0:output:ChillSourceEffect}%", { breakdown = "DotChill" }, }, }, + { label = "Chill Duration", bgCol = colorCodes.CHILLBG, flag = "chill", { format = "{2:output:ChillDuration}s", + { breakdown = "MainHand.ChillDuration" }, + { breakdown = "OffHand.ChillDuration" }, + { breakdown = "ChillDuration" }, + { label = "Player modifiers", modName = { "EnemyChillDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration" }, cfg = "skill" }, + { label = "Enemy modifiers", modName = { "SelfChillDuration", "SelfAilmentDuration", "SelfElementalAilmentDuration", "BuffExpireFaster" }, enemy = true }, + }, }, { label = "Chill Effect Mod", bgCol = colorCodes.CHILLBG, flag = "chill", { format = "x {2:output:ChillEffectMod}", { breakdown = "ChillEffectMod" }, { breakdown = "MainHand.ChillDPS" }, @@ -1203,13 +1217,6 @@ return { { label = "Player modifiers", modName = { "EnemyChillMagnitude", "ChillAsThoughDealing" }, cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfChillEffect", enemy = true }, }, }, - { label = "Chill Duration", bgCol = colorCodes.CHILLBG, flag = "chill", { format = "{2:output:ChillDuration}s", - { breakdown = "MainHand.ChillDuration" }, - { breakdown = "OffHand.ChillDuration" }, - { breakdown = "ChillDuration" }, - { label = "Player modifiers", modName = { "EnemyChillDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration" }, cfg = "skill" }, - { label = "Enemy modifiers", modName = { "SelfChillDuration", "SelfAilmentDuration", "SelfElementalAilmentDuration", "BuffExpireFaster" }, enemy = true }, - }, }, { label = "Maximum Chill", bgCol = colorCodes.CHILLBG, flag = "chill", { format = "{0:output:MaximumChill}%", { modName = "ChillMax" }, }, }, @@ -1261,16 +1268,6 @@ return { { label = "Configured Brittle", modName = "BrittleVal", enemy = true, modType = "BASE" }, { label = "Guaranteed Brittles", modName = "BrittleOverride", modType = "BASE" }, }, }, - { label = "Shock Effect Mod", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "x {2:output:ShockEffectMod}", - { breakdown = "ShockEffectMod" }, - { breakdown = "MainHand.ShockDPS" }, - { breakdown = "OffHand.ShockDPS" }, - { breakdown = "ShockDPS" }, - { label = "Player modifiers", notFlag = "attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "skill" }, - { label = "Main hand modifiers", flag = "weapon1Attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "weapon1" }, - { label = "Off hand modifiers", flag = "weapon2Attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "weapon2" }, - { label = "Enemy modifiers", modName = "SelfShockEffect", enemy = true }, - }, }, { label = "Chance to Shock", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:ShockChance}%", { breakdown = "MainHand.ShockChance" }, { breakdown = "OffHand.ShockChance" }, @@ -1285,6 +1282,16 @@ return { { label = "Player modifiers", modName = { "EnemyShockDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration" }, cfg = "skill" }, { label = "Enemy modifiers", modName = { "SelfShockDuration", "SelfAilmentDuration", "SelfElementalAilmentDuration", "BuffExpireFaster" }, enemy = true }, }, }, + { label = "Shock Effect Mod", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "x {2:output:ShockEffectMod}", + { breakdown = "ShockEffectMod" }, + { breakdown = "MainHand.ShockDPS" }, + { breakdown = "OffHand.ShockDPS" }, + { breakdown = "ShockDPS" }, + { label = "Player modifiers", notFlag = "attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "skill" }, + { label = "Main hand modifiers", flag = "weapon1Attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "weapon1" }, + { label = "Off hand modifiers", flag = "weapon2Attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "weapon2" }, + { label = "Enemy modifiers", modName = "SelfShockEffect", enemy = true }, + }, }, { label = "Maximum Shock", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:MaximumShock}%", { modName = "ShockMax" }, }, }, From 0fab122c72edc2009fcac7ee93c5f751319d35c0 Mon Sep 17 00:00:00 2001 From: Default global Date: Sun, 19 Jan 2025 19:04:34 -0800 Subject: [PATCH 04/23] Cleanup for PR --- src/Modules/CalcOffence.lua | 22 ++++++++++------------ src/Modules/CalcSections.lua | 1 + 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 6fc390560f..eb3bd4b285 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3813,6 +3813,7 @@ function calcs.offence(env, actor, activeSkill) -- Freeze (non-damaging) -- Stun (non-damaging - note that I think the game doesn't consider this an "ailment") + -- Possible direct (ie not about damage hit modifier) crit effects on ailments (as of Jan 19 2025) -- Increased magnitude of damaging ailments inflicted with critical hits @@ -3946,7 +3947,6 @@ function calcs.offence(env, actor, activeSkill) local canCrit = not skillModList:Flag(cfg, "AilmentsAreNeverFromCrit") local sourceHitDmg, sourceCritDmg = 0, 0 for _, dmg_type in ipairs(dmgTypeList) do - ConPrintf("canDoAilment(%s, %s) = %s", ailment, dmg_type, canDoAilment(ailment, dmg_type, defaultDamageTypes)) if canDoAilment(ailment, dmg_type, defaultDamageTypes) then sourceHitDmg = sourceHitDmg + output[dmg_type.."HitAverage"] if canCrit then @@ -3958,7 +3958,7 @@ function calcs.offence(env, actor, activeSkill) end -- Calculates damage to be used in damaging ailment calculations - local function calcAilmentSourceDamage(ailment, defaultDamageTypes) + local function calcMinMaxUnmitigatedAilmentSourceDamage(ailment, defaultDamageTypes) -- requires: -- output.StoredHitMin -- output.StoredHitMax @@ -4070,10 +4070,8 @@ function calcs.offence(env, actor, activeSkill) return baseVal end - -- Poison/Ignite/Bleed - -- Chaos/Fire/Physical - -- Chaos+Physical/Fire/Physical - local function calcDamagingAilment(ailment, ailmentDamageType, defaultDamageTypes) + -- Calculate global / breakdown values for a damaging ailment + local function calcDamagingAilmentOutputs(ailment, ailmentDamageType, defaultDamageTypes) -- requires: -- output.ChanceOnHit -- output.ChanceOnCrit @@ -4213,7 +4211,7 @@ function calcs.offence(env, actor, activeSkill) end end - local hitMin, hitMax, critMin, critMax = calcAilmentSourceDamage(ailment, defaultDamageTypes) + local hitMin, hitMax, critMin, critMax = calcMinMaxUnmitigatedAilmentSourceDamage(ailment, defaultDamageTypes) local hitAvg = hitMin + ((hitMax - hitMin) * ailmentRollAverage / 100) local critAvg = critMin + ((critMax - critMin) * ailmentRollAverage / 100) if globalBreakdown then @@ -4427,13 +4425,13 @@ function calcs.offence(env, actor, activeSkill) -- For Chill in-game tooltip says: -- "All Hits that have any Contribution to Chill Magnitude can Chill, without requiring an explicit chance to inflict, -- provided the Magnitudes meets a minimum threshold. So low damage Hits may still fail to Chill." - local dealtCold = calcAverageUnmitigatedSourceDamage("Chill", defaultAilmentDamageTypes["Chill"]["ScalesFrom"]) - ConPrintf(dealtCold) + local unmitigatedColdDamage = calcAverageUnmitigatedSourceDamage("Chill", defaultAilmentDamageTypes["Chill"]["ScalesFrom"]) + ConPrintf(unmitigatedColdDamage) ConPrintf(enemyThreshold) ConPrintf(output["ColdHitAverage"]) local chillAilmentThresholdGuess = enemyThreshold * 0.04 * 15 -- Assume 15% is sufficient output['ChillAilmentThresholdGuess'] = chillAilmentThresholdGuess - if dealtCold > chillAilmentThresholdGuess then + if unmitigatedColdDamage > chillAilmentThresholdGuess then output["ChillChanceOnHit"] = 100 output["ChillChanceOnCrit"] = 100 skillFlags["inflictChill"] = true @@ -4452,7 +4450,7 @@ function calcs.offence(env, actor, activeSkill) -- Calculate scaling threshold ailment chance for _, ailment in ipairs({"Ignite", "Shock"}) do - local hitMin, hitMax, critMin, critMax = calcAilmentSourceDamage(ailment, defaultAilmentDamageTypes[ailment]["ScalesFrom"]) + local hitMin, hitMax, critMin, critMax = calcMinMaxUnmitigatedAilmentSourceDamage(ailment, defaultAilmentDamageTypes[ailment]["ScalesFrom"]) -- TODO: average for now, can do more complicated calculation later local hitAvg = hitMin + (hitMax - hitMin) / 2 local critAvg = critMin + (critMax - critMin) / 2 @@ -4502,7 +4500,7 @@ function calcs.offence(env, actor, activeSkill) -- Calculate damaging ailment values for _, damagingAilment in ipairs({"Bleed", "Poison", "Ignite"}) do - calcDamagingAilment( + calcDamagingAilmentOutputs( damagingAilment, defaultAilmentDamageTypes[damagingAilment]["DamageType"], defaultAilmentDamageTypes[damagingAilment]["ScalesFrom"] diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 70335af3a4..756bd52c77 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -1268,6 +1268,7 @@ return { { label = "Configured Brittle", modName = "BrittleVal", enemy = true, modType = "BASE" }, { label = "Guaranteed Brittles", modName = "BrittleOverride", modType = "BASE" }, }, }, + { label = "Enemy Ail. Thresh.", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:EnemyAilmentThreshold}", { modname = "EnemyAilmentThreshold" }, }, }, { label = "Chance to Shock", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:ShockChance}%", { breakdown = "MainHand.ShockChance" }, { breakdown = "OffHand.ShockChance" }, From 81cc48d791c596a48c4e544e250c122fc61e9db7 Mon Sep 17 00:00:00 2001 From: Default global Date: Sun, 19 Jan 2025 19:48:35 -0800 Subject: [PATCH 05/23] Remove leftover ConPrintf values --- src/Modules/CalcOffence.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index eb3bd4b285..67498c7d12 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -4426,9 +4426,9 @@ function calcs.offence(env, actor, activeSkill) -- "All Hits that have any Contribution to Chill Magnitude can Chill, without requiring an explicit chance to inflict, -- provided the Magnitudes meets a minimum threshold. So low damage Hits may still fail to Chill." local unmitigatedColdDamage = calcAverageUnmitigatedSourceDamage("Chill", defaultAilmentDamageTypes["Chill"]["ScalesFrom"]) - ConPrintf(unmitigatedColdDamage) - ConPrintf(enemyThreshold) - ConPrintf(output["ColdHitAverage"]) + -- ConPrintf(unmitigatedColdDamage) + -- ConPrintf(enemyThreshold) + -- ConPrintf(output["ColdHitAverage"]) local chillAilmentThresholdGuess = enemyThreshold * 0.04 * 15 -- Assume 15% is sufficient output['ChillAilmentThresholdGuess'] = chillAilmentThresholdGuess if unmitigatedColdDamage > chillAilmentThresholdGuess then @@ -4456,8 +4456,8 @@ function calcs.offence(env, actor, activeSkill) local critAvg = critMin + (critMax - critMin) / 2 local hitElementalAilmentChance = (hitAvg / enemyThreshold) / 0.04 local critElementalAilmentChance = (critAvg / enemyThreshold) / 0.04 - ConPrintf("raw %s hitElementalAilmentChance: %s", ailment, hitElementalAilmentChance) - ConPrintf("raw %s critElementalAilmentChance: %s", ailment, critElementalAilmentChance) + -- ConPrintf("raw %s hitElementalAilmentChance: %s", ailment, hitElementalAilmentChance) + -- ConPrintf("raw %s critElementalAilmentChance: %s", ailment, critElementalAilmentChance) if skillFlags.hit and not skillModList:Flag(cfg, "Cannot"..ailment) then output[ailment.."ChanceOnHit"] = m_min(100, hitElementalAilmentChance) From ce2ce4d59309d8afc2e9af5baf20cd6cbdb50383 Mon Sep 17 00:00:00 2001 From: Default global Date: Sun, 26 Jan 2025 18:52:34 -0800 Subject: [PATCH 06/23] Implement @deathbeam feedback 1. Make effective DPS visible again 2. Make damage per stack visible again (renamed to "Dmg./ Stack" for clarity) --- src/Modules/CalcSections.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 756bd52c77..59610386c1 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -980,6 +980,11 @@ return { { breakdown = "MainHand.PoisonDPS" }, { breakdown = "OffHand.PoisonDPS" }, }, }, + { label = "Dmg./Poison Stack", { format = "{1:output:PoisonDamage}", + { breakdown = "MainHand.PoisonDamage" }, + { breakdown = "OffHand.PoisonDamage" }, + { breakdown = "PoisonDamage" }, + }, }, { label = "Caustic Ground", haveOutput = "CausticGroundFromPoison", { format = "{0:output:CausticGroundDPS}", { breakdown = "CausticGroundDPS" } } }, { label = "Dmg. of all Poisons", { format = "{1:output:PoisonDamage}", { breakdown = "MainHand.PoisonDamage" }, @@ -1039,6 +1044,11 @@ return { { breakdown = "MainHand.IgniteDPS" }, { breakdown = "OffHand.IgniteDPS" }, }, }, + { label = "Dmg./Ignite Stack", { format = "{1:output:IgniteDamage}", + { breakdown = "MainHand.IgniteDamage" }, + { breakdown = "OffHand.IgniteDamage" }, + { breakdown = "IgniteDamage" }, + }, }, { label = "Burning Ground", haveOutput = "BurningGroundFromIgnite", { format = "{0:output:BurningGroundDPS}", { breakdown = "BurningGroundDPS" } } }, { label = "Dmg. of all Ignites", { format = "{1:output:IgniteDamage}", { breakdown = "MainHand.IgniteDamage" }, From ec214b1a9292583ce0c1e6af0056d2d46b3a2008 Mon Sep 17 00:00:00 2001 From: Default global Date: Sun, 26 Jan 2025 19:44:06 -0800 Subject: [PATCH 07/23] Remove rebase leftovers --- src/Modules/CalcSections.lua | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 59610386c1..756bd52c77 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -980,11 +980,6 @@ return { { breakdown = "MainHand.PoisonDPS" }, { breakdown = "OffHand.PoisonDPS" }, }, }, - { label = "Dmg./Poison Stack", { format = "{1:output:PoisonDamage}", - { breakdown = "MainHand.PoisonDamage" }, - { breakdown = "OffHand.PoisonDamage" }, - { breakdown = "PoisonDamage" }, - }, }, { label = "Caustic Ground", haveOutput = "CausticGroundFromPoison", { format = "{0:output:CausticGroundDPS}", { breakdown = "CausticGroundDPS" } } }, { label = "Dmg. of all Poisons", { format = "{1:output:PoisonDamage}", { breakdown = "MainHand.PoisonDamage" }, @@ -1044,11 +1039,6 @@ return { { breakdown = "MainHand.IgniteDPS" }, { breakdown = "OffHand.IgniteDPS" }, }, }, - { label = "Dmg./Ignite Stack", { format = "{1:output:IgniteDamage}", - { breakdown = "MainHand.IgniteDamage" }, - { breakdown = "OffHand.IgniteDamage" }, - { breakdown = "IgniteDamage" }, - }, }, { label = "Burning Ground", haveOutput = "BurningGroundFromIgnite", { format = "{0:output:BurningGroundDPS}", { breakdown = "BurningGroundDPS" } } }, { label = "Dmg. of all Ignites", { format = "{1:output:IgniteDamage}", { breakdown = "MainHand.IgniteDamage" }, From a26885a4a27e9144041135925c46c86ef72d11c8 Mon Sep 17 00:00:00 2001 From: Default global Date: Sun, 26 Jan 2025 19:47:02 -0800 Subject: [PATCH 08/23] Fix typo bug added in #569 --- src/Modules/CalcOffence.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 67498c7d12..24cafcdd2b 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -4031,7 +4031,7 @@ function calcs.offence(env, actor, activeSkill) t_insert(breakdownDPS, pass.label..":") end if sourceHitDmg == sourceCritDmg or output.CritChance == 0 then - t_insert(breakdownDPS, "Total base DPS per " .. type .. ":") + t_insert(breakdownDPS, "Total base DPS per " .. ailment .. ":") t_insert(breakdownDPS, s_format("%.1f ^8(source damage)",sourceHitDmg)) if sourceMult > 1 then t_insert(breakdownDPS, s_format("x %.2f ^8(inflicting as though dealing more damage)", sourceMult)) @@ -4055,7 +4055,7 @@ function calcs.offence(env, actor, activeSkill) end end if baseFromHit > 0 and baseFromCrit > 0 then - t_insert(breakdownDPS, "Total base DPS per " .. type .. ":") + t_insert(breakdownDPS, "Total base DPS per " .. ailment .. ":") t_insert(breakdownDPS, s_format("%.1f + %.1f", baseFromHit, baseFromCrit)) if sourceMult == 1 then t_insert(breakdownDPS, s_format("= %.1f", baseVal)) From 64c0ac9c64226b3d3673bca9bb78ef00c7175ecd Mon Sep 17 00:00:00 2001 From: Default global Date: Sun, 26 Jan 2025 19:49:42 -0800 Subject: [PATCH 09/23] Remove ailment threshold from bleed --- src/Modules/CalcSections.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 756bd52c77..e3357a30e4 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -885,8 +885,6 @@ return { { 1, "Bleed", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Bleed", data = { extra = "{0:output:BleedChance}% {1:output:BleedDPS} {2:output:BleedDuration}s", flag = "bleed", - { label = "Enemy Ail. Thresh.", { format = "{0:output:EnemyAilmentThreshold}", { modname = "EnemyAilmentThreshold" }, }, }, - { label = "Source Physical", textSize = 12, notFlag = "attack", haveOutput = "BleedPhysicalMax", { format = "{0:output:BleedPhysicalMin} to {0:output:BleedPhysicalMax}", { breakdown = "BleedPhysical" }, }, }, { label = "MH Source Physical", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.BleedPhysicalMax", { format = "{0:output:MainHand.BleedPhysicalMin} to {0:output:MainHand.BleedPhysicalMax}", { breakdown = "MainHand.BleedPhysical" }, }, }, { label = "OH Source Physical", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.BleedPhysicalMax", { format = "{0:output:OffHand.BleedPhysicalMin} to {0:output:OffHand.BleedPhysicalMax}", { breakdown = "OffHand.BleedPhysical" }, }, }, From 6911696bb32d003f8377b982227e92c83d6e583c Mon Sep 17 00:00:00 2001 From: Default global Date: Sun, 26 Jan 2025 20:28:27 -0800 Subject: [PATCH 10/23] Fix Nightblade feedback (modname -> modName) --- src/Modules/CalcSections.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index e3357a30e4..ae8edf49ce 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -989,7 +989,7 @@ return { { 1, "Ignite", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Ignite", data = { extra = "{0:output:IgniteChancePerHit}% {1:output:IgniteDPS} {2:output:IgniteDuration}s", flag = "ignite", - { label = "Enemy Ail. Thresh.", { format = "{0:output:EnemyAilmentThreshold}", { modname = "EnemyAilmentThreshold" }, }, }, + { label = "Enemy Ail. Thresh.", { format = "{0:output:EnemyAilmentThreshold}", { modName = "EnemyAilmentThreshold" }, }, }, { label = "Source Physical", textSize = 12, notFlag = "attack", haveOutput = "IgnitePhysicalMax", { format = "{0:output:IgnitePhysicalMin} to {0:output:IgnitePhysicalMax}", { breakdown = "IgnitePhysical" }, }, }, { label = "MH Source Physical", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.IgnitePhysicalMax", { format = "{0:output:MainHand.IgnitePhysicalMin} to {0:output:MainHand.IgnitePhysicalMax}", { breakdown = "MainHand.IgnitePhysical" }, }, }, @@ -1266,7 +1266,7 @@ return { { label = "Configured Brittle", modName = "BrittleVal", enemy = true, modType = "BASE" }, { label = "Guaranteed Brittles", modName = "BrittleOverride", modType = "BASE" }, }, }, - { label = "Enemy Ail. Thresh.", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:EnemyAilmentThreshold}", { modname = "EnemyAilmentThreshold" }, }, }, + { label = "Enemy Ail. Thresh.", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:EnemyAilmentThreshold}", { modName = "EnemyAilmentThreshold" }, }, }, { label = "Chance to Shock", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:ShockChance}%", { breakdown = "MainHand.ShockChance" }, { breakdown = "OffHand.ShockChance" }, From 665292af1d972996a90a8880da55ee0473225b25 Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Sun, 9 Feb 2025 16:03:14 +1100 Subject: [PATCH 11/23] Fix PR part 1 Remove print statements Remove close range knockback remove output requirements for functions Fix comment typos --- src/Modules/CalcOffence.lua | 74 +++++++++++++------------------------ 1 file changed, 25 insertions(+), 49 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 5baffcc99d..656cea6570 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3820,10 +3820,9 @@ function calcs.offence(env, actor, activeSkill) -- [Ailments that use buildup mechanic] -- Electrocute (non-damaging) -- Freeze (non-damaging) - -- Stun (non-damaging - note that I think the game doesn't consider this an "ailment") - - - -- Possible direct (ie not about damage hit modifier) crit effects on ailments (as of Jan 19 2025) + -- Stun (non-damaging - not an ailment) + + -- Possible direct (i.e. not about damage hit modifier) crit effects on ailments (as of Jan 19 2025) -- Increased magnitude of damaging ailments inflicted with critical hits -- -- (Notable) Shredding Force @@ -3915,8 +3914,8 @@ function calcs.offence(env, actor, activeSkill) output.ChaosPoisonChance = 0 -- address Weapon1H interaction with Ailment for nodes like Coated Arms (PoE1: Sleight of Hand) - -- bit-and on cfg.flags confirms if the skill has the 1H flag - -- if so bit-or on the targetCfg (e.g. dotCfg) to guarantee for calculations like Sum("INC") and breakdown + -- bit.and on cfg.flags confirms if the skill has the 1H flag + -- if so bit.or on the targetCfg (e.g. dotCfg) to guarantee for calculations like Sum("INC") and breakdown local function checkWeapon1HFlags(targetCfg) targetCfg.flags = bor(targetCfg.flags, band(cfg.flags, ModFlag.Weapon1H)) end @@ -3926,33 +3925,26 @@ function calcs.offence(env, actor, activeSkill) if not canDeal[damageType] then return false end - -- check against input valid types - if ( - (defaultDamageTypes and defaultDamageTypes[damageType]) - or (ailmentData[ailmentType] and damageType == ailmentData[ailmentType].associatedType) - ) then + if ((defaultDamageTypes and defaultDamageTypes[damageType]) + or (ailmentData[ailmentType] and damageType == ailmentData[ailmentType].associatedType)) then if skillModList:Flag(cfg, damageType.."Cannot"..ailmentType) then return false end return true end - -- Process overrides eg. LightningCanFreeze if skillModList:Flag(cfg, damageType.."Can"..ailmentType) then return true end - return false end ---Calculates normal and crit damage to be used in non-damaging ailment calculations ---@param ailment string - ---@return number, number @average hit damage, average crit damage + ---@param defaultDamageTypes table + ---@return number, number average hit damage, average crit damage local function calcAverageUnmitigatedSourceDamage(ailment, defaultDamageTypes) - -- requires: - -- output.HitAverage - -- output.CritAverage local canCrit = not skillModList:Flag(cfg, "AilmentsAreNeverFromCrit") local sourceHitDmg, sourceCritDmg = 0, 0 for _, dmg_type in ipairs(dmgTypeList) do @@ -3965,14 +3957,12 @@ function calcs.offence(env, actor, activeSkill) end return sourceHitDmg, sourceCritDmg end - - -- Calculates damage to be used in damaging ailment calculations + + ---Calculates damage to be used in damaging ailment calculations + ---@param ailment string + ---@param defaultDamageTypes table + ---@return number, number, number, number min / max hit, min / max crit damage local function calcMinMaxUnmitigatedAilmentSourceDamage(ailment, defaultDamageTypes) - -- requires: - -- output.StoredHitMin - -- output.StoredHitMax - -- output.StoredCritMin - -- output.StoredCritMax local canCrit = not skillModList:Flag(cfg, "AilmentsAreNeverFromCrit") local hitMin, hitMax = 0, 0 local critMin, critMax = 0, 0 @@ -3995,11 +3985,14 @@ function calcs.offence(env, actor, activeSkill) return hitMin, hitMax, critMin, critMax end - -- Calculate the inflict chance and base damage of a secondary effect (bleed/poison/ignite/shock/freeze) + ---Calculate the inflict chance and base damage of a secondary effect (bleed/poison/ignite/shock/freeze) + ---@param ailment string + ---@param sourceCritChance number + ---@param sourceHitDmg number + ---@param sourceCritDmg number + ---@param hideFromBreakdown boolean + ---@return number baseVal local function calcAilmentDamage(ailment, sourceCritChance, sourceHitDmg, sourceCritDmg, hideFromBreakdown) - -- requires: - -- output.ChanceOnHit - -- output.ChanceOnCrit local chanceOnHit, chanceOnCrit = output[ailment.."ChanceOnHit"], output[ailment.."ChanceOnCrit"] -- Use sourceCritChance to factor in chance a critical ailment is present @@ -4079,14 +4072,11 @@ function calcs.offence(env, actor, activeSkill) return baseVal end - -- Calculate global / breakdown values for a damaging ailment + ---Calculate global / breakdown values for a damaging ailment + ---@param ailment string + ---@param ailmentDamageType table + ---@param defaultDamageTypes table local function calcDamagingAilmentOutputs(ailment, ailmentDamageType, defaultDamageTypes) - -- requires: - -- output.ChanceOnHit - -- output.ChanceOnCrit - -- output.CritChance - -- output.HitChance - -- output.Cooldown -> output.HitTime or output.Time if not canDeal[ailmentDamageType] then return @@ -4402,15 +4392,6 @@ function calcs.offence(env, actor, activeSkill) -- Knockback (not sure why this is in ailment calc, but I'll calculate it anyway) output.KnockbackChanceOnHit = 0 output.KnockbackChanceOnCrit = 0 - local knockbackWithHitsCloseRange = modDB:Sum("INC", skillCfg, "KnockbackWithHitsCloseRange") - if ( -- (Notable) Clear Space - skillFlags.hit - and not skillModList:Flag(cfg, "CannotKnockback") - and modDB:Flag(nil, "conditionAtCloseRange") - and knockbackWithHitsCloseRange > 0 - ) then - output.KnockbackChanceOnHit = knockbackWithHitsCloseRange - end if skillModList:Flag(cfg, "Knockback") then -- From what I could see, all skills are 0% or 100%, with no enemy mitigation output.KnockbackChanceOnHit = 100 output.KnockbackChanceOnCrit = 100 @@ -4435,9 +4416,6 @@ function calcs.offence(env, actor, activeSkill) -- "All Hits that have any Contribution to Chill Magnitude can Chill, without requiring an explicit chance to inflict, -- provided the Magnitudes meets a minimum threshold. So low damage Hits may still fail to Chill." local unmitigatedColdDamage = calcAverageUnmitigatedSourceDamage("Chill", defaultAilmentDamageTypes["Chill"]["ScalesFrom"]) - -- ConPrintf(unmitigatedColdDamage) - -- ConPrintf(enemyThreshold) - -- ConPrintf(output["ColdHitAverage"]) local chillAilmentThresholdGuess = enemyThreshold * 0.04 * 15 -- Assume 15% is sufficient output['ChillAilmentThresholdGuess'] = chillAilmentThresholdGuess if unmitigatedColdDamage > chillAilmentThresholdGuess then @@ -4465,8 +4443,6 @@ function calcs.offence(env, actor, activeSkill) local critAvg = critMin + (critMax - critMin) / 2 local hitElementalAilmentChance = (hitAvg / enemyThreshold) / 0.04 local critElementalAilmentChance = (critAvg / enemyThreshold) / 0.04 - -- ConPrintf("raw %s hitElementalAilmentChance: %s", ailment, hitElementalAilmentChance) - -- ConPrintf("raw %s critElementalAilmentChance: %s", ailment, critElementalAilmentChance) if skillFlags.hit and not skillModList:Flag(cfg, "Cannot"..ailment) then output[ailment.."ChanceOnHit"] = m_min(100, hitElementalAilmentChance) From f7948f8b1a8727a286493dfc5d4025e3a8f73aca Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Sun, 9 Feb 2025 16:15:18 +1100 Subject: [PATCH 12/23] Fix CalcSections --- src/Modules/CalcSections.lua | 148 +++++++++++++++++------------------ 1 file changed, 72 insertions(+), 76 deletions(-) diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 369dec6f6a..92314f8b6b 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -885,6 +885,19 @@ return { { 1, "Bleed", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Bleed", data = { extra = "{0:output:BleedChance}% {1:output:BleedDPS} {2:output:BleedDuration}s", flag = "bleed", + { label = "Max Bleed Stacks", { format = "{0:output:BleedStacksMax}", { modName = "BleedStacksMax" } }, }, + { label = "Stack Potential", { format = "{2:output:BleedStackPotentialPercent}%", { breakdown = "BleedStackPotential" } }}, + { label = "Average Bleed Roll", { format = "{2:output:BleedRollAverage}%", { breakdown = "BleedRollAverage" } }}, + { label = "Chance to Bleed", { format = "{0:output:BleedChance}%", + { breakdown = "MainHand.BleedChance" }, + { breakdown = "OffHand.BleedChance" }, + { breakdown = "BleedChance" }, + { label = "Main Hand", flag = "weapon1Attack", modName = "BleedChance", modType = "BASE", cfg = "weapon1" }, + { label = "Off Hand", flag = "weapon2Attack", modName = "BleedChance", modType = "BASE", cfg = "weapon2" }, + { label = "Enemy modifiers", modName = "SelfBleedChance", modType = "BASE", enemy = true }, + { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, + }, }, + { label = "Magnitude Effect", { format = "x {2:output:BleedMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "bleed" }, }, }, { label = "Source Physical", textSize = 12, notFlag = "attack", haveOutput = "BleedPhysicalMax", { format = "{0:output:BleedPhysicalMin} to {0:output:BleedPhysicalMax}", { breakdown = "BleedPhysical" }, }, }, { label = "MH Source Physical", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.BleedPhysicalMax", { format = "{0:output:MainHand.BleedPhysicalMin} to {0:output:MainHand.BleedPhysicalMax}", { breakdown = "MainHand.BleedPhysical" }, }, }, { label = "OH Source Physical", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.BleedPhysicalMax", { format = "{0:output:OffHand.BleedPhysicalMin} to {0:output:OffHand.BleedPhysicalMax}", { breakdown = "OffHand.BleedPhysical" }, }, }, @@ -900,41 +913,40 @@ return { { label = "Source Chaos", textSize = 12, notFlag = "attack", haveOutput = "BleedChaosMax", { format = "{0:output:BleedChaosMin} to {0:output:BleedChaosMax}", { breakdown = "BleedChaos" }, }, }, { label = "MH Source Chaos", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.BleedChaosMax", { format = "{0:output:MainHand.BleedChaosMin} to {0:output:MainHand.BleedChaosMax}", { breakdown = "MainHand.BleedChaos" }, }, }, { label = "OH Source Chaos", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.BleedChaosMax", { format = "{0:output:OffHand.BleedChaosMin} to {0:output:OffHand.BleedChaosMax}", { breakdown = "OffHand.BleedChaos" }, }, }, - - { label = "Chance to Bleed", { format = "{0:output:BleedChance}%", - { breakdown = "MainHand.BleedChance" }, - { breakdown = "OffHand.BleedChance" }, - { breakdown = "BleedChance" }, - { label = "Main Hand", flag = "weapon1Attack", modName = "BleedChance", modType = "BASE", cfg = "weapon1" }, - { label = "Off Hand", flag = "weapon2Attack", modName = "BleedChance", modType = "BASE", cfg = "weapon2" }, - { label = "Enemy modifiers", modName = "SelfBleedChance", modType = "BASE", enemy = true }, - { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, - }, }, - { label = "Max Bleed Stacks", { format = "{0:output:BleedStacksMax}", { modName = "BleedStacksMax" } }, }, - { label = "Bleed Duration", { format = "{2:output:BleedDuration}s", - { breakdown = "BleedDuration" }, - { label = "Player modifiers", modName = { "EnemyBleedDuration", "EnemyAilmentDuration", "SkillAndDamagingAilmentDuration", "BleedFaster" }, cfg = "bleed" }, - { label = "Enemy modifiers", modName = { "SelfBleedDuration", "SelfAilmentDuration", "SelfBleedFaster", "BleedExpireRate" }, enemy = true }, - }, }, - { label = "Stack Potential", { format = "{2:output:BleedStackPotentialPercent}%", { breakdown = "BleedStackPotential" } }}, - { label = "Average Bleed Roll", { format = "{2:output:BleedRollAverage}%", { breakdown = "BleedRollAverage" } }}, - { label = "Magnitude Effect", { format = "x {2:output:BleedMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "bleed" }, }, }, { label = "Effective DPS Mod", flag = "effective", { format = "x {3:output:BleedEffMult}", { breakdown = "BleedEffMult" }, { label = "Enemy modifiers", modName = { "DamageTaken", "DamageTakenOverTime", "PhysicalDamageTaken", "PhysicalDamageTakenOverTime", "PhysicalDamageReduction" }, enemy = true, cfg = "bleed" }, }, }, { label = "Bleed DPS", { format = "{1:output:BleedDPS}", { breakdown = "BleedDPS" }, { breakdown = "MainHand.BleedDPS" }, { breakdown = "OffHand.BleedDPS" }, }, }, + { label = "Bleed Duration", { format = "{2:output:BleedDuration}s", + { breakdown = "BleedDuration" }, + { label = "Player modifiers", modName = { "EnemyBleedDuration", "EnemyAilmentDuration", "SkillAndDamagingAilmentDuration", "BleedFaster" }, cfg = "bleed" }, + { label = "Enemy modifiers", modName = { "SelfBleedDuration", "SelfAilmentDuration", "SelfBleedFaster", "BleedExpireRate" }, enemy = true }, + }, }, { label = "Dmg. of all Bleeds", { format = "{1:output:BleedDamage}", { breakdown = "MainHand.BleedDamage" }, { breakdown = "OffHand.BleedDamage" }, { breakdown = "BleedDamage" }, - } }, + }, }, } } } }, { 1, "Poison", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Poison", data = { extra = "{0:output:PoisonChance}% {1:output:PoisonDPS} {2:output:PoisonDuration}s", flag = "poison", + { label = "Max Poison Stacks", { format = "{1:output:PoisonStacksMax}", { modName = "PoisonStacks" }, }, }, + { label = "Stack Potential", { format = "{2:output:PoisonStackPotentialPercent}%", { breakdown = "PoisonStackPotential" } }}, + { label = "Average Poison Roll", { format = "{2:output:PoisonRollAverage}%", { breakdown = "PoisonRollAverage" } }}, + { label = "Chance to Poison", { format = "{0:output:PoisonChance}%", + { breakdown = "MainHand.PoisonChance" }, + { breakdown = "OffHand.PoisonChance" }, + { breakdown = "PoisonChance" }, + { notFlag = "attack", modName = "PoisonChance", modType = "BASE", cfg = "skill" }, + { label = "Main Hand", flag = "weapon1Attack", modName = "PoisonChance", modType = "BASE", cfg = "weapon1" }, + { label = "Off Hand", flag = "weapon2Attack", modName = "PoisonChance", modType = "BASE", cfg = "weapon2" }, + { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, + }, }, + { label = "Magnitude Effect", { format = "x {2:output:PoisonMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "poison" }, }, }, { label = "Source Physical", textSize = 12, notFlag = "attack", haveOutput = "PoisonPhysicalMax", { format = "{0:output:PoisonPhysicalMin} to {0:output:PoisonPhysicalMax}", { breakdown = "PoisonPhysical" }, }, }, { label = "MH Source Physical", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.PoisonPhysicalMax", { format = "{0:output:MainHand.PoisonPhysicalMin} to {0:output:MainHand.PoisonPhysicalMax}", { breakdown = "MainHand.PoisonPhysical" }, }, }, { label = "OH Source Physical", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.PoisonPhysicalMax", { format = "{0:output:OffHand.PoisonPhysicalMin} to {0:output:OffHand.PoisonPhysicalMax}", { breakdown = "OffHand.PoisonPhysical" }, }, }, @@ -950,25 +962,6 @@ return { { label = "Source Chaos", textSize = 12, notFlag = "attack", haveOutput = "PoisonChaosMax", { format = "{0:output:PoisonChaosMin} to {0:output:PoisonChaosMax}", { breakdown = "PoisonChaos" }, }, }, { label = "MH Source Chaos", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.PoisonChaosMax", { format = "{0:output:MainHand.PoisonChaosMin} to {0:output:MainHand.PoisonChaosMax}", { breakdown = "MainHand.PoisonChaos" }, }, }, { label = "OH Source Chaos", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.PoisonChaosMax", { format = "{0:output:OffHand.PoisonChaosMin} to {0:output:OffHand.PoisonChaosMax}", { breakdown = "OffHand.PoisonChaos" }, }, }, - - { label = "Chance to Poison", { format = "{0:output:PoisonChance}%", - { breakdown = "MainHand.PoisonChance" }, - { breakdown = "OffHand.PoisonChance" }, - { breakdown = "PoisonChance" }, - { notFlag = "attack", modName = "PoisonChance", modType = "BASE", cfg = "skill" }, - { label = "Main Hand", flag = "weapon1Attack", modName = "PoisonChance", modType = "BASE", cfg = "weapon1" }, - { label = "Off Hand", flag = "weapon2Attack", modName = "PoisonChance", modType = "BASE", cfg = "weapon2" }, - { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, - }, }, - { label = "Max Poison Stacks", { format = "{1:output:PoisonStacksMax}", { modName = "PoisonStacks" }, }, }, - { label = "Poison Duration", { format = "{2:output:PoisonDuration}s", - { breakdown = "PoisonDuration" }, - { label = "Player modifiers", modName = { "EnemyPoisonDuration", "EnemyAilmentDuration", "SkillAndDamagingAilmentDuration", "PoisonFaster" }, cfg = "poison" }, - { label = "Enemy modifiers", modName = { "SelfPoisonDuration", "SelfAilmentDuration", "SelfPoisonFaster" }, enemy = true }, - }, }, - { label = "Stack Potential", { format = "{2:output:PoisonStackPotentialPercent}%", { breakdown = "PoisonStackPotential" } }}, - { label = "Average Poison Roll", { format = "{2:output:PoisonRollAverage}%", { breakdown = "PoisonRollAverage" } }}, - { label = "Magnitude Effect", { format = "x {2:output:PoisonMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "poison" }, }, }, { label = "Effective DPS Mod", flag = "effective", { format = "x {3:output:PoisonEffMult}", { breakdown = "PoisonEffMult" }, { label = "Enemy modifiers", modName = { "ChaosResist", "DamageTaken", "DamageTakenOverTime", "ChaosDamageTaken", "ChaosDamageTakenOverTime" }, enemy = true }, @@ -979,6 +972,11 @@ return { { breakdown = "OffHand.PoisonDPS" }, }, }, { label = "Caustic Ground", haveOutput = "CausticGroundFromPoison", { format = "{0:output:CausticGroundDPS}", { breakdown = "CausticGroundDPS" } } }, + { label = "Poison Duration", { format = "{2:output:PoisonDuration}s", + { breakdown = "PoisonDuration" }, + { label = "Player modifiers", modName = { "EnemyPoisonDuration", "EnemyAilmentDuration", "SkillAndDamagingAilmentDuration", "PoisonFaster" }, cfg = "poison" }, + { label = "Enemy modifiers", modName = { "SelfPoisonDuration", "SelfAilmentDuration", "SelfPoisonFaster" }, enemy = true }, + }, }, { label = "Dmg. of all Poisons", { format = "{1:output:PoisonDamage}", { breakdown = "MainHand.PoisonDamage" }, { breakdown = "OffHand.PoisonDamage" }, @@ -990,7 +988,18 @@ return { extra = "{0:output:IgniteChancePerHit}% {1:output:IgniteDPS} {2:output:IgniteDuration}s", flag = "ignite", { label = "Enemy Ail. Thresh.", { format = "{0:output:EnemyAilmentThreshold}", { modName = "EnemyAilmentThreshold" }, }, }, - + { label = "Max Ignite Stacks", { format = "{1:output:IgniteStacksMax}", { modName = "IgniteStacks" }, }, }, + { label = "Stack Potential", { format = "{2:output:IgniteStackPotentialPercent}%", { breakdown = "IgniteStackPotential" } }}, + { label = "Average Ignite Roll", { format = "{2:output:IgniteRollAverage}%", { breakdown = "IgniteRollAverage" } }}, + { label = "Chance to Ignite", { format = "{0:output:IgniteChancePerHit}%", + { breakdown = "MainHand.IgniteChance" }, + { breakdown = "OffHand.IgniteChance" }, + { breakdown = "IgniteChance" }, + { label = "Player modifiers", modName = "EnemyIgniteChance", cfg = "skill" }, + { label = "Enemy modifiers", modName = "SelfIgniteChance", enemy = true }, + { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, + }, }, + { label = "Magnitude Effect", { format = "x {2:output:IgniteMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "ignite" }, }, }, { label = "Source Physical", textSize = 12, notFlag = "attack", haveOutput = "IgnitePhysicalMax", { format = "{0:output:IgnitePhysicalMin} to {0:output:IgnitePhysicalMax}", { breakdown = "IgnitePhysical" }, }, }, { label = "MH Source Physical", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.IgnitePhysicalMax", { format = "{0:output:MainHand.IgnitePhysicalMin} to {0:output:MainHand.IgnitePhysicalMax}", { breakdown = "MainHand.IgnitePhysical" }, }, }, { label = "OH Source Physical", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.IgnitePhysicalMax", { format = "{0:output:OffHand.IgnitePhysicalMin} to {0:output:OffHand.IgnitePhysicalMax}", { breakdown = "OffHand.IgnitePhysical" }, }, }, @@ -1006,24 +1015,6 @@ return { { label = "Source Chaos", textSize = 12, notFlag = "attack", haveOutput = "IgniteChaosMax", { format = "{0:output:IgniteChaosMin} to {0:output:IgniteChaosMax}", { breakdown = "IgniteChaos" }, }, }, { label = "MH Source Chaos", bgCol = colorCodes.MAINHANDBG, textSize = 12, flag = "weapon1Attack", haveOutput = "MainHand.IgniteChaosMax", { format = "{0:output:MainHand.IgniteChaosMin} to {0:output:MainHand.IgniteChaosMax}", { breakdown = "MainHand.IgniteChaos" }, }, }, { label = "OH Source Chaos", bgCol = colorCodes.OFFHANDBG, textSize = 12, flag = "weapon2Attack", haveOutput = "OffHand.IgniteChaosMax", { format = "{0:output:OffHand.IgniteChaosMin} to {0:output:OffHand.IgniteChaosMax}", { breakdown = "OffHand.IgniteChaos" }, }, }, - - { label = "Chance to Ignite", { format = "{0:output:IgniteChancePerHit}%", - { breakdown = "MainHand.IgniteChance" }, - { breakdown = "OffHand.IgniteChance" }, - { breakdown = "IgniteChance" }, - { label = "Player modifiers", modName = "EnemyIgniteChance", cfg = "skill" }, - { label = "Enemy modifiers", modName = "SelfIgniteChance", enemy = true }, - { label = "Ailment modifiers", modName = "AilmentChance", cfg = "skill" }, - }, }, - { label = "Max Ignite Stacks", { format = "{1:output:IgniteStacksMax}", { modName = "IgniteStacks" }, }, }, - { label = "Ignite Duration", { format = "{2:output:IgniteDuration}s", - { breakdown = "IgniteDuration" }, - { label = "Player modifiers", modName = { "EnemyIgniteDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration", "SkillAndDamagingAilmentDuration", "IgniteFaster", "IgniteSlower" }, cfg = "skill" }, - { label = "Enemy modifiers", modName = {"SelfIgniteDuration", "SelfAilmentDuration", "SelfElementalAilmentDuration", "SelfIgniteFaster"}, enemy = true }, - }, }, - { label = "Stack Potential", { format = "{2:output:IgniteStackPotentialPercent}%", { breakdown = "IgniteStackPotential" } }}, - { label = "Average Ignite Roll", { format = "{2:output:IgniteRollAverage}%", { breakdown = "IgniteRollAverage" } }}, - { label = "Magnitude Effect", { format = "x {2:output:IgniteMagnitudeEffect}", { modName = "AilmentMagnitude", cfg = "ignite" }, }, }, { label = "Effective DPS Mod", flag = "effective", notFlag = "igniteToChaos", { format = "x {3:output:IgniteEffMult}", { breakdown = "IgniteEffMult" }, { label = "Enemy modifiers", modName = { "FireResist", "ElementalResist", "DamageTaken", "DamageTakenOverTime", "FireDamageTaken", "FireDamageTakenOverTime", "ElementalDamageTaken" }, enemy = true }, @@ -1038,6 +1029,11 @@ return { { breakdown = "OffHand.IgniteDPS" }, }, }, { label = "Burning Ground", haveOutput = "BurningGroundFromIgnite", { format = "{0:output:BurningGroundDPS}", { breakdown = "BurningGroundDPS" } } }, + { label = "Ignite Duration", { format = "{2:output:IgniteDuration}s", + { breakdown = "IgniteDuration" }, + { label = "Player modifiers", modName = { "EnemyIgniteDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration", "SkillAndDamagingAilmentDuration", "IgniteFaster", "IgniteSlower" }, cfg = "skill" }, + { label = "Enemy modifiers", modName = {"SelfIgniteDuration", "SelfAilmentDuration", "SelfElementalAilmentDuration", "SelfIgniteFaster"}, enemy = true }, + }, }, { label = "Dmg. of all Ignites", { format = "{1:output:IgniteDamage}", { breakdown = "MainHand.IgniteDamage" }, { breakdown = "OffHand.IgniteDamage" }, @@ -1200,13 +1196,6 @@ return { { label = "Total Scorch", modName = "ElementalResistByScorch", enemy = true, cfg = "skill" }, }, }, { label = "Effect of Chill", bgCol = colorCodes.CHILLBG, flag = "chill", haveOutput = "ChillSourceEffect", { format = "{0:output:ChillSourceEffect}%", { breakdown = "DotChill" }, }, }, - { label = "Chill Duration", bgCol = colorCodes.CHILLBG, flag = "chill", { format = "{2:output:ChillDuration}s", - { breakdown = "MainHand.ChillDuration" }, - { breakdown = "OffHand.ChillDuration" }, - { breakdown = "ChillDuration" }, - { label = "Player modifiers", modName = { "EnemyChillDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration" }, cfg = "skill" }, - { label = "Enemy modifiers", modName = { "SelfChillDuration", "SelfAilmentDuration", "SelfElementalAilmentDuration", "BuffExpireFaster" }, enemy = true }, - }, }, { label = "Chill Effect Mod", bgCol = colorCodes.CHILLBG, flag = "chill", { format = "x {2:output:ChillEffectMod}", { breakdown = "ChillEffectMod" }, { breakdown = "MainHand.ChillDPS" }, @@ -1215,6 +1204,13 @@ return { { label = "Player modifiers", modName = { "EnemyChillMagnitude", "ChillAsThoughDealing" }, cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfChillEffect", enemy = true }, }, }, + { label = "Chill Duration", bgCol = colorCodes.CHILLBG, flag = "chill", { format = "{2:output:ChillDuration}s", + { breakdown = "MainHand.ChillDuration" }, + { breakdown = "OffHand.ChillDuration" }, + { breakdown = "ChillDuration" }, + { label = "Player modifiers", modName = { "EnemyChillDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration" }, cfg = "skill" }, + { label = "Enemy modifiers", modName = { "SelfChillDuration", "SelfAilmentDuration", "SelfElementalAilmentDuration", "BuffExpireFaster" }, enemy = true }, + }, }, { label = "Maximum Chill", bgCol = colorCodes.CHILLBG, flag = "chill", { format = "{0:output:MaximumChill}%", { modName = "ChillMax" }, }, }, @@ -1266,7 +1262,17 @@ return { { label = "Configured Brittle", modName = "BrittleVal", enemy = true, modType = "BASE" }, { label = "Guaranteed Brittles", modName = "BrittleOverride", modType = "BASE" }, }, }, - { label = "Enemy Ail. Thresh.", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:EnemyAilmentThreshold}", { modName = "EnemyAilmentThreshold" }, }, }, + { label = "Enemy Ail. Thresh.", { format = "{0:output:EnemyAilmentThreshold}", { modName = "EnemyAilmentThreshold" }, }, }, + { label = "Shock Effect Mod", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "x {2:output:ShockEffectMod}", + { breakdown = "ShockEffectMod" }, + { breakdown = "MainHand.ShockDPS" }, + { breakdown = "OffHand.ShockDPS" }, + { breakdown = "ShockDPS" }, + { label = "Player modifiers", notFlag = "attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "skill" }, + { label = "Main hand modifiers", flag = "weapon1Attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "weapon1" }, + { label = "Off hand modifiers", flag = "weapon2Attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "weapon2" }, + { label = "Enemy modifiers", modName = "SelfShockEffect", enemy = true }, + }, }, { label = "Chance to Shock", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:ShockChance}%", { breakdown = "MainHand.ShockChance" }, { breakdown = "OffHand.ShockChance" }, @@ -1281,16 +1287,6 @@ return { { label = "Player modifiers", modName = { "EnemyShockDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration" }, cfg = "skill" }, { label = "Enemy modifiers", modName = { "SelfShockDuration", "SelfAilmentDuration", "SelfElementalAilmentDuration", "BuffExpireFaster" }, enemy = true }, }, }, - { label = "Shock Effect Mod", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "x {2:output:ShockEffectMod}", - { breakdown = "ShockEffectMod" }, - { breakdown = "MainHand.ShockDPS" }, - { breakdown = "OffHand.ShockDPS" }, - { breakdown = "ShockDPS" }, - { label = "Player modifiers", notFlag = "attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "skill" }, - { label = "Main hand modifiers", flag = "weapon1Attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "weapon1" }, - { label = "Off hand modifiers", flag = "weapon2Attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "weapon2" }, - { label = "Enemy modifiers", modName = "SelfShockEffect", enemy = true }, - }, }, { label = "Maximum Shock", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:MaximumShock}%", { modName = "ShockMax" }, }, }, From cb586f45bfe5f59320ead1a2e184f62765b3274e Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Sun, 9 Feb 2025 16:18:15 +1100 Subject: [PATCH 13/23] Add back Impale Block --- src/Modules/CalcOffence.lua | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 656cea6570..98a3bb412d 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -4711,7 +4711,59 @@ function calcs.offence(env, actor, activeSkill) end end end + + -- Calculate impale chance and modifiers + if canDeal.Physical and (output.ImpaleChance + output.ImpaleChanceOnCrit) > 0 then + skillFlags.impale = true + local critChance = output.CritChance / 100 + local impaleChance = (m_min(output.ImpaleChance/100, 1) * (1 - critChance) + m_min(output.ImpaleChanceOnCrit/100, 1) * critChance) + local maxStacks = skillModList:Sum("BASE", cfg, "ImpaleStacksMax") * (1 + skillModList:Sum("BASE", cfg, "ImpaleAdditionalDurationChance") / 100) + local configStacks = enemyDB:Sum("BASE", cfg, "Multiplier:ImpaleStacks") + local impaleStacks = m_min(maxStacks, configStacks) + + local baseStoredDamage = data.misc.ImpaleStoredDamageBase + local storedExpectedDamageIncOnBleed = skillModList:Sum("INC", cfg, "ImpaleEffectOnBleed")*skillModList:Sum("BASE", cfg, "BleedChance")/100 + local storedExpectedDamageInc = (skillModList:Sum("INC", cfg, "ImpaleEffect") + storedExpectedDamageIncOnBleed)/100 + local storedExpectedDamageMore = round(skillModList:More(cfg, "ImpaleEffect"), 2) + local storedExpectedDamageModifier = (1 + storedExpectedDamageInc) * storedExpectedDamageMore + local impaleStoredDamage = baseStoredDamage * storedExpectedDamageModifier + local impaleHitDamageMod = impaleStoredDamage * impaleStacks -- Source: https://www.reddit.com/r/pathofexile/comments/chgqqt/impale_and_armor_interaction/ + + local enemyArmour = m_max(calcLib.val(enemyDB, "Armour"), 0) + local impaleArmourReduction = calcs.armourReductionF(enemyArmour, impaleHitDamageMod * output.PhysicalStoredCombinedAvg) + local impaleResist = m_min(m_max(0, enemyDB:Sum("BASE", nil, "PhysicalDamageReduction") + skillModList:Sum("BASE", cfg, "EnemyImpalePhysicalDamageReduction") + impaleArmourReduction), data.misc.DamageReductionCap) + if skillModList:Flag(cfg, "IgnoreEnemyImpalePhysicalDamageReduction") then + impaleResist = 0 + end + local impaleTakenCfg = { flags = ModFlag.Hit } + local impaleTaken = (1 + enemyDB:Sum("INC", impaleTakenCfg, "DamageTaken", "PhysicalDamageTaken", "ReflectedDamageTaken") / 100) + * enemyDB:More(impaleTakenCfg, "DamageTaken", "PhysicalDamageTaken", "ReflectedDamageTaken") + local impaleDMGModifier = impaleHitDamageMod * (1 - impaleResist / 100) * impaleChance * impaleTaken + + globalOutput.ImpaleStacksMax = maxStacks + globalOutput.ImpaleStacks = impaleStacks + --ImpaleStoredDamage should be named ImpaleEffect or similar + --Using the variable name ImpaleEffect breaks the calculations sidebar (?!) + output.ImpaleStoredDamage = impaleStoredDamage * 100 + output.ImpaleModifier = 1 + impaleDMGModifier + if breakdown then + breakdown.ImpaleStoredDamage = {} + t_insert(breakdown.ImpaleStoredDamage, "10% ^8(base value)") + t_insert(breakdown.ImpaleStoredDamage, s_format("x %.2f ^8(increased effectiveness)", storedExpectedDamageModifier)) + t_insert(breakdown.ImpaleStoredDamage, s_format("= %.1f%%", output.ImpaleStoredDamage)) + + breakdown.ImpaleModifier = {} + t_insert(breakdown.ImpaleModifier, s_format("%d ^8(number of stacks, can be overridden in the Configuration tab)", impaleStacks)) + t_insert(breakdown.ImpaleModifier, s_format("x %.3f ^8(stored damage)", impaleStoredDamage)) + t_insert(breakdown.ImpaleModifier, s_format("x %.2f ^8(impale chance)", impaleChance)) + t_insert(breakdown.ImpaleModifier, s_format("x %.2f ^8(impale enemy physical damage reduction)", (1 - impaleResist / 100))) + if impaleTaken ~= 1 then + t_insert(breakdown.ImpaleModifier, s_format("x %.2f ^8(impale enemy damage taken)", impaleTaken)) + end + t_insert(breakdown.ImpaleModifier, s_format("= %.3f ^8(impale damage multiplier)", impaleDMGModifier)) + end + end end -- Combine secondary effect stats From c61ec75c2ea6f69359fce08765b9915a62f2f323 Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Sun, 9 Feb 2025 17:41:58 +1100 Subject: [PATCH 14/23] Update enemy ailment threshold values Uses game constants for values --- src/Data/Misc.lua | 4 +--- src/Export/Scripts/miscdata.lua | 2 -- src/Modules/CalcOffence.lua | 17 ++++------------- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/Data/Misc.lua b/src/Data/Misc.lua index 5e0daff0b5..9658ae7d16 100644 --- a/src/Data/Misc.lua +++ b/src/Data/Misc.lua @@ -5,13 +5,11 @@ local data = ... data.monsterEvasionTable = { 11, 14, 17, 20, 24, 27, 31, 35, 38, 42, 46, 50, 54, 59, 63, 67, 72, 76, 81, 86, 91, 96, 101, 106, 111, 117, 122, 128, 134, 140, 146, 152, 158, 165, 171, 178, 185, 191, 199, 206, 213, 221, 228, 236, 244, 252, 261, 269, 278, 286, 295, 304, 314, 323, 333, 343, 353, 363, 373, 384, 395, 406, 417, 429, 440, 452, 464, 477, 489, 502, 515, 528, 542, 556, 570, 584, 598, 613, 628, 644, 659, 675, 691, 708, 724, 742, 759, 777, 795, 813, 832, 850, 870, 889, 909, 930, 951, 972, 993, 1015, } data.monsterAccuracyTable = { 51, 56, 60, 65, 70, 75, 80, 86, 91, 97, 103, 110, 116, 123, 130, 137, 145, 152, 160, 169, 177, 186, 195, 204, 214, 224, 234, 245, 256, 267, 279, 291, 304, 317, 330, 344, 358, 372, 387, 403, 419, 435, 452, 470, 488, 506, 526, 545, 566, 587, 608, 630, 653, 677, 701, 726, 752, 778, 806, 834, 863, 892, 923, 955, 987, 1020, 1055, 1090, 1126, 1164, 1202, 1242, 1283, 1324, 1368, 1412, 1457, 1504, 1552, 1602, 1653, 1705, 1759, 1814, 1871, 1930, 1990, 2052, 2115, 2180, 2247, 2316, 2387, 2460, 2535, 2612, 2690, 2772, 2855, 2941, } data.monsterLifeTable = { 15, 20, 24, 28, 33, 38, 45, 52, 62, 74, 89, 106, 127, 151, 179, 211, 237, 267, 298, 332, 368, 406, 446, 488, 533, 579, 629, 680, 734, 791, 849, 911, 975, 1053, 1137, 1228, 1326, 1432, 1547, 1671, 1804, 1949, 2104, 2273, 2455, 2577, 2706, 2842, 2984, 3133, 3289, 3454, 3627, 3808, 3998, 4198, 4408, 4629, 4860, 5103, 5358, 5626, 5907, 6203, 6513, 6904, 7318, 7757, 8222, 8716, 9239, 9793, 10381, 11003, 11664, 12363, 13105, 13892, 14725, 15609, 16545, 17538, 18590, 19705, 20888, 22141, 23469, 24878, 26370, 27953, 29630, 31407, 33292, 35289, 37407, 39651, 42030, 44552, 47225, 50059, } -data.monsterLifeTable2 = { 22, 28, 35, 41, 48, 55, 63, 70, 77, 85, 93, 101, 109, 118, 126, 135, 144, 153, 163, 172, 182, 192, 202, 213, 223, 234, 245, 256, 268, 280, 292, 304, 317, 330, 343, 356, 370, 383, 398, 412, 427, 442, 457, 473, 489, 505, 522, 538, 556, 573, 591, 609, 628, 647, 666, 686, 706, 727, 747, 769, 790, 812, 835, 858, 881, 905, 929, 954, 979, 1004, 1030, 1057, 1084, 1112, 1140, 1168, 1197, 1227, 1257, 1288, 1319, 1351, 1383, 1416, 1449, 1484, 1518, 1554, 1590, 1626, 1664, 1701, 1740, 1779, 1819, 1860, 1902, 1944, 1987, 2030, } -data.monsterLifeTable3 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } data.monsterAllyLifeTable = { 51, 79, 109, 140, 172, 207, 243, 281, 321, 362, 406, 453, 501, 552, 605, 661, 720, 781, 845, 912, 982, 1056, 1132, 1213, 1296, 1384, 1475, 1571, 1671, 1775, 1883, 1996, 2114, 2238, 2366, 2500, 2639, 2784, 2936, 3093, 3258, 3429, 3607, 3792, 3985, 4185, 4394, 4611, 4837, 5072, 5316, 5570, 5834, 6108, 6394, 6690, 6998, 7318, 7650, 7996, 8354, 8727, 9114, 9515, 9932, 10365, 10814, 11280, 11764, 12266, 12787, 13328, 13889, 14471, 15074, 15700, 16349, 17023, 17721, 18445, 19195, 19973, 20780, 21616, 22483, 23381, 24312, 25277, 26277, 27313, 28386, 29498, 30650, 31843, 33079, 34360, 35686, 37060, 38482, 39955, } data.monsterDamageTable = { 9.1599998474121, 10.260000228882, 11.390000343323, 12.569999694824, 13.779999732971, 15.029999732971, 16.319999694824, 17.64999961853, 19.020000457764, 20.440000534058, 21.89999961853, 23.409999847412, 24.969999313354, 26.569999694824, 28.229999542236, 29.930000305176, 31.690000534058, 33.5, 35.369998931885, 37.290000915527, 39.270000457764, 41.310001373291, 43.409999847412, 45.569999694824, 47.799999237061, 50.090000152588, 52.450000762939, 54.880001068115, 57.369998931885, 59.939998626709, 62.590000152588, 65.309997558594, 68.099998474121, 70.980003356934, 73.940002441406, 76.980003356934, 80.110000610352, 83.319999694824, 86.629997253418, 90.019996643066, 93.51000213623, 97.099998474121, 100.79000091553, 104.56999969482, 108.45999908447, 112.45999908447, 116.56999969482, 120.7799987793, 125.12000274658, 129.55999755859, 134.13000488281, 138.82000732422, 143.63999938965, 148.58000183105, 153.66000366211, 158.86999511719, 164.21000671387, 169.69999694824, 175.33999633789, 181.11999511719, 187.05000305176, 193.13999938965, 199.38000488281, 205.78999328613, 212.36000061035, 219.11000061035, 226.0299987793, 233.11999511719, 240.39999389648, 247.86000061035, 255.52000427246, 263.36999511719, 271.42001342773, 279.67999267578, 288.14001464844, 296.82000732422, 305.7200012207, 314.83999633789, 324.19000244141, 333.7799987793, 343.60000610352, 353.67001342773, 364, 374.57998657227, 385.42001342773, 396.5299987793, 407.92001342773, 419.57998657227, 431.54000854492, 443.79000854492, 456.33999633789, 469.20001220703, 482.38000488281, 495.86999511719, 509.70001220703, 523.85998535156, 538.36999511719, 553.22998046875, 568.46002197266, 584.04998779297, } data.monsterAllyDamageTable = { 3.1600000858307, 4.210000038147, 5.3699998855591, 6.6399998664856, 8.0299997329712, 9.539999961853, 11.199999809265, 13, 14.960000038147, 17.10000038147, 19.409999847412, 21.930000305176, 24.659999847412, 27.610000610352, 30.809999465942, 34.270000457764, 38.009998321533, 42.060001373291, 46.419998168945, 51.130001068115, 56.200000762939, 61.669998168945, 67.559997558594, 73.910003662109, 80.73999786377, 88.080001831055, 95.970001220703, 104.45999908447, 113.56999969482, 123.34999847412, 133.86000061035, 145.13000488281, 157.2200012207, 170.17999267578, 184.08000183105, 198.9700012207, 214.91999816895, 232, 250.30000305176, 269.86999511719, 290.82000732422, 313.23999023438, 337.20999145508, 362.83999633789, 390.25, 419.54000854492, 450.82998657227, 484.26998901367, 519.97998046875, 558.11999511719, 598.84997558594, 642.32000732422, 688.71002197266, 738.21997070312, 791.04998779297, 847.40002441406, 907.5, 971.59002685547, 1039.9200439453, 1112.7700195312, 1190.4200439453, 1273.1800537109, 1361.3599853516, 1455.3199462891, 1555.4000244141, 1662.0200195312, 1775.5600585938, 1896.4699707031, 2025.2099609375, 2162.2700195312, 2308.1599121094, 2463.4499511719, 2628.7199707031, 2804.580078125, 2991.6999511719, 3190.7800292969, 3402.5600585938, 3627.8200683594, 3867.3999023438, 4122.1899414062, 4393.1201171875, 4681.1899414062, 4987.4501953125, 5313.0297851562, 5659.1201171875, 6026.9599609375, 6417.8999023438, 6833.33984375, 7274.7998046875, 7743.8598632812, 8242.2001953125, 8771.6103515625, 9333.990234375, 9931.33984375, 10565.790039062, 11239.599609375, 11955.150390625, 12714.969726562, 13521.759765625, 14378.349609375, } data.monsterArmourTable = { 5, 8, 11, 15, 19, 23, 27, 32, 37, 43, 49, 55, 62, 70, 78, 86, 96, 106, 116, 127, 139, 152, 166, 181, 196, 213, 231, 250, 270, 292, 315, 339, 365, 393, 422, 453, 486, 521, 559, 599, 641, 685, 733, 783, 837, 893, 953, 1017, 1084, 1156, 1231, 1311, 1396, 1486, 1581, 1682, 1788, 1901, 2020, 2146, 2279, 2420, 2569, 2726, 2893, 3068, 3254, 3451, 3658, 3877, 4108, 4353, 4611, 4883, 5171, 5475, 5795, 6133, 6490, 6867, 7264, 7684, 8126, 8593, 9085, 9604, 10151, 10728, 11336, 11978, 12654, 13367, 14119, 14911, 15745, 16625, 17552, 18528, 19557, 20641, } -data.monsterAilmentThresholdTable = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, } +data.monsterAilmentThresholdTable = { 15, 20, 24, 28, 34, 39, 46, 54, 64, 77, 93, 112, 135, 161, 192, 228, 257, 291, 327, 366, 408, 453, 501, 551, 606, 662, 724, 787, 855, 927, 1002, 1082, 1165, 1267, 1377, 1497, 1627, 1768, 1923, 2091, 2273, 2472, 2687, 2923, 3179, 3360, 3552, 3757, 3972, 4200, 4440, 4696, 4966, 5251, 5552, 5872, 6210, 6568, 6946, 7346, 7769, 8217, 8690, 9193, 9723, 10382, 11085, 11837, 12639, 13497, 14413, 15390, 16435, 17549, 18742, 20013, 21372, 22824, 24373, 26029, 27796, 29684, 31700, 33852, 36153, 38608, 41230, 44033, 47023, 50219, 53630, 57272, 61164, 65318, 69757, 74494, 79554, 84958, 90729, 96892, } -- From MinionGemLevelScaling.dat data.minionLevelTable = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, } diff --git a/src/Export/Scripts/miscdata.lua b/src/Export/Scripts/miscdata.lua index 9740cfc3db..d560c9a0ac 100644 --- a/src/Export/Scripts/miscdata.lua +++ b/src/Export/Scripts/miscdata.lua @@ -28,8 +28,6 @@ out:write('-- From DefaultMonsterStats.dat\n') out:write('data.monsterEvasionTable = { '..evasion..'}\n') --This table is off by about 0.5% in some cases but is quicker than generating the value at runtime out:write('data.monsterAccuracyTable = { '..accuracy..'}\n') out:write('data.monsterLifeTable = { '..life..'}\n') -out:write('data.monsterLifeTable2 = { '..altLife1..'}\n') -out:write('data.monsterLifeTable3 = { '..altLife2..'}\n') out:write('data.monsterAllyLifeTable = { '..allyLife..'}\n') out:write('data.monsterDamageTable = { '..damage..'}\n') out:write('data.monsterAllyDamageTable = { '..allyDamage..'}\n') diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 98a3bb412d..9d1da956f6 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3841,16 +3841,7 @@ function calcs.offence(env, actor, activeSkill) -- Various tree nodes for bleed chance on crit -- Calculate ailment thresholds - local enemyAilmentThreshold = data.monsterAilmentThresholdTable[env.enemyLevel] - local isBoss = env.configInput["enemyIsBoss"] ~= "None" - local enemyMapLifeMult = 1 - local enemyMapAilmentMult = 1 - if env.enemyLevel >= 66 then - enemyMapLifeMult = isBoss and data.mapLevelBossLifeMult[env.enemyLevel] or data.mapLevelLifeMult[env.enemyLevel] - enemyMapAilmentMult = isBoss and data.mapLevelBossAilmentMult[env.enemyLevel] or enemyMapAilmentMult - end - local enemyTypeMult = isBoss and 7.68 or 1 - local enemyThreshold = enemyAilmentThreshold * enemyTypeMult * enemyMapLifeMult * enemyDB:More(nil, "Life") * enemyMapAilmentMult * enemyDB:More(nil, "AilmentThreshold") + local enemyThreshold = data.monsterAilmentThresholdTable[env.enemyLevel] * enemyDB:More(nil, "AilmentThreshold") output['EnemyAilmentThreshold'] = enemyThreshold -- TODO: Should probably be in Data.lua instead, or pulled from export data @@ -4416,7 +4407,7 @@ function calcs.offence(env, actor, activeSkill) -- "All Hits that have any Contribution to Chill Magnitude can Chill, without requiring an explicit chance to inflict, -- provided the Magnitudes meets a minimum threshold. So low damage Hits may still fail to Chill." local unmitigatedColdDamage = calcAverageUnmitigatedSourceDamage("Chill", defaultAilmentDamageTypes["Chill"]["ScalesFrom"]) - local chillAilmentThresholdGuess = enemyThreshold * 0.04 * 15 -- Assume 15% is sufficient + local chillAilmentThresholdGuess = enemyThreshold / data.gameConstants.MiscAilmentChanceMultiplier * 15 -- Assume 15% is sufficient output['ChillAilmentThresholdGuess'] = chillAilmentThresholdGuess if unmitigatedColdDamage > chillAilmentThresholdGuess then output["ChillChanceOnHit"] = 100 @@ -4441,8 +4432,8 @@ function calcs.offence(env, actor, activeSkill) -- TODO: average for now, can do more complicated calculation later local hitAvg = hitMin + (hitMax - hitMin) / 2 local critAvg = critMin + (critMax - critMin) / 2 - local hitElementalAilmentChance = (hitAvg / enemyThreshold) / 0.04 - local critElementalAilmentChance = (critAvg / enemyThreshold) / 0.04 + local hitElementalAilmentChance = (hitAvg / enemyThreshold) * data.gameConstants[ailment .. "ChanceMultiplier"] + local critElementalAilmentChance = (critAvg / enemyThreshold) * data.gameConstants[ailment .. "ChanceMultiplier"] if skillFlags.hit and not skillModList:Flag(cfg, "Cannot"..ailment) then output[ailment.."ChanceOnHit"] = m_min(100, hitElementalAilmentChance) From 44430d0ad24a8082c6504367fc723b601310379c Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Mon, 10 Feb 2025 01:43:02 +1100 Subject: [PATCH 15/23] Formatting --- src/Modules/CalcOffence.lua | 12 +++--------- src/Modules/ConfigOptions.lua | 7 +------ 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 9d1da956f6..9962f824a5 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3894,9 +3894,7 @@ function calcs.offence(env, actor, activeSkill) globalOutput, globalBreakdown = output, breakdown local source, output, cfg, breakdown = pass.source, pass.output, pass.cfg, pass.breakdown - -- Legacy PoE1 ailments (to be removed later) - -- No more "alt" ailments: Scorched, Brittle, Sapped - -- No more Impale + -- Legacy PoE1 ailments (to be removed later): Scorched, Brittle, Sapped, Impale output.ImpaleChance = 0 output.ImpaleChanceOnCrit = 0 output.ScorchChance = 0 @@ -3906,7 +3904,7 @@ function calcs.offence(env, actor, activeSkill) -- address Weapon1H interaction with Ailment for nodes like Coated Arms (PoE1: Sleight of Hand) -- bit.and on cfg.flags confirms if the skill has the 1H flag - -- if so bit.or on the targetCfg (e.g. dotCfg) to guarantee for calculations like Sum("INC") and breakdown + -- if so, bit.or on the targetCfg (e.g. dotCfg) to guarantee for calculations like Sum("INC") and breakdown local function checkWeapon1HFlags(targetCfg) targetCfg.flags = bor(targetCfg.flags, band(cfg.flags, ModFlag.Weapon1H)) end @@ -4476,11 +4474,7 @@ function calcs.offence(env, actor, activeSkill) -- Calculate damaging ailment values for _, damagingAilment in ipairs({"Bleed", "Poison", "Ignite"}) do - calcDamagingAilmentOutputs( - damagingAilment, - defaultAilmentDamageTypes[damagingAilment]["DamageType"], - defaultAilmentDamageTypes[damagingAilment]["ScalesFrom"] - ) + calcDamagingAilmentOutputs(damagingAilment, defaultAilmentDamageTypes[damagingAilment]["DamageType"],defaultAilmentDamageTypes[damagingAilment]["ScalesFrom"]) end -- Calculate non-damaging ailments effect and duration modifiers diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 44f19bb278..048f615fc5 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -1560,7 +1560,6 @@ Huge sets the radius to 11. end }, { var = "conditionScorchedEffect", type = "count", label = "Effect of ^xB97123Scorched:", ifOption = "conditionEnemyScorched", tooltip = "This effect will only be applied while you can inflict ^xB97123Scorched.", apply = function(val, modList, enemyModList) enemyModList:NewMod("ScorchVal", "BASE", val, "Config", { type = "Condition", var = "ScorchedConfig" }) - enemyModList:NewMod("DesiredScorchVal", "BASE", val, "Scorch", { type = "Condition", var = "ScorchedConfig", neg = true }) end }, { var = "ScorchStacks", type = "integer", label = "^xB97123Scorch ^7Stacks", ifFlag = "ScorchCanStack", ifOption = "conditionEnemyScorched", defaultPlaceholderState = 1, tooltip = "Amount of stacks of ^xB97123Scorch ^7applied to the enemy.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:ScorchStacks", "BASE", val, "Config", { type = "Condition", var = "Effective" }) @@ -1579,7 +1578,6 @@ Huge sets the radius to 11. end }, { var = "conditionEnemyChilledEffect", type = "count", label = "Effect of ^x3F6DB3Chill:", ifOption = "conditionEnemyChilled", apply = function(val, modList, enemyModList) enemyModList:NewMod("ChillVal", "BASE", val, "Chill", { type = "Condition", var = "ChilledConfig" }) - enemyModList:NewMod("DesiredChillVal", "BASE", val, "Chill", { type = "Condition", var = "ChilledConfig", neg = true }) end }, { var = "ChillStacks", type = "count", label = "^xADAA47Chill ^7Stacks", ifFlag = "ChillCanStack", ifOption = "conditionEnemyChilled", defaultPlaceholderState = 1, tooltip = "Amount of stacks of ^xADAA47Chill ^7applied to the enemy.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:ChillStacks", "BASE", val, "Config", { type = "Condition", var = "Effective" }) @@ -1605,7 +1603,6 @@ Huge sets the radius to 11. end }, { var = "conditionBrittleEffect", type = "count", label = "Effect of ^x3F6DB3Brittle:", ifOption = "conditionEnemyBrittle", tooltip = "This effect will only be applied while you can inflict ^x3F6DB3Brittle.", apply = function(val, modList, enemyModList) enemyModList:NewMod("BrittleVal", "BASE", val, "Config", { type = "Condition", var = "BrittleConfig" }) - enemyModList:NewMod("DesiredBrittleVal", "BASE", val, "Brittle", { type = "Condition", var = "BrittleConfig", neg = true }) end }, { var = "conditionEnemyOnBrittleGround", type = "check", label = "Is the enemy on ^xADAA47Brittle ^7Ground?", tooltip = "This also implies that the enemy is ^xADAA47Brittle.", ifEnemyCond = "OnBrittleGround", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Brittle", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) @@ -1615,9 +1612,8 @@ Huge sets the radius to 11. enemyModList:NewMod("Condition:Shocked", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:ShockedConfig", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionShockEffect", type = "count", label = "Effect of ^xADAA47Shock:", ifOption = "conditionEnemyShocked", tooltip = "If you have a guaranteed source of ^xADAA47Shock^7,\nthe strongest one will apply instead unless this option would apply a stronger ^xADAA47Shock.", apply = function(val, modList, enemyModList) + { var = "conditionShockEffect", type = "count", label = "Effect of ^xADAA47Shock^7 (if not maximum):", ifOption = "conditionEnemyShocked", tooltip = "If you have a guaranteed source of ^xADAA47Shock^7,\nthe strongest one will apply instead unless this option would apply a stronger ^xADAA47Shock.", apply = function(val, modList, enemyModList) enemyModList:NewMod("ShockVal", "BASE", val, "Shock", { type = "Condition", var = "ShockedConfig" }) - enemyModList:NewMod("DesiredShockVal", "BASE", val, "Shock", { type = "Condition", var = "ShockedConfig", neg = true }) end }, { var = "ShockStacks", type = "count", label = "^xADAA47Shock ^7Stacks", ifFlag = "ShockCanStack", ifOption = "conditionEnemyShocked", defaultPlaceholderState = 1, tooltip = "Amount of stacks of ^xADAA47Shock ^7applied to the enemy.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:ShockStacks", "BASE", val, "Config", { type = "Condition", var = "Effective" }) @@ -1636,7 +1632,6 @@ Huge sets the radius to 11. end }, { var = "conditionSapEffect", type = "count", label = "Effect of ^xADAA47Sap:", ifOption = "conditionEnemySapped", tooltip = "If you have a guaranteed source of ^xADAA47Sap^7,\nthe strongest one will apply instead unless this option would apply a stronger ^xADAA47Sap.", apply = function(val, modList, enemyModList) enemyModList:NewMod("SapVal", "BASE", val, "Sap", { type = "Condition", var = "SappedConfig" }) - enemyModList:NewMod("DesiredSapVal", "BASE", val, "Sap", { type = "Condition", var = "SappedConfig", neg = true }) end }, { var = "conditionEnemyOnSappedGround", type = "check", label = "Is the enemy on ^xADAA47Sapped ^7Ground?", tooltip = "This also implies that the enemy is ^xADAA47Sapped.", ifEnemyCond = "OnSappedGround", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Sapped", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) From 70d1d755cdf9addf91343da3ddd69dfbd0e9cd71 Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Mon, 10 Feb 2025 01:43:54 +1100 Subject: [PATCH 16/23] Shock chance calcs --- src/Modules/CalcDefence.lua | 2 +- src/Modules/CalcOffence.lua | 21 ++++++++------------- src/Modules/CalcPerform.lua | 4 ++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 44b163591a..826f856f59 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -1716,7 +1716,7 @@ function calcs.defence(env, actor) output["Self"..ailment.."Duration"] = more * inc / (100 + output.DebuffExpirationRate + modDB:Sum("BASE", nil, "Self"..ailment.."DebuffExpirationRate")) end for _, ailment in ipairs(data.ailmentTypeList) do - output["Self"..ailment.."Effect"] = calcLib.mod(modDB, nil, "Self"..ailment.."Effect") * (modDB:Flag(nil, "Condition:"..ailment.."edSelf") and calcLib.mod(modDB, nil, "Enemy"..ailment.."Effect") or calcLib.mod(enemyDB, nil, "Enemy"..ailment.."Effect")) * 100 + output["Self"..ailment.."Effect"] = calcLib.mod(modDB, nil, "Self"..ailment.."Effect") * (modDB:Flag(nil, "Condition:"..ailment.."edSelf") and calcLib.mod(modDB, nil, "Enemy"..ailment.."Magnitude") or calcLib.mod(enemyDB, nil, "Enemy"..ailment.."Magnitude")) * 100 end end diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 9962f824a5..de6e42ea90 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -4430,8 +4430,13 @@ function calcs.offence(env, actor, activeSkill) -- TODO: average for now, can do more complicated calculation later local hitAvg = hitMin + (hitMax - hitMin) / 2 local critAvg = critMin + (critMax - critMin) / 2 - local hitElementalAilmentChance = (hitAvg / enemyThreshold) * data.gameConstants[ailment .. "ChanceMultiplier"] - local critElementalAilmentChance = (critAvg / enemyThreshold) * data.gameConstants[ailment .. "ChanceMultiplier"] + local base = skillModList:Sum("BASE", cfg, "Enemy"..ailment.."Chance") + enemyDB:Sum("BASE", nil, "Self"..ailment.."Chance") + local inc = skillModList:Sum("INC", cfg, "Enemy"..ailment.."Chance") + local more = skillModList:More(cfg, "Enemy"..ailment.."Chance") + local hitElementalAilmentChance = hitAvg / enemyThreshold * data.gameConstants[ailment .. "ChanceMultiplier"] + hitElementalAilmentChance = (hitElementalAilmentChance + base) * (1 + inc / 100) * more + local critElementalAilmentChance = critAvg / enemyThreshold * data.gameConstants[ailment .. "ChanceMultiplier"] + critElementalAilmentChance = (critElementalAilmentChance + base) * (1 + inc / 100) * more if skillFlags.hit and not skillModList:Flag(cfg, "Cannot"..ailment) then output[ailment.."ChanceOnHit"] = m_min(100, hitElementalAilmentChance) @@ -4454,16 +4459,6 @@ function calcs.offence(env, actor, activeSkill) end end - -- Apply increased ailment chance mods - for _, ailment in ipairs(ailmentTypeList) do - local mult = (1 + modDB:Sum("INC", skillCfg, "AilmentChance") / 100) - if env.mode_effective then - mult = mult * (enemyDB:Flag(nil, ailment.."Immune") and 0 or 1 - enemyDB:Sum("BASE", nil, "Avoid"..ailment) / 100) - end - output[ailment.."ChanceOnHit"] = m_min(100, output[ailment.."ChanceOnHit"] * mult) - output[ailment.."ChanceOnCrit"] = m_min(100, output[ailment.."ChanceOnCrit"] * mult) - end - -- Apply user damage type config local ailmentMode = env.configInput.ailmentMode or "AVERAGE" if ailmentMode == "CRIT" then @@ -4539,7 +4534,7 @@ function calcs.offence(env, actor, activeSkill) local incDur = skillModList:Sum("INC", cfg, "Enemy"..ailment.."Duration", "EnemyElementalAilmentDuration", "EnemyAilmentDuration") + enemyDB:Sum("INC", nil, "Self"..ailment.."Duration", "SelfElementalAilmentDuration", "SelfAilmentDuration") local moreDur = skillModList:More(cfg, "Enemy"..ailment.."Duration", "EnemyElementalAilmentDuration", "EnemyAilmentDuration") * enemyDB:More(nil, "Self"..ailment.."Duration", "SelfElementalAilmentDuration", "SelfAilmentDuration") output[ailment.."Duration"] = ailmentData[ailment].duration * (1 + incDur / 100) * moreDur * debuffDurationMult - output[ailment.."EffectMod"] = calcLib.mod(skillModList, cfg, "Enemy"..ailment.."Effect") + output[ailment.."EffectMod"] = calcLib.mod(skillModList, cfg, "Enemy"..ailment.."Magnitude") if breakdown then local maximum = globalOutput["Maximum"..ailment] or ailmentData[ailment].max local current = m_max(m_min(globalOutput["Current"..ailment] or 0, maximum), 0) diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 4b45496791..199ec1a48f 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -2796,9 +2796,9 @@ function calcs.perform(env, skipEHP) -- if not, use the generic modifiers -- Scorch/Sap/Brittle do not have guaranteed sources from hits, and therefore will only end up in this bit of code if it's not supposed to apply the skillModList, which is bad if ailment ~= "Scorch" and ailment ~= "Sap" and ailment ~= "Brittle" and not env.player.mainSkill.skillModList:Flag(nil, "Cannot"..ailment) and hitFlag and modDB:Flag(nil, "ChecksHighestDamage") then - effect = effect * calcLib.mod(env.player.mainSkill.skillModList, nil, "Enemy"..ailment.."Effect") + effect = effect * calcLib.mod(env.player.mainSkill.skillModList, env.player.mainSkill.skillModList.skillCfg, "Enemy"..ailment.."Magnitude") else - effect = effect * calcLib.mod(modDB, nil, "Enemy"..ailment.."Effect") + effect = effect * calcLib.mod(env.player.mainSkill.skillModList, env.player.mainSkill.skillModList.skillCfg, "Enemy"..ailment.."Magnitude") end modDB:NewMod(ailment.."Override", "BASE", effect, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) if mod.name == ailment.."Minimum" then From 67cb71e3a6afc5e5470c31ae8a31cb3fd784264e Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Mon, 10 Feb 2025 01:44:31 +1100 Subject: [PATCH 17/23] Fix base Shock value --- src/Modules/CalcPerform.lua | 3 +-- src/Modules/CalcSections.lua | 2 ++ src/Modules/CalcSetup.lua | 1 + src/Modules/Data.lua | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 199ec1a48f..03710254e1 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -2736,7 +2736,6 @@ function calcs.perform(env, skipEHP) local mods = { } if modDB:Flag(nil, "ChillCanStack") then - t_insert(mods, modLib.createMod("DamageTaken", "INC", num, "Shock", { type = "Condition", var = "Shocked" }, { type = "Multiplier", var = "ShockStacks", limit = modDB:Override(nil, "ShockStacksMax") or modDB:Sum("BASE", nil, "ShockStacksMax")})) output["CurrentChill"] = num * m_min(enemyDB:Sum("BASE", nil, "Multiplier:ChillStacks"), modDB:Override(nil, "ChillStacksMax") or modDB:Sum("BASE", nil, "ChillStacksMax")) if breakdown then t_insert(mods, modLib.createMod("ActionSpeed", "INC", -num, "Chill Stacks", { type = "Condition", var = "Chilled" }, { type = "Multiplier", var = "ShockStacks", limit = modDB:Override(nil, "ShockStacksMax") or modDB:Sum("BASE", nil, "ShockStacksMax")})) @@ -2759,8 +2758,8 @@ function calcs.perform(env, skipEHP) mods = function(num) local mods = { } if modDB:Flag(nil, "ShockCanStack") then + output.ShockStackCount = m_min(enemyDB:Sum("BASE", nil, "Multiplier:ShockStacks"), modDB:Override(nil, "ShockStacksMax") or modDB:Sum("BASE", nil, "ShockStacksMax")) t_insert(mods, modLib.createMod("DamageTaken", "INC", num, "Shock", { type = "Condition", var = "Shocked" }, { type = "Multiplier", var = "ShockStacks", limit = modDB:Override(nil, "ShockStacksMax") or modDB:Sum("BASE", nil, "ShockStacksMax")})) - output["CurrentShock"] = num * m_min(enemyDB:Sum("BASE", nil, "Multiplier:ShockStacks"), modDB:Override(nil, "ShockStacksMax") or modDB:Sum("BASE", nil, "ShockStacksMax")) if breakdown then t_insert(mods, modLib.createMod("DamageTakenByShock", "INC", num, "Shock Stacks", { type = "Condition", var = "Shocked" }, { type = "Multiplier", var = "ShockStacks", limit = modDB:Override(nil, "ShockStacksMax") or modDB:Sum("BASE", nil, "ShockStacksMax")})) end diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 92314f8b6b..86decaa426 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -1290,6 +1290,8 @@ return { { label = "Maximum Shock", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:MaximumShock}%", { modName = "ShockMax" }, }, }, + { label = "Shock Stacks", bgCol = colorCodes.SHOCKBG, haveOutput = "ShockStackCount", { format = "{0:output:ShockStackCount}", + }, }, { label = "Current Shock", bgCol = colorCodes.SHOCKBG, haveOutput = "CurrentShock", { format = "{0:output:CurrentShock}%", { label = "Configured Shock", modName = "ShockVal", enemy = true, modType = "BASE" }, { label = "Guaranteed Shocks", modName = "ShockOverride", modType = "BASE" }, diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 8106fe60cd..8cdc448583 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -68,6 +68,7 @@ function calcs.initModDB(env, modDB) modDB:NewMod("Damage", "MORE", -10, "Base", { type = "Condition", var = "Debilitated"}) modDB:NewMod("Condition:Burning", "FLAG", true, "Base", { type = "IgnoreCond" }, { type = "Condition", var = "Ignited" }) modDB:NewMod("Condition:Poisoned", "FLAG", true, "Base", { type = "IgnoreCond" }, { type = "MultiplierThreshold", var = "PoisonStack", threshold = 1 }) + modDB:NewMod("ShockBase", "BASE", 20, "Base", { type = "ActorCondition", actor = "enemy", var = "Shocked" }) modDB:NewMod("Blind", "FLAG", true, "Base", { type = "Condition", var = "Blinded" }) modDB:NewMod("Chill", "FLAG", true, "Base", { type = "Condition", var = "Chilled" }) modDB:NewMod("Freeze", "FLAG", true, "Base", { type = "Condition", var = "Frozen" }) diff --git a/src/Modules/Data.lua b/src/Modules/Data.lua index 2c07d84d06..5a926a1678 100644 --- a/src/Modules/Data.lua +++ b/src/Modules/Data.lua @@ -302,7 +302,7 @@ data.nonElementalAilmentTypeList = { "Bleed", "Poison" } data.nonDamagingAilment = { ["Chill"] = { associatedType = "Cold", alt = false, default = 10, min = 5, max = data.gameConstants["ChillMaxEffect"], precision = 0, duration = data.gameConstants["BaseChillDuration"] }, ["Freeze"] = { associatedType = "Cold", alt = false, default = nil, min = 0.3, max = 3, precision = 2, duration = data.gameConstants["FreezeDuration"] }, - ["Shock"] = { associatedType = "Lightning", alt = false, default = 20, min = 20, max = 20, precision = 0, duration = data.gameConstants["BaseShockDuration"] }, + ["Shock"] = { associatedType = "Lightning", alt = false, default = 20, min = 20, max = 100, precision = 0, duration = data.gameConstants["BaseShockDuration"] }, } -- Used in ModStoreClass:ScaleAddMod(...) to identify high precision modifiers From a30893927e277b7e76c97636af34f7f5a9438c9b Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Mon, 10 Feb 2025 01:57:38 +1100 Subject: [PATCH 18/23] Remove unneeded comment and move to data.lua --- src/Modules/CalcOffence.lua | 96 ++----------------------------------- src/Modules/Data.lua | 44 +++++++++++++++++ 2 files changed, 49 insertions(+), 91 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index de6e42ea90..2bfd7e77c4 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3799,96 +3799,10 @@ function calcs.offence(env, actor, activeSkill) end skillFlags.impale = false - -- Ailment notes - - -- -- (PoE2) -- - -- "Flat chance ailments" - -- [Ailments that require chance and ignore threshold] - -- Bleed (damaging) - -- Poison (damaging) - - -- "Scaling threshold ailments" - -- [Ailments that use enemy ailment threshold (1% chance per 4% ailment threshold dealt)] - -- Ignite (damaging) - -- Shock (non-damaging) - - -- "Minimum threshold ailments" - -- [Ailments that "require a minimum threshold" (unknown number) but then always apply] - -- Chill (non-damaging) - - -- "Buildup ailments" - -- [Ailments that use buildup mechanic] - -- Electrocute (non-damaging) - -- Freeze (non-damaging) - -- Stun (non-damaging - not an ailment) - - -- Possible direct (i.e. not about damage hit modifier) crit effects on ailments (as of Jan 19 2025) - - -- Increased magnitude of damaging ailments inflicted with critical hits - -- -- (Notable) Shredding Force - -- -- (Notable) Cruel Fate - -- -- (Small) Spell Critical Chance and Critical Ailment Effect - - -- Increased magnitude of non-damaging ailments inflicted with critical hits - -- -- (Notable) Tainted Strike - - -- 100% poison chance - -- -- (Helmet) Atsak's Sight Veiled Mask - - -- Aggravate Bleeding on targets you Critically Hit with Attacks - -- -- (Helmet) The Smiling Knight Cowled Helm - - -- Various tree nodes for bleed chance on crit - -- Calculate ailment thresholds local enemyThreshold = data.monsterAilmentThresholdTable[env.enemyLevel] * enemyDB:More(nil, "AilmentThreshold") output['EnemyAilmentThreshold'] = enemyThreshold - -- TODO: Should probably be in Data.lua instead, or pulled from export data - local defaultAilmentDamageTypes = { - -- damaging - ["Bleed"] = { - ["ScalesFrom"] = { - ["Physical"] = true, - }, - ["DamageType"] = "Physical", - }, - ["Poison"] = { - ["ScalesFrom"] = { - ["Physical"] = true, - ["Chaos"] = true, - }, - ["DamageType"] = "Chaos", - }, - ["Ignite"] = { - ["ScalesFrom"] = { - ["Fire"] = true, - }, - ["DamageType"] = "Fire", - }, - -- non-damaging - ["Shock"] = { - ["ScalesFrom"] = { - ["Lightning"] = true, - } - }, - ["Chill"] = { - ["ScalesFrom"] = { - ["Cold"] = true, - } - }, - ["Freeze"] = { - ["ScalesFrom"] = { - ["Cold"] = true, - } - }, - ["Electrocute"] = { - ["ScalesFrom"] = { - ["Lightning"] = true, - } - }, - } - -- Calculate ailments and debuffs (poison, bleed, ignite, impale, exposure, etc) for _, pass in ipairs(passList) do globalOutput, globalBreakdown = output, breakdown @@ -4404,7 +4318,7 @@ function calcs.offence(env, actor, activeSkill) -- For Chill in-game tooltip says: -- "All Hits that have any Contribution to Chill Magnitude can Chill, without requiring an explicit chance to inflict, -- provided the Magnitudes meets a minimum threshold. So low damage Hits may still fail to Chill." - local unmitigatedColdDamage = calcAverageUnmitigatedSourceDamage("Chill", defaultAilmentDamageTypes["Chill"]["ScalesFrom"]) + local unmitigatedColdDamage = calcAverageUnmitigatedSourceDamage("Chill", data.defaultAilmentDamageTypes["Chill"]["ScalesFrom"]) local chillAilmentThresholdGuess = enemyThreshold / data.gameConstants.MiscAilmentChanceMultiplier * 15 -- Assume 15% is sufficient output['ChillAilmentThresholdGuess'] = chillAilmentThresholdGuess if unmitigatedColdDamage > chillAilmentThresholdGuess then @@ -4426,7 +4340,7 @@ function calcs.offence(env, actor, activeSkill) -- Calculate scaling threshold ailment chance for _, ailment in ipairs({"Ignite", "Shock"}) do - local hitMin, hitMax, critMin, critMax = calcMinMaxUnmitigatedAilmentSourceDamage(ailment, defaultAilmentDamageTypes[ailment]["ScalesFrom"]) + local hitMin, hitMax, critMin, critMax = calcMinMaxUnmitigatedAilmentSourceDamage(ailment, data.defaultAilmentDamageTypes[ailment]["ScalesFrom"]) -- TODO: average for now, can do more complicated calculation later local hitAvg = hitMin + (hitMax - hitMin) / 2 local critAvg = critMin + (critMax - critMin) / 2 @@ -4469,7 +4383,7 @@ function calcs.offence(env, actor, activeSkill) -- Calculate damaging ailment values for _, damagingAilment in ipairs({"Bleed", "Poison", "Ignite"}) do - calcDamagingAilmentOutputs(damagingAilment, defaultAilmentDamageTypes[damagingAilment]["DamageType"],defaultAilmentDamageTypes[damagingAilment]["ScalesFrom"]) + calcDamagingAilmentOutputs(damagingAilment, data.defaultAilmentDamageTypes[damagingAilment]["DamageType"], data.defaultAilmentDamageTypes[damagingAilment]["ScalesFrom"]) end -- Calculate non-damaging ailments effect and duration modifiers @@ -4511,7 +4425,7 @@ function calcs.offence(env, actor, activeSkill) s_format("Ailment mode: %s ^8(can be changed in the Configuration tab)", ailmentMode == "CRIT" and "Crits Only" or "Average Damage") } end - local baseVal = calcAilmentDamage("Freeze", output.CritChance, calcAverageUnmitigatedSourceDamage("Freeze", defaultAilmentDamageTypes["Freeze"]["ScalesFrom"])) * skillModList:More(cfg, "FreezeAsThoughDealing") + local baseVal = calcAilmentDamage("Freeze", output.CritChance, calcAverageUnmitigatedSourceDamage("Freeze", data.defaultAilmentDamageTypes["Freeze"]["ScalesFrom"])) * skillModList:More(cfg, "FreezeAsThoughDealing") if baseVal > 0 then skillFlags.freeze = true output.FreezeDurationMod = 1 + skillModList:Sum("INC", cfg, "EnemyFreezeDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration") / 100 + enemyDB:Sum("INC", nil, "SelfFreezeDuration", "SelfElementalAilmentDuration", "SelfAilmentDuration", "HoarfrostFreezeDuration") / 100 @@ -4528,7 +4442,7 @@ function calcs.offence(env, actor, activeSkill) s_format("Ailment mode: %s ^8(can be changed in the Configuration tab)", ailmentMode == "CRIT" and "Crits Only" or "Average Damage") } end - local damage = calcAilmentDamage(ailment, output.CritChance, calcAverageUnmitigatedSourceDamage(ailment, defaultAilmentDamageTypes[ailment]["ScalesFrom"])) * skillModList:More(cfg, ailment.."AsThoughDealing") + local damage = calcAilmentDamage(ailment, output.CritChance, calcAverageUnmitigatedSourceDamage(ailment, data.defaultAilmentDamageTypes[ailment]["ScalesFrom"])) * skillModList:More(cfg, ailment.."AsThoughDealing") if damage > 0 then skillFlags[string.lower(ailment)] = true local incDur = skillModList:Sum("INC", cfg, "Enemy"..ailment.."Duration", "EnemyElementalAilmentDuration", "EnemyAilmentDuration") + enemyDB:Sum("INC", nil, "Self"..ailment.."Duration", "SelfElementalAilmentDuration", "SelfAilmentDuration") diff --git a/src/Modules/Data.lua b/src/Modules/Data.lua index 5a926a1678..a3904b3784 100644 --- a/src/Modules/Data.lua +++ b/src/Modules/Data.lua @@ -305,6 +305,50 @@ data.nonDamagingAilment = { ["Shock"] = { associatedType = "Lightning", alt = false, default = 20, min = 20, max = 100, precision = 0, duration = data.gameConstants["BaseShockDuration"] }, } +data.defaultAilmentDamageTypes = { + -- damaging + ["Bleed"] = { + ["ScalesFrom"] = { + ["Physical"] = true, + }, + ["DamageType"] = "Physical", + }, + ["Poison"] = { + ["ScalesFrom"] = { + ["Physical"] = true, + ["Chaos"] = true, + }, + ["DamageType"] = "Chaos", + }, + ["Ignite"] = { + ["ScalesFrom"] = { + ["Fire"] = true, + }, + ["DamageType"] = "Fire", + }, + -- non-damaging + ["Shock"] = { + ["ScalesFrom"] = { + ["Lightning"] = true, + } + }, + ["Chill"] = { + ["ScalesFrom"] = { + ["Cold"] = true, + } + }, + ["Freeze"] = { + ["ScalesFrom"] = { + ["Cold"] = true, + } + }, + ["Electrocute"] = { + ["ScalesFrom"] = { + ["Lightning"] = true, + } + }, + } + -- Used in ModStoreClass:ScaleAddMod(...) to identify high precision modifiers data.defaultHighPrecision = 1 data.modScalability = LoadModule("Data/ModScalability") From dd80aa70a929c91315e62b84ba4af53be093b5e6 Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Mon, 10 Feb 2025 02:33:19 +1100 Subject: [PATCH 19/23] Fix Ailment Magnitude not working correctly --- src/Data/ModCache.lua | 8 ++++---- src/Modules/CalcDefence.lua | 2 +- src/Modules/CalcOffence.lua | 6 +++--- src/Modules/CalcPerform.lua | 4 ++-- src/Modules/CalcSections.lua | 8 ++++---- src/Modules/ModParser.lua | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index d7a0e25c0a..04bfee9b97 100755 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -766,7 +766,7 @@ c["10% increased Life Regeneration rate"]={{[1]={flags=0,keywordFlags=0,name="Li c["10% increased Life and Mana Recovery from Flasks"]={{[1]={flags=0,keywordFlags=0,name="FlaskLifeRecovery",type="INC",value=10},[2]={flags=0,keywordFlags=0,name="FlaskManaRecovery",type="INC",value=10}},nil} c["10% increased Lightning Damage"]={{[1]={flags=0,keywordFlags=0,name="LightningDamage",type="INC",value=10}},nil} c["10% increased Lightning Exposure Effect"]={{[1]={flags=0,keywordFlags=0,name="LightningExposureEffect",type="INC",value=10}},nil} -c["10% increased Magnitude of Ailments you inflict"]={{[1]={flags=0,keywordFlags=14680064,name="AilmentMagnitude",type="INC",value=10}},nil} +c["10% increased Magnitude of Ailments you inflict"]={{[1]={flags=0,keywordFlags=0,name="AilmentMagnitude",type="INC",value=10}},nil} c["10% increased Magnitude of Bleeding you inflict"]={{[1]={flags=0,keywordFlags=4194304,name="AilmentMagnitude",type="INC",value=10}},nil} c["10% increased Magnitude of Chill you inflict"]={{[1]={flags=0,keywordFlags=0,name="EnemyChillMagnitude",type="INC",value=10}},nil} c["10% increased Magnitude of Ignite you inflict"]={{[1]={flags=0,keywordFlags=8388608,name="AilmentMagnitude",type="INC",value=10}},nil} @@ -928,7 +928,7 @@ c["12% increased Freeze Buildup 12% increased chance to Shock"]={{[1]={flags=0,k c["12% increased Grenade Area of Effect"]={{[1]={[1]={skillType=169,type="SkillType"},flags=0,keywordFlags=0,name="AreaOfEffect",type="INC",value=12}},nil} c["12% increased Grenade Damage"]={{[1]={[1]={skillType=169,type="SkillType"},flags=0,keywordFlags=0,name="Damage",type="INC",value=12}},nil} c["12% increased Lightning Damage"]={{[1]={flags=0,keywordFlags=0,name="LightningDamage",type="INC",value=12}},nil} -c["12% increased Magnitude of Ailments you inflict"]={{[1]={flags=0,keywordFlags=14680064,name="AilmentMagnitude",type="INC",value=12}},nil} +c["12% increased Magnitude of Ailments you inflict"]={{[1]={flags=0,keywordFlags=0,name="AilmentMagnitude",type="INC",value=12}},nil} c["12% increased Magnitude of Ignite you inflict"]={{[1]={flags=0,keywordFlags=8388608,name="AilmentMagnitude",type="INC",value=12}},nil} c["12% increased Magnitude of Poison you inflict"]={{[1]={flags=0,keywordFlags=2097152,name="AilmentMagnitude",type="INC",value=12}},nil} c["12% increased Mana Regeneration Rate"]={{[1]={flags=0,keywordFlags=0,name="ManaRegen",type="INC",value=12}},nil} @@ -1658,7 +1658,7 @@ c["30% increased Life Recovery from Flasks"]={{[1]={flags=0,keywordFlags=0,name= c["30% increased Life Regeneration rate during Effect of any Life Flask"]={{[1]={[1]={type="Condition",var="UsingLifeFlask"},flags=0,keywordFlags=0,name="LifeRegen",type="INC",value=30}},nil} c["30% increased Light Radius"]={{[1]={flags=0,keywordFlags=0,name="LightRadius",type="INC",value=30}},nil} c["30% increased Lightning Exposure Effect"]={{[1]={flags=0,keywordFlags=0,name="LightningExposureEffect",type="INC",value=30}},nil} -c["30% increased Magnitude of Ailments you inflict"]={{[1]={flags=0,keywordFlags=14680064,name="AilmentMagnitude",type="INC",value=30}},nil} +c["30% increased Magnitude of Ailments you inflict"]={{[1]={flags=0,keywordFlags=0,name="AilmentMagnitude",type="INC",value=30}},nil} c["30% increased Magnitude of Chill you inflict"]={{[1]={flags=0,keywordFlags=0,name="EnemyChillMagnitude",type="INC",value=30}},nil} c["30% increased Magnitude of Non-Damaging Ailments you inflict"]={{[1]={flags=0,keywordFlags=0,name="EnemyShockMagnitude",type="INC",value=30},[2]={flags=0,keywordFlags=0,name="EnemyChillMagnitude",type="INC",value=30},[3]={flags=0,keywordFlags=0,name="EnemyFreezeEffect",type="INC",value=30}},nil} c["30% increased Magnitude of Non-Damaging Ailments you inflict with Critical Hits"]={{[1]={[1]={type="Condition",var="CriticalStrike"},flags=0,keywordFlags=0,name="EnemyShockMagnitude",type="INC",value=30},[2]={[1]={type="Condition",var="CriticalStrike"},flags=0,keywordFlags=0,name="EnemyChillMagnitude",type="INC",value=30},[3]={[1]={type="Condition",var="CriticalStrike"},flags=0,keywordFlags=0,name="EnemyFreezeEffect",type="INC",value=30}},nil} @@ -1924,7 +1924,7 @@ c["5% increased Dexterity"]={{[1]={flags=0,keywordFlags=0,name="Dex",type="INC", c["5% increased Duration of Damaging Ailments on Enemies"]={{[1]={flags=0,keywordFlags=0,name="EnemyIgniteDuration",type="INC",value=5},[2]={flags=0,keywordFlags=0,name="EnemyBleedDuration",type="INC",value=5},[3]={flags=0,keywordFlags=0,name="EnemyPoisonDuration",type="INC",value=5}},nil} c["5% increased Experience gain"]={{}," Experience gain "} c["5% increased Flask Effect Duration"]={{[1]={flags=0,keywordFlags=0,name="FlaskDuration",type="INC",value=5}},nil} -c["5% increased Magnitude of Ailments you inflict"]={{[1]={flags=0,keywordFlags=14680064,name="AilmentMagnitude",type="INC",value=5}},nil} +c["5% increased Magnitude of Ailments you inflict"]={{[1]={flags=0,keywordFlags=0,name="AilmentMagnitude",type="INC",value=5}},nil} c["5% increased Mana Cost of Skills"]={{[1]={flags=0,keywordFlags=0,name="ManaCost",type="INC",value=5}},nil} c["5% increased Maximum Life per Socketed Rune or Soul Core"]={{[1]={[1]={type="Multiplier",var="RunesSocketedIn{SlotName}"},flags=0,keywordFlags=0,name="Life",type="INC",value=5}},nil} c["5% increased Maximum Mana per Socketed Rune or Soul Core"]={{[1]={[1]={type="Multiplier",var="RunesSocketedIn{SlotName}"},flags=0,keywordFlags=0,name="Mana",type="INC",value=5}},nil} diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 826f856f59..e5d664ce39 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -1716,7 +1716,7 @@ function calcs.defence(env, actor) output["Self"..ailment.."Duration"] = more * inc / (100 + output.DebuffExpirationRate + modDB:Sum("BASE", nil, "Self"..ailment.."DebuffExpirationRate")) end for _, ailment in ipairs(data.ailmentTypeList) do - output["Self"..ailment.."Effect"] = calcLib.mod(modDB, nil, "Self"..ailment.."Effect") * (modDB:Flag(nil, "Condition:"..ailment.."edSelf") and calcLib.mod(modDB, nil, "Enemy"..ailment.."Magnitude") or calcLib.mod(enemyDB, nil, "Enemy"..ailment.."Magnitude")) * 100 + output["Self"..ailment.."Effect"] = calcLib.mod(modDB, nil, "Self"..ailment.."Effect") * (modDB:Flag(nil, "Condition:"..ailment.."edSelf") and calcLib.mod(modDB, nil, "Enemy"..ailment.."Magnitude", "AilmentMagnitude") or calcLib.mod(enemyDB, nil, "Enemy"..ailment.."Magnitude", "AilmentMagnitude")) * 100 end end diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 2bfd7e77c4..e52e80f111 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -4383,7 +4383,7 @@ function calcs.offence(env, actor, activeSkill) -- Calculate damaging ailment values for _, damagingAilment in ipairs({"Bleed", "Poison", "Ignite"}) do - calcDamagingAilmentOutputs(damagingAilment, data.defaultAilmentDamageTypes[damagingAilment]["DamageType"], data.defaultAilmentDamageTypes[damagingAilment]["ScalesFrom"]) + calcDamagingAilmentOutputs(damagingAilment, data.defaultAilmentDamageTypes[damagingAilment]["DamageType"], data.defaultAilmentDamageTypes[damagingAilment]["ScalesFrom"]) end -- Calculate non-damaging ailments effect and duration modifiers @@ -4403,7 +4403,7 @@ function calcs.offence(env, actor, activeSkill) } if activeSkill.skillTypes[SkillType.ChillingArea] or activeSkill.skillTypes[SkillType.NonHitChill] then skillFlags.chill = true - local incChill = skillModList:Sum("INC", cfg, "EnemyChillMagnitude") + local incChill = skillModList:Sum("INC", cfg, "EnemyChillMagnitude", "AilmentMagnitude") local moreChill = skillModList:More(cfg, "EnemyChillMagnitude") output.ChillEffectMod = (1 + incChill / 100) * moreChill output.ChillDurationMod = 1 + skillModList:Sum("INC", cfg, "EnemyChillDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration") / 100 @@ -4448,7 +4448,7 @@ function calcs.offence(env, actor, activeSkill) local incDur = skillModList:Sum("INC", cfg, "Enemy"..ailment.."Duration", "EnemyElementalAilmentDuration", "EnemyAilmentDuration") + enemyDB:Sum("INC", nil, "Self"..ailment.."Duration", "SelfElementalAilmentDuration", "SelfAilmentDuration") local moreDur = skillModList:More(cfg, "Enemy"..ailment.."Duration", "EnemyElementalAilmentDuration", "EnemyAilmentDuration") * enemyDB:More(nil, "Self"..ailment.."Duration", "SelfElementalAilmentDuration", "SelfAilmentDuration") output[ailment.."Duration"] = ailmentData[ailment].duration * (1 + incDur / 100) * moreDur * debuffDurationMult - output[ailment.."EffectMod"] = calcLib.mod(skillModList, cfg, "Enemy"..ailment.."Magnitude") + output[ailment.."EffectMod"] = calcLib.mod(skillModList, cfg, "Enemy"..ailment.."Magnitude", "AilmentMagnitude") if breakdown then local maximum = globalOutput["Maximum"..ailment] or ailmentData[ailment].max local current = m_max(m_min(globalOutput["Current"..ailment] or 0, maximum), 0) diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 03710254e1..3740b42b6d 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -2795,9 +2795,9 @@ function calcs.perform(env, skipEHP) -- if not, use the generic modifiers -- Scorch/Sap/Brittle do not have guaranteed sources from hits, and therefore will only end up in this bit of code if it's not supposed to apply the skillModList, which is bad if ailment ~= "Scorch" and ailment ~= "Sap" and ailment ~= "Brittle" and not env.player.mainSkill.skillModList:Flag(nil, "Cannot"..ailment) and hitFlag and modDB:Flag(nil, "ChecksHighestDamage") then - effect = effect * calcLib.mod(env.player.mainSkill.skillModList, env.player.mainSkill.skillModList.skillCfg, "Enemy"..ailment.."Magnitude") + effect = effect * calcLib.mod(env.player.mainSkill.skillModList, env.player.mainSkill.skillModList.skillCfg, "Enemy"..ailment.."Magnitude", "AilmentMagnitude") else - effect = effect * calcLib.mod(env.player.mainSkill.skillModList, env.player.mainSkill.skillModList.skillCfg, "Enemy"..ailment.."Magnitude") + effect = effect * calcLib.mod(env.player.mainSkill.skillModList, env.player.mainSkill.skillModList.skillCfg, "Enemy"..ailment.."Magnitude", "AilmentMagnitude") end modDB:NewMod(ailment.."Override", "BASE", effect, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) if mod.name == ailment.."Minimum" then diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 86decaa426..a4f28612c9 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -1201,7 +1201,7 @@ return { { breakdown = "MainHand.ChillDPS" }, { breakdown = "OffHand.ChillDPS" }, { breakdown = "ChillDPS" }, - { label = "Player modifiers", modName = { "EnemyChillMagnitude", "ChillAsThoughDealing" }, cfg = "skill" }, + { label = "Player modifiers", modName = { "EnemyChillMagnitude", "AilmentMagnitude", "ChillAsThoughDealing" }, cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfChillEffect", enemy = true }, }, }, { label = "Chill Duration", bgCol = colorCodes.CHILLBG, flag = "chill", { format = "{2:output:ChillDuration}s", @@ -1268,9 +1268,9 @@ return { { breakdown = "MainHand.ShockDPS" }, { breakdown = "OffHand.ShockDPS" }, { breakdown = "ShockDPS" }, - { label = "Player modifiers", notFlag = "attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "skill" }, - { label = "Main hand modifiers", flag = "weapon1Attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "weapon1" }, - { label = "Off hand modifiers", flag = "weapon2Attack", modName = { "EnemyShockMagnitude", "ShockAsThoughDealing" }, cfg = "weapon2" }, + { label = "Player modifiers", notFlag = "attack", modName = { "EnemyShockMagnitude", "AilmentMagnitude", "ShockAsThoughDealing" }, cfg = "skill" }, + { label = "Main hand modifiers", flag = "weapon1Attack", modName = { "EnemyShockMagnitude", "AilmentMagnitude", "ShockAsThoughDealing" }, cfg = "weapon1" }, + { label = "Off hand modifiers", flag = "weapon2Attack", modName = { "EnemyShockMagnitude", "AilmentMagnitude", "ShockAsThoughDealing" }, cfg = "weapon2" }, { label = "Enemy modifiers", modName = "SelfShockEffect", enemy = true }, }, }, { label = "Chance to Shock", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "{0:output:ShockChance}%", diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 7c8aa0e3cb..2bf7e3e44f 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -695,7 +695,7 @@ local modNameList = { ["magnitude of bleeding you inflict"] = { "AilmentMagnitude", keywordFlags = KeywordFlag.Bleed }, ["magnitude of ignite you inflict"] = { "AilmentMagnitude", keywordFlags = KeywordFlag.Ignite }, ["magnitude of poison you inflict"] = { "AilmentMagnitude", keywordFlags = KeywordFlag.Poison }, - ["magnitude of ailments you inflict"] = { "AilmentMagnitude", keywordFlags = bor(KeywordFlag.Poison, KeywordFlag.Bleed, KeywordFlag.Ignite) }, + ["magnitude of ailments you inflict"] = "AilmentMagnitude", ["magnitude of damaging ailments you inflict"] = { "AilmentMagnitude", keywordFlags = bor(KeywordFlag.Poison, KeywordFlag.Bleed, KeywordFlag.Ignite) }, ["effect of lightning ailments"] = "EnemyShockMagnitude", ["effect of chill and shock on you"] = { "SelfChillEffect", "SelfShockEffect" }, From f1f9b9dccaabef6404af1ae491d84dcfa4656ada Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Mon, 10 Feb 2025 11:29:13 +1100 Subject: [PATCH 20/23] Fix Ailment Threshold value on bosses --- src/Modules/CalcOffence.lua | 2 +- src/Modules/ConfigOptions.lua | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index e52e80f111..01cc94c2ee 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3800,7 +3800,7 @@ function calcs.offence(env, actor, activeSkill) skillFlags.impale = false -- Calculate ailment thresholds - local enemyThreshold = data.monsterAilmentThresholdTable[env.enemyLevel] * enemyDB:More(nil, "AilmentThreshold") + local enemyThreshold = data.monsterAilmentThresholdTable[env.enemyLevel] * calcLib.mod(enemyDB, nil, "AilmentThreshold") output['EnemyAilmentThreshold'] = enemyThreshold -- Calculate ailments and debuffs (poison, bleed, ignite, impale, exposure, etc) diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 048f615fc5..d7f51f08bf 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -1763,7 +1763,6 @@ Huge sets the radius to 11. build.configTab.varControls['enemyEvasion']:SetPlaceholder(data.monsterEvasionTable[defaultLevel], true) elseif val == "Boss" then enemyModList:NewMod("Condition:RareOrUnique", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) - enemyModList:NewMod("AilmentThreshold", "MORE", 488, "Boss") modList:NewMod("WarcryPower", "BASE", 20, "Boss") modList:NewMod("Multiplier:EnemyPower", "BASE", 20, "Boss") @@ -1798,7 +1797,6 @@ Huge sets the radius to 11. elseif val == "Pinnacle" then enemyModList:NewMod("Condition:RareOrUnique", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:PinnacleBoss", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) - enemyModList:NewMod("AilmentThreshold", "MORE", 404, "Boss") modList:NewMod("WarcryPower", "BASE", 20, "Boss") modList:NewMod("Multiplier:EnemyPower", "BASE", 20, "Boss") @@ -1808,7 +1806,7 @@ Huge sets the radius to 11. build.configTab.varControls['enemyFireResist']:SetPlaceholder(defaultEleResist, true) build.configTab.varControls['enemyChaosResist']:SetPlaceholder(0, true) - local defaultLevel = 84 + local defaultLevel = 82 build.configTab.varControls['enemyLevel']:SetPlaceholder(defaultLevel, true) build.configTab:UpdateLevel() if build.configTab.enemyLevel then @@ -1832,7 +1830,6 @@ Huge sets the radius to 11. enemyModList:NewMod("Condition:RareOrUnique", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:PinnacleBoss", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("DamageTaken", "MORE", -70, "Boss") - enemyModList:NewMod("AilmentThreshold", "MORE", 404, "Boss") modList:NewMod("WarcryPower", "BASE", 20, "Boss") modList:NewMod("Multiplier:EnemyPower", "BASE", 20, "Boss") From 66ede26c368278256bd3bccab460d4c4d0d94e79 Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Mon, 10 Feb 2025 12:35:34 +1100 Subject: [PATCH 21/23] Implement Minimum Chill values --- src/Modules/CalcOffence.lua | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 01cc94c2ee..7b5bb8c212 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -4313,15 +4313,11 @@ function calcs.offence(env, actor, activeSkill) skillFlags["inflict"..flatAilment] = true end end - - -- TODO: Placeholder values until proper numbers are figured out - -- For Chill in-game tooltip says: - -- "All Hits that have any Contribution to Chill Magnitude can Chill, without requiring an explicit chance to inflict, - -- provided the Magnitudes meets a minimum threshold. So low damage Hits may still fail to Chill." + local unmitigatedColdDamage = calcAverageUnmitigatedSourceDamage("Chill", data.defaultAilmentDamageTypes["Chill"]["ScalesFrom"]) - local chillAilmentThresholdGuess = enemyThreshold / data.gameConstants.MiscAilmentChanceMultiplier * 15 -- Assume 15% is sufficient - output['ChillAilmentThresholdGuess'] = chillAilmentThresholdGuess - if unmitigatedColdDamage > chillAilmentThresholdGuess then + local chillMinimumThreshold = enemyThreshold / data.gameConstants.ChillEffectMultiplier + output['chillMinimumThreshold'] = chillMinimumThreshold + if unmitigatedColdDamage > chillMinimumThreshold then output["ChillChanceOnHit"] = 100 output["ChillChanceOnCrit"] = 100 skillFlags["inflictChill"] = true From 504c51aac658154bda4d5005feb1fa0c2b5fe0ff Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Mon, 10 Feb 2025 12:39:57 +1100 Subject: [PATCH 22/23] Fix Current shock for Stormweaver node --- src/Modules/CalcPerform.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 3740b42b6d..72322eb879 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -2760,6 +2760,7 @@ function calcs.perform(env, skipEHP) if modDB:Flag(nil, "ShockCanStack") then output.ShockStackCount = m_min(enemyDB:Sum("BASE", nil, "Multiplier:ShockStacks"), modDB:Override(nil, "ShockStacksMax") or modDB:Sum("BASE", nil, "ShockStacksMax")) t_insert(mods, modLib.createMod("DamageTaken", "INC", num, "Shock", { type = "Condition", var = "Shocked" }, { type = "Multiplier", var = "ShockStacks", limit = modDB:Override(nil, "ShockStacksMax") or modDB:Sum("BASE", nil, "ShockStacksMax")})) + output["CurrentShock"] = num * m_min(enemyDB:Sum("BASE", nil, "Multiplier:ShockStacks"), modDB:Override(nil, "ShockStacksMax") or modDB:Sum("BASE", nil, "ShockStacksMax")) if breakdown then t_insert(mods, modLib.createMod("DamageTakenByShock", "INC", num, "Shock Stacks", { type = "Condition", var = "Shocked" }, { type = "Multiplier", var = "ShockStacks", limit = modDB:Override(nil, "ShockStacksMax") or modDB:Sum("BASE", nil, "ShockStacksMax")})) end From 1f9c983dd2962473fb6ceec3db23a4080b751a80 Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Mon, 10 Feb 2025 13:09:20 +1100 Subject: [PATCH 23/23] Fix breakdowns --- src/Modules/CalcOffence.lua | 6 ++---- src/Modules/CalcSections.lua | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 7b5bb8c212..94f26e5c0c 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -4386,8 +4386,8 @@ function calcs.offence(env, actor, activeSkill) local nonDamagingAilmentsConfig = { ["Chill"] = { effList = { 10, 20 }, - effect = function(damage, effectMod) return 50 * ((damage / enemyThreshold) ^ 0.4) * effectMod end, - thresh = function(damage, value, effectMod) return damage * ((50 * effectMod / value) ^ 2.5) end, + effect = function(damage, effectMod) return data.gameConstants.ChillEffectMultiplier * (damage / enemyThreshold) * effectMod end, + thresh = function(damage, value, effectMod) return damage * (data.gameConstants.ChillEffectMultiplier * effectMod / value) end, ramping = false, }, ["Shock"] = { @@ -4427,7 +4427,6 @@ function calcs.offence(env, actor, activeSkill) output.FreezeDurationMod = 1 + skillModList:Sum("INC", cfg, "EnemyFreezeDuration", "EnemyAilmentDuration", "EnemyElementalAilmentDuration") / 100 + enemyDB:Sum("INC", nil, "SelfFreezeDuration", "SelfElementalAilmentDuration", "SelfAilmentDuration", "HoarfrostFreezeDuration") / 100 if breakdown then t_insert(breakdown.FreezeDPS, s_format("For freeze to apply for the minimum of 0.3 seconds, target must have no more than %.0f Ailment Threshold.", baseVal * 20 * output.FreezeDurationMod)) - t_insert(breakdown.FreezeDPS, s_format("^8(Ailment Threshold is about equal to Life except on bosses where it is about half of their life)")) end end end @@ -4465,7 +4464,6 @@ function calcs.offence(env, actor, activeSkill) t_insert(val.effList, desired) end breakdown[ailment.."DPS"].label = "Resulting ailment effect"..((current > 0 and val.ramping) and s_format(" ^8(with a ^7%s%% ^8%s on the enemy)^7", current, ailment) or "") - breakdown[ailment.."DPS"].footer = s_format("^8(ailment threshold is about equal to life, except on bosses that have specific ailment thresholds)\n(the above table shows that when the enemy has X ailment threshold, you ^8%s for Y)", ailment:lower()) breakdown[ailment.."DPS"].rowList = { } breakdown[ailment.."DPS"].colList = { { label = "Ailment Threshold", key = "thresh" }, diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index a4f28612c9..d2df054fd0 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -1165,6 +1165,7 @@ return { } } } }, { 1, "EleAilments", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Non-Damaging Ailments", data = { + { label = "Enemy Ail. Thresh.", { format = "{0:output:EnemyAilmentThreshold}", { modName = "EnemyAilmentThreshold" }, }, }, { label = "Scorch Effect Mod", bgCol = colorCodes.SCORCHBG, flag = "scorch", { format = "x {2:output:ScorchEffectMod}", { breakdown = "ScorchEffectMod" }, { breakdown = "MainHand.ScorchDPS" }, @@ -1262,7 +1263,6 @@ return { { label = "Configured Brittle", modName = "BrittleVal", enemy = true, modType = "BASE" }, { label = "Guaranteed Brittles", modName = "BrittleOverride", modType = "BASE" }, }, }, - { label = "Enemy Ail. Thresh.", { format = "{0:output:EnemyAilmentThreshold}", { modName = "EnemyAilmentThreshold" }, }, }, { label = "Shock Effect Mod", bgCol = colorCodes.SHOCKBG, flag = "shock", { format = "x {2:output:ShockEffectMod}", { breakdown = "ShockEffectMod" }, { breakdown = "MainHand.ShockDPS" },