Merge remote-tracking branch 'origin/dev'

This commit is contained in:
Openarl
2017-01-30 02:21:00 +10:00
6 changed files with 379 additions and 218 deletions

View File

@@ -184,7 +184,7 @@ return {
{ 1, "Bleed", 1, "Bleed", data.colorCodes.OFFENCE, {
extra = "{0:output:BleedChance}% {1:output:BleedDPS} {2:output:BleedDuration}s",
flag = "bleed",
{ label = "Chance to Bleed", { format = "{0:output:BleedChance}%", { modName = "BleedChance", cfg = "skill" }, }, },
{ label = "Chance to Bleed", { format = "{0:output:BleedChance}%", { breakdown = "BleedChance" }, { modName = "BleedChance", cfg = "skill" }, }, },
{ label = "Total Increased", { format = "{0:mod:1}%", { modName = { "Damage", "PhysicalDamage" }, modType = "INC", cfg = "bleed" }, }, },
{ label = "Total More", { format = "{0:mod:1}%", { modName = { "Damage", "PhysicalDamage" }, modType = "MORE", cfg = "bleed" }, }, },
{ label = "Effective DPS Mod", flag = "effective", { format = "x {3:output:BleedEffMult}", { breakdown = "BleedEffMult" }, { label = "Enemy modifiers", modName = { "DamageTaken", "DotTaken", "PhysicalDamageTaken", "PhysicalDamageReduction" }, enemy = true }, }, },
@@ -194,7 +194,7 @@ return {
{ 1, "Poison", 1, "Poison", data.colorCodes.OFFENCE, {
extra = "{0:output:PoisonChance}% {1:output:PoisonDPS} {2:output:PoisonDuration}s",
flag = "poison",
{ label = "Chance to Poison", { format = "{0:output:PoisonChance}%", { modName = "PoisonChance", cfg = "skill" }, }, },
{ label = "Chance to Poison", { format = "{0:output:PoisonChance}%", { breakdown = "PoisonChance" }, { modName = "PoisonChance", cfg = "skill" }, }, },
{ label = "Total Increased", { format = "{0:mod:1}%", { modName = { "Damage", "ChaosDamage" }, modType = "INC", cfg = "poison" }, }, },
{ label = "Total More", { format = "{0:mod:1}%", { modName = { "Damage", "ChaosDamage" }, modType = "MORE", cfg = "poison" }, }, },
{ label = "Effective DPS Mod", flag = "effective", { format = "x {3:output:PoisonEffMult}", { breakdown = "PoisonEffMult" }, { label = "Enemy modifiers", modName = { "ChaosResist", "DamageTaken", "DotTaken", "ChaosDamageTaken" }, enemy = true }, }, },
@@ -205,7 +205,7 @@ return {
{ 1, "Ignite", 1, "Ignite", data.colorCodes.OFFENCE, {
extra = "{0:output:IgniteChance}% {1:output:IgniteDPS} {2:output:IgniteDuration}s",
flag = "ignite",
{ label = "Chance to Ignite", { format = "{0:output:IgniteChance}%", { label = "Player modifiers", modName = "EnemyIgniteChance", cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfIgniteChance", enemy = true }, }, },
{ label = "Chance to Ignite", { format = "{0:output:IgniteChance}%", { breakdown = "IgniteChance" }, { label = "Player modifiers", modName = "EnemyIgniteChance", cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfIgniteChance", enemy = true }, }, },
{ label = "Total Increased", { format = "{0:mod:1}%", { modName = { "Damage", "FireDamage", "ElementalDamage" }, modType = "INC", cfg = "ignite" }, }, },
{ label = "Total More", { format = "{0:mod:1}%", { modName = { "Damage", "FireDamage", "ElementalDamage" }, modType = "MORE", cfg = "ignite" }, }, },
{ label = "Effective DPS Mod", flag = "effective", { format = "x {3:output:IgniteEffMult}", { breakdown = "IgniteEffMult" }, { label = "Enemy modifiers", modName = { "FireResist", "ElementalResist", "DamageTaken", "DotTaken", "FireDamageTaken", "BurningDamageTaken", "ElementalDamageTaken" }, enemy = true }, }, },
@@ -215,10 +215,10 @@ return {
} },
{ 1, "MiscEffects", 1, "Other Effects", data.colorCodes.OFFENCE, {
flag = "hit",
{ label = "Chance to Shock", flag = "shock", { format = "{0:output:ShockChance}%", { label = "Player modifiers", modName = "EnemyShockChance", cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfShockChance", enemy = true }, }, },
{ label = "Shock Dur. Mod", flag = "shock", { format = "x {2:output:ShockDurationMod}", { label = "Player modifiers", modName = "EnemyShockDuration", cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfShockDuration", enemy = true }, }, },
{ label = "Chance to Freeze", flag = "freeze", { format = "{0:output:FreezeChance}%", { label = "Player modifiers", modName = "EnemyFreezeChance", cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfFreezeChance", enemy = true }, }, },
{ label = "Freeze Dur. Mod", flag = "freeze", { format = "x {2:output:FreezeDurationMod}", { label = "Player modifiers", modName = "EnemyFreezeDuration", cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfFreezeDuration", enemy = true }, }, },
{ label = "Chance to Shock", flag = "shock", { format = "{0:output:ShockChance}%", { breakdown = "ShockChance" }, { label = "Player modifiers", modName = "EnemyShockChance", cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfShockChance", enemy = true }, }, },
{ label = "Shock Dur. Mod", flag = "shock", { format = "x {2:output:ShockDurationMod}", { breakdown = "ShockDPS" }, { label = "Player modifiers", modName = "EnemyShockDuration", cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfShockDuration", enemy = true }, }, },
{ label = "Chance to Freeze", flag = "freeze", { format = "{0:output:FreezeChance}%", { breakdown = "FreezeChance" }, { label = "Player modifiers", modName = "EnemyFreezeChance", cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfFreezeChance", enemy = true }, }, },
{ label = "Freeze Dur. Mod", flag = "freeze", { format = "x {2:output:FreezeDurationMod}", { breakdown = "FreezeDPS" }, { label = "Player modifiers", modName = "EnemyFreezeDuration", cfg = "skill" }, { label = "Enemy modifiers", modName = "SelfFreezeDuration", enemy = true }, }, },
{ label = "Stun Thresh. Mod", { format = "x {2:output:EnemyStunThresholdMod}", { modName = "EnemyStunThreshold", cfg = "skill" }, }, },
{ label = "Stun Duration", { format = "{2:output:EnemyStunDuration}s", { breakdown = "EnemyStunDuration" }, { label = "Player modifiers", modName = { "EnemyStunDuration" }, cfg = "skill" }, { label = "Enemy modifiers", modName = { "StunRecovery" }, enemy = true }, }, },
{ label = "Inc. Item Quantity", { format = "{0:mod:1}%", { modName = "LootQuantity", modType = "INC", cfg = "skill" }, }, },

View File

@@ -3,7 +3,7 @@
-- Module: Calcs
-- Performs all the offense and defense calculations.
-- Here be dragons!
-- This file is 2400 lines long, over half of which is in one function...
-- This file is 2700 lines long, over half of which is in one function...
--
local pairs = pairs
@@ -933,7 +933,7 @@ local function mergeMainMods(env, repSlotName, repItem)
end
-- Finalise environment and perform the calculations
-- This function is 1300 lines long. Enjoy!
-- This function is 1600 lines long. Enjoy!
local function performCalcs(env)
local modDB = env.modDB
local enemyDB = env.enemyDB
@@ -1811,6 +1811,32 @@ local function performCalcs(env)
env.conversionTable[damageType] = dmgTable
end
env.conversionTable["Chaos"] = { mult = 1 }
-- Calculate mana cost (may be slightly off due to rounding differences)
do
local more = m_floor(modDB:Sum("MORE", skillCfg, "ManaCost") * 100 + 0.0001) / 100
local inc = modDB:Sum("INC", skillCfg, "ManaCost")
local base = modDB:Sum("BASE", skillCfg, "ManaCost")
output.ManaCost = m_floor(m_max(0, (skillData.manaCost or 0) * more * (1 + inc / 100) + base))
if env.mainSkill.skillTypes[SkillType.ManaCostPercent] and skillFlags.totem then
output.ManaCost = m_floor(output.Mana * output.ManaCost / 100)
end
if breakdown and output.ManaCost ~= (skillData.manaCost or 0) then
breakdown.ManaCost = {
s_format("%d ^8(base mana cost)", skillData.manaCost or 0)
}
if more ~= 1 then
t_insert(breakdown.ManaCost, s_format("x %.2f ^8(mana cost multiplier)", more))
end
if inc ~= 0 then
t_insert(breakdown.ManaCost, s_format("x %.2f ^8(increased/reduced mana cost)", 1 + inc/100))
end
if base ~= 0 then
t_insert(breakdown.ManaCost, s_format("- %d ^8(- mana cost)", -base))
end
t_insert(breakdown.ManaCost, s_format("= %d", output.ManaCost))
end
end
-- Calculate hit chance
output.Accuracy = calcVal(modDB, "Accuracy", skillCfg)
@@ -1925,9 +1951,7 @@ local function performCalcs(env)
end
end
end
if modDB:Sum("FLAG", skillCfg, "NoCritDamage") then
output.CritMultiplier = 0
elseif modDB:Sum("FLAG", skillCfg, "NoCritMultiplier") then
if modDB:Sum("FLAG", skillCfg, "NoCritMultiplier") then
output.CritMultiplier = 1
else
local extraDamage = 0.5 + modDB:Sum("BASE", skillCfg, "CritMultiplier") / 100
@@ -1961,8 +1985,11 @@ local function performCalcs(env)
end
-- Calculate hit damage for each damage type
local totalMin, totalMax = 0, 0
do
local totalHitMin, totalHitMax = 0, 0
local totalCritMin, totalCritMax = 0, 0
for pass = 1, 2 do
-- Pass 1 is critical strike damage, pass 2 is non-critical strike
condList["CriticalStrike"] = (pass == 1)
local hitSource = (env.mode_skillType == "ATTACK") and env.weaponData1 or env.mainSkill.skillData
for _, damageType in ipairs(dmgTypeList) do
local min, max
@@ -1983,6 +2010,11 @@ local function performCalcs(env)
end
min = min * convMult
max = max * convMult
if pass == 1 then
-- Apply crit multiplier
min = min * output.CritMultiplier
max = max * output.CritMultiplier
end
if (min ~= 0 or max ~= 0) and env.mode_effective then
-- Apply enemy resistances and damage taken modifiers
local preMult
@@ -2001,7 +2033,10 @@ local function performCalcs(env)
if skillFlags.projectile then
taken = taken + enemyDB:Sum("INC", nil, "ProjectileDamageTaken")
end
local effMult = (1 - (resist - pen) / 100) * (1 + taken / 100)
local effMult = (1 + taken / 100)
if not isElemental[damageType] or not modDB:Sum("FLAG", skillCfg, "IgnoreElementalResistances") then
effMult = effMult * (1 - (resist - pen) / 100)
end
min = min * effMult
max = max * effMult
if env.mode == "CALCS" then
@@ -2023,25 +2058,31 @@ local function performCalcs(env)
}
end
end
if env.mode == "CALCS" then
output[damageType.."Min"] = min
output[damageType.."Max"] = max
if pass == 1 then
output[damageType.."CritAverage"] = (min + max) / 2
totalCritMin = totalCritMin + min
totalCritMax = totalCritMax + max
else
if env.mode == "CALCS" then
output[damageType.."Min"] = min
output[damageType.."Max"] = max
end
output[damageType.."HitAverage"] = (min + max) / 2
totalHitMin = totalHitMin + min
totalHitMax = totalHitMax + max
end
output[damageType.."Average"] = (min + max) / 2
totalMin = totalMin + min
totalMax = totalMax + max
end
end
output.TotalMin = totalMin
output.TotalMax = totalMax
output.TotalMin = totalHitMin
output.TotalMax = totalHitMax
-- Update enemy hit-by-damage-type conditions
enemyDB.conditions.HitByFireDamage = output.FireAverage > 0
enemyDB.conditions.HitByColdDamage = output.ColdAverage > 0
enemyDB.conditions.HitByLightningDamage = output.LightningAverage > 0
enemyDB.conditions.HitByFireDamage = output.FireHitAverage > 0
enemyDB.conditions.HitByColdDamage = output.ColdHitAverage > 0
enemyDB.conditions.HitByLightningDamage = output.LightningHitAverage > 0
-- Calculate average damage and final DPS
output.AverageHit = (totalMin + totalMax) / 2 * output.CritEffect
output.AverageHit = (totalHitMin + totalHitMax) / 2 * (1 - output.CritChance / 100) + (totalCritMin + totalCritMax) / 2 * output.CritChance / 100
output.AverageDamage = output.AverageHit * output.HitChance / 100
output.TotalDPS = output.AverageDamage * (output.HitSpeed or output.Speed) * (skillData.dpsMultiplier or 1)
if env.mode == "CALCS" then
@@ -2054,8 +2095,8 @@ local function performCalcs(env)
if breakdown then
if output.CritEffect ~= 1 then
breakdown.AverageHit = {
s_format("%.1f ^8(non-crit average)", (totalMin + totalMax) / 2),
s_format("x %.3f ^8(crit effect modifier)", output.CritEffect),
s_format("%.1f x (1 - %.4f) ^8(damage from non-crits)", (totalHitMin + totalHitMax) / 2, output.CritChance / 100),
s_format("+ %.1f x %.4f ^8(damage from crits)", (totalCritMin + totalCritMax) / 2, output.CritChance / 100),
s_format("= %.1f", output.AverageHit),
}
end
@@ -2081,32 +2122,6 @@ local function performCalcs(env)
t_insert(breakdown.TotalDPS, s_format("= %.1f", output.TotalDPS))
end
-- Calculate mana cost (may be slightly off due to rounding differences)
do
local more = m_floor(modDB:Sum("MORE", skillCfg, "ManaCost") * 100 + 0.0001) / 100
local inc = modDB:Sum("INC", skillCfg, "ManaCost")
local base = modDB:Sum("BASE", skillCfg, "ManaCost")
output.ManaCost = m_floor(m_max(0, (skillData.manaCost or 0) * more * (1 + inc / 100) + base))
if env.mainSkill.skillTypes[SkillType.ManaCostPercent] and skillFlags.totem then
output.ManaCost = m_floor(output.Mana * output.ManaCost / 100)
end
if breakdown and output.ManaCost ~= (skillData.manaCost or 0) then
breakdown.ManaCost = {
s_format("%d ^8(base mana cost)", skillData.manaCost or 0)
}
if more ~= 1 then
t_insert(breakdown.ManaCost, s_format("x %.2f ^8(mana cost multiplier)", more))
end
if inc ~= 0 then
t_insert(breakdown.ManaCost, s_format("x %.2f ^8(increased/reduced mana cost)", 1 + inc/100))
end
if base ~= 0 then
t_insert(breakdown.ManaCost, s_format("- %d ^8(- mana cost)", -base))
end
t_insert(breakdown.ManaCost, s_format("= %d", output.ManaCost))
end
end
-- Calculate skill DOT components
local dotCfg = {
skillName = skillCfg.skillName,
@@ -2133,13 +2148,14 @@ local function performCalcs(env)
if damageType == "Physical" then
resist = enemyDB:Sum("INC", nil, "PhysicalDamageReduction")
else
resist = enemyDB:Sum("BASE", nil, damageType.."Resist")
if isElemental[damageType] then
resist = resist + enemyDB:Sum("BASE", nil, "ElementalResist")
taken = taken + enemyDB:Sum("INC", nil, "ElementalDamageTaken")
end
if damageType == "Fire" then
taken = taken + enemyDB:Sum("INC", nil, "BurningDamageTaken")
end
resist = output["Enemy"..damageType.."Resist"]
end
effMult = (1 - resist / 100) * (1 + taken / 100)
output[damageType.."DotEffMult"] = effMult
@@ -2159,148 +2175,241 @@ local function performCalcs(env)
end
end
-- Calculate bleeding chance and damage
skillFlags.bleed = false
output.BleedChance = m_min(100, modDB:Sum("BASE", skillCfg, "BleedChance"))
if canDeal.Physical and not modDB:Sum("FLAG", skillCfg, "CannotBleed") and output.BleedChance > 0 and output.PhysicalAverage > 0 then
skillFlags.bleed = true
skillFlags.duration = true
local dotCfg = {
slotName = skillCfg.slotName,
flags = bor(band(skillCfg.flags, ModFlag.SourceMask), ModFlag.Dot, skillData.dotIsSpell and ModFlag.Spell or 0),
keywordFlags = bor(skillCfg.keywordFlags, KeywordFlag.Bleed)
}
env.mainSkill.bleedCfg = dotCfg
local baseVal = output.PhysicalAverage * output.CritEffect * 0.1
local effMult = 1
if env.mode_effective then
local resist = enemyDB:Sum("INC", nil, "PhysicalDamageReduction")
local taken = enemyDB:Sum("INC", dotCfg, "DamageTaken", "PhysicalDamageTaken", "DotTaken")
effMult = (1 - resist / 100) * (1 + taken / 100)
output["BleedEffMult"] = effMult
if breakdown and effMult ~= 1 then
breakdown.BleedEffMult = effMultBreakdown("Physical", resist, 0, taken, effMult)
-- Calculate chance to inflict secondary dots/status effects
condList["CriticalStrike"] = true
if modDB:Sum("FLAG", skillCfg, "CannotBleed") then
output.BleedChanceOnCrit = 0
else
output.BleedChanceOnCrit = m_min(100, modDB:Sum("BASE", skillCfg, "BleedChance"))
end
output.PoisonChanceOnCrit = m_min(100, modDB:Sum("BASE", skillCfg, "PoisonChance"))
if modDB:Sum("FLAG", skillCfg, "CannotIgnite") then
output.IgniteChanceOnCrit = 0
else
output.IgniteChanceOnCrit = 100
end
if modDB:Sum("FLAG", skillCfg, "CannotShock") then
output.ShockChanceOnCrit = 0
else
output.ShockChanceOnCrit = 100
end
if modDB:Sum("FLAG", skillCfg, "CannotFreeze") then
output.FreezeChanceOnCrit = 0
else
output.FreezeChanceOnCrit = 100
end
condList["CriticalStrike"] = false
if modDB:Sum("FLAG", skillCfg, "CannotBleed") then
output.BleedChanceOnHit = 0
else
output.BleedChanceOnHit = m_min(100, modDB:Sum("BASE", skillCfg, "BleedChance"))
end
output.PoisonChanceOnHit = m_min(100, modDB:Sum("BASE", skillCfg, "PoisonChance"))
if modDB:Sum("FLAG", skillCfg, "CannotIgnite") then
output.IgniteChanceOnHit = 0
else
output.IgniteChanceOnHit = m_min(100, modDB:Sum("BASE", skillCfg, "EnemyIgniteChance") + enemyDB:Sum("BASE", nil, "SelfIgniteChance"))
end
if modDB:Sum("FLAG", skillCfg, "CannotShock") then
output.ShockChanceOnHit = 0
else
output.ShockChanceOnHit = m_min(100, modDB:Sum("BASE", skillCfg, "EnemyShockChance") + enemyDB:Sum("BASE", nil, "SelfShockChance"))
end
if modDB:Sum("FLAG", skillCfg, "CannotFreeze") then
output.FreezeChanceOnHit = 0
else
output.FreezeChanceOnHit = m_min(100, modDB:Sum("BASE", skillCfg, "EnemyFreezeChance") + enemyDB:Sum("BASE", nil, "SelfFreezeChance"))
if modDB:Sum("FLAG", skillCfg, "CritsDontAlwaysFreeze") then
output.FreezeChanceOnCrit = output.FreezeChanceOnHit
end
end
local function calcSecondaryEffectBase(type, sourceHitDmg, sourceCritDmg)
-- Calculate the inflict chance and base damage of a secondary effect (bleed/poison/ignite/shock/freeze)
local chanceOnHit, chanceOnCrit = output[type.."ChanceOnHit"], output[type.."ChanceOnCrit"]
local chanceFromHit = chanceOnHit * (1 - output.CritChance / 100)
local chanceFromCrit = chanceOnCrit * output.CritChance / 100
local chance = chanceFromHit + chanceFromCrit
output[type.."Chance"] = chance
local baseFromHit = sourceHitDmg * chanceFromHit / (chanceFromHit + chanceFromCrit)
local baseFromCrit = sourceCritDmg * chanceFromCrit / (chanceFromHit + chanceFromCrit)
local baseVal = baseFromHit + baseFromCrit
if breakdown and chance ~= 0 then
local breakdownChance = {
s_format("Chance on Non-crit: %d%%", chanceOnHit),
s_format("Chance on Crit: %d%%", chanceOnCrit),
}
if chanceOnHit ~= chanceOnCrit then
t_insert(breakdownChance, "Combined chance:")
t_insert(breakdownChance, s_format("%d x (1 - %.4f) ^8(chance from non-crits)", chanceOnHit, output.CritChance/100))
t_insert(breakdownChance, s_format("+ %d x %.4f ^8(chance from crits)", chanceOnCrit, output.CritChance/100))
t_insert(breakdownChance, s_format("= %.2f", chance))
end
breakdown[type.."Chance"] = breakdownChance
end
if breakdown and baseVal > 0 then
local breakdownDPS = breakdown[type.."DPS"]
if sourceHitDmg == sourceCritDmg then
t_insert(breakdownDPS, "Base damage:")
t_insert(breakdownDPS, s_format("%.1f ^8(source damage)",sourceHitDmg))
else
if baseFromHit > 0 then
t_insert(breakdownDPS, "Base from Non-crits:")
t_insert(breakdownDPS, s_format("%.1f ^8(source damage from non-crits)", sourceHitDmg))
t_insert(breakdownDPS, s_format("x %.3f ^8(portion of instances created by non-crits)", chanceFromHit / (chanceFromHit + chanceFromCrit)))
t_insert(breakdownDPS, s_format("= %.1f", baseFromHit))
end
if baseFromCrit > 0 then
t_insert(breakdownDPS, "Base from Crits:")
t_insert(breakdownDPS, s_format("%.1f ^8(source damage from crits)", sourceCritDmg))
t_insert(breakdownDPS, s_format("x %.3f ^8(portion of instances created by crits)", chanceFromCrit / (chanceFromHit + chanceFromCrit)))
t_insert(breakdownDPS, s_format("= %.1f", baseFromCrit))
end
if baseFromHit > 0 and baseFromCrit > 0 then
t_insert(breakdownDPS, "Total base damage:")
t_insert(breakdownDPS, s_format("%.1f + %.1f", baseFromHit, baseFromCrit))
t_insert(breakdownDPS, s_format("= %.1f", baseVal))
end
end
end
local inc = modDB:Sum("INC", dotCfg, "Damage", "PhysicalDamage")
local more = round(modDB:Sum("MORE", dotCfg, "Damage", "PhysicalDamage"), 2)
output.BleedDPS = baseVal * (1 + inc/100) * more * effMult
output.BleedDuration = 5 * calcMod(modDB, dotCfg, "Duration") * debuffDurationMult
if breakdown then
breakdown.BleedDPS = {
"Base damage:",
s_format("%.1f ^8(average physical non-crit damage)", output.PhysicalAverage)
return baseVal
end
-- Calculate bleeding chance and damage
skillFlags.bleed = false
if canDeal.Physical and (output.BleedChanceOnHit + output.BleedChanceOnCrit) > 0 then
local sourceHitDmg = output.PhysicalHitAverage
local sourceCritDmg = output.PhysicalCritAverage
if sourceHitDmg + sourceCritDmg > 0 then
skillFlags.bleed = true
skillFlags.duration = true
local dotCfg = {
slotName = skillCfg.slotName,
flags = bor(band(skillCfg.flags, ModFlag.SourceMask), ModFlag.Dot, skillData.dotIsSpell and ModFlag.Spell or 0),
keywordFlags = bor(skillCfg.keywordFlags, KeywordFlag.Bleed)
}
if output.CritEffect ~= 1 then
t_insert(breakdown.BleedDPS, s_format("x %.3f ^8(crit effect modifier)", output.CritEffect))
env.mainSkill.bleedCfg = dotCfg
if breakdown then
breakdown.BleedDPS = { }
end
t_insert(breakdown.BleedDPS, "x 0.1 ^8(bleed deals 10% per second)")
t_insert(breakdown.BleedDPS, s_format("= %.1f", baseVal, 1))
t_insert(breakdown.BleedDPS, "Bleed DPS:")
dotBreakdown(breakdown.BleedDPS, baseVal, inc, more, effMult, output.BleedDPS)
if output.BleedDuration ~= 5 then
breakdown.BleedDuration = {
"5.00s ^8(base duration)"
}
if output.DurationMod ~= 1 then
t_insert(breakdown.BleedDuration, s_format("x %.2f ^8(duration modifier)", calcMod(modDB, dotCfg, "Duration")))
local baseVal = calcSecondaryEffectBase("Bleed", sourceHitDmg, sourceCritDmg) * 0.1
local effMult = 1
if env.mode_effective then
local resist = enemyDB:Sum("INC", nil, "PhysicalDamageReduction")
local taken = enemyDB:Sum("INC", dotCfg, "DamageTaken", "PhysicalDamageTaken", "DotTaken")
effMult = (1 - resist / 100) * (1 + taken / 100)
output["BleedEffMult"] = effMult
if breakdown and effMult ~= 1 then
breakdown.BleedEffMult = effMultBreakdown("Physical", resist, 0, taken, effMult)
end
if debuffDurationMult ~= 1 then
t_insert(breakdown.BleedDuration, s_format("/ %.2f ^8(debuff expires slower/faster)", 1 / debuffDurationMult))
end
local inc = modDB:Sum("INC", dotCfg, "Damage", "PhysicalDamage")
local more = round(modDB:Sum("MORE", dotCfg, "Damage", "PhysicalDamage"), 2)
output.BleedDPS = baseVal * (1 + inc/100) * more * effMult
local durationMod = calcMod(modDB, dotCfg, "Duration")
output.BleedDuration = 5 * durationMod * debuffDurationMult
if breakdown then
t_insert(breakdown.BleedDPS, "x 0.1 ^8(bleed deals 10% per second)")
t_insert(breakdown.BleedDPS, s_format("= %.1f", baseVal))
t_insert(breakdown.BleedDPS, "Bleed DPS:")
dotBreakdown(breakdown.BleedDPS, baseVal, inc, more, effMult, output.BleedDPS)
if output.BleedDuration ~= 5 then
breakdown.BleedDuration = {
"5.00s ^8(base duration)"
}
if durationMod ~= 1 then
t_insert(breakdown.BleedDuration, s_format("x %.2f ^8(duration modifier)", durationMod))
end
if debuffDurationMult ~= 1 then
t_insert(breakdown.BleedDuration, s_format("/ %.2f ^8(debuff expires slower/faster)", 1 / debuffDurationMult))
end
t_insert(breakdown.BleedDuration, s_format("= %.2fs", output.BleedDuration))
end
t_insert(breakdown.BleedDuration, s_format("= %.2fs", output.BleedDuration))
end
end
end
-- Calculate poison chance and damage
skillFlags.poison = false
output.PoisonChance = m_min(100, modDB:Sum("BASE", skillCfg, "PoisonChance"))
if canDeal.Chaos and output.PoisonChance > 0 and (output.PhysicalAverage > 0 or output.ChaosAverage > 0) then
skillFlags.poison = true
skillFlags.duration = true
local dotCfg = {
slotName = skillCfg.slotName,
flags = bor(band(skillCfg.flags, ModFlag.SourceMask), ModFlag.Dot, skillData.dotIsSpell and ModFlag.Spell or 0),
keywordFlags = bor(skillCfg.keywordFlags, KeywordFlag.Poison)
}
env.mainSkill.poisonCfg = dotCfg
local poisonCritEffect = 1 - output.CritChance / 100 + output.CritChance / 100 * output.CritMultiplier * modDB:Sum("MORE", skillCfg, "PoisonDamageOnCrit")
local baseVal = (output.PhysicalAverage + output.ChaosAverage) * poisonCritEffect * 0.08
local effMult = 1
if env.mode_effective then
local resist = output["EnemyChaosResist"]
local taken = enemyDB:Sum("INC", nil, "DamageTaken", "ChaosDamageTaken", "DotTaken")
effMult = (1 - resist / 100) * (1 + taken / 100)
output["PoisonEffMult"] = effMult
if breakdown then
breakdown.PoisonEffMult = effMultBreakdown("Chaos", resist, 0, taken, effMult)
end
end
local inc = modDB:Sum("INC", dotCfg, "Damage", "ChaosDamage")
local more = round(modDB:Sum("MORE", dotCfg, "Damage", "ChaosDamage"), 2)
output.PoisonDPS = baseVal * (1 + inc/100) * more * effMult
local durationBase
if skillData.poisonDurationIsSkillDuration then
durationBase = skillData.duration
else
durationBase = 2
end
output.PoisonDuration = durationBase * calcMod(modDB, dotCfg, "Duration") * debuffDurationMult
output.PoisonDamage = output.PoisonDPS * output.PoisonDuration
if breakdown then
breakdown.PoisonDPS = { }
if poisonCritEffect ~= output.CritEffect then
t_insert(breakdown.PoisonDPS, "Crit effect modifier for poison base damage:")
t_insert(breakdown.PoisonDPS, s_format("(1 - %g) ^8(portion of damage from non-crits)", output.CritChance/100))
t_insert(breakdown.PoisonDPS, s_format("+ (%g x %g x %g) ^8(portion of damage from crits)", output.CritChance/100, output.CritMultiplier, modDB:Sum("MORE", skillCfg, "PoisonDamageOnCrit")))
t_insert(breakdown.PoisonDPS, s_format("= %.3f", poisonCritEffect))
end
t_insert(breakdown.PoisonDPS, "Base damage:")
t_insert(breakdown.PoisonDPS, s_format("%.1f ^8(average physical + chaos non-crit damage)", output.PhysicalAverage + output.ChaosAverage))
if output.CritEffect ~= 1 then
t_insert(breakdown.PoisonDPS, s_format("x %.3f ^8(crit effect modifier)", poisonCritEffect))
end
t_insert(breakdown.PoisonDPS, "x 0.08 ^8(poison deals 8% per second)")
t_insert(breakdown.PoisonDPS, s_format("= %.1f", baseVal, 1))
t_insert(breakdown.PoisonDPS, "Poison DPS:")
dotBreakdown(breakdown.PoisonDPS, baseVal, inc, more, effMult, output.PoisonDPS)
if output.PoisonDuration ~= 2 then
breakdown.PoisonDuration = {
s_format("%.2fs ^8(base duration)", durationBase)
}
if output.DurationMod ~= 1 then
t_insert(breakdown.PoisonDuration, s_format("x %.2f ^8(duration modifier)", calcMod(modDB, dotCfg, "Duration")))
end
if debuffDurationMult ~= 1 then
t_insert(breakdown.PoisonDuration, s_format("/ %.2f ^8(debuff expires slower/faster)", 1 / debuffDurationMult))
end
t_insert(breakdown.PoisonDuration, s_format("= %.2fs", output.PoisonDuration))
end
breakdown.PoisonDamage = {
s_format("%.1f ^8(damage per second)", output.PoisonDPS),
s_format("x %.2fs ^8(poison duration)", output.PoisonDuration),
s_format("= %.1f ^8damage per poison stack", output.PoisonDamage),
if canDeal.Chaos and (output.PoisonChanceOnHit + output.PoisonChanceOnCrit) > 0 then
local sourceHitDmg = output.PhysicalHitAverage + output.ChaosHitAverage
local sourceCritDmg = output.PhysicalCritAverage + output.ChaosCritAverage
if sourceHitDmg + sourceCritDmg > 0 then
skillFlags.poison = true
skillFlags.duration = true
local dotCfg = {
slotName = skillCfg.slotName,
flags = bor(band(skillCfg.flags, ModFlag.SourceMask), ModFlag.Dot, skillData.dotIsSpell and ModFlag.Spell or 0),
keywordFlags = bor(skillCfg.keywordFlags, KeywordFlag.Poison)
}
env.mainSkill.poisonCfg = dotCfg
if breakdown then
breakdown.PoisonDPS = { }
end
local baseVal = calcSecondaryEffectBase("Poison", sourceHitDmg, sourceCritDmg * modDB:Sum("MORE", skillCfg, "PoisonDamageOnCrit")) * 0.08
local effMult = 1
if env.mode_effective then
local resist = output["EnemyChaosResist"]
local taken = enemyDB:Sum("INC", nil, "DamageTaken", "ChaosDamageTaken", "DotTaken")
effMult = (1 - resist / 100) * (1 + taken / 100)
output["PoisonEffMult"] = effMult
if breakdown then
breakdown.PoisonEffMult = effMultBreakdown("Chaos", resist, 0, taken, effMult)
end
end
local inc = modDB:Sum("INC", dotCfg, "Damage", "ChaosDamage")
local more = round(modDB:Sum("MORE", dotCfg, "Damage", "ChaosDamage"), 2)
output.PoisonDPS = baseVal * (1 + inc/100) * more * effMult
local durationBase
if skillData.poisonDurationIsSkillDuration then
durationBase = skillData.duration
else
durationBase = 2
end
local durationMod = calcMod(modDB, dotCfg, "Duration")
output.PoisonDuration = durationBase * durationMod * debuffDurationMult
output.PoisonDamage = output.PoisonDPS * output.PoisonDuration
if breakdown then
t_insert(breakdown.PoisonDPS, "x 0.08 ^8(poison deals 8% per second)")
t_insert(breakdown.PoisonDPS, s_format("= %.1f", baseVal, 1))
t_insert(breakdown.PoisonDPS, "Poison DPS:")
dotBreakdown(breakdown.PoisonDPS, baseVal, inc, more, effMult, output.PoisonDPS)
if output.PoisonDuration ~= 2 then
breakdown.PoisonDuration = {
s_format("%.2fs ^8(base duration)", durationBase)
}
if durationMod ~= 1 then
t_insert(breakdown.PoisonDuration, s_format("x %.2f ^8(duration modifier)", durationMod))
end
if debuffDurationMult ~= 1 then
t_insert(breakdown.PoisonDuration, s_format("/ %.2f ^8(debuff expires slower/faster)", 1 / debuffDurationMult))
end
t_insert(breakdown.PoisonDuration, s_format("= %.2fs", output.PoisonDuration))
end
breakdown.PoisonDamage = {
s_format("%.1f ^8(damage per second)", output.PoisonDPS),
s_format("x %.2fs ^8(poison duration)", output.PoisonDuration),
s_format("= %.1f ^8damage per poison stack", output.PoisonDamage),
}
end
end
end
-- Calculate ignite chance and damage
skillFlags.ignite = false
skillFlags.igniteCanStack = false
if modDB:Sum("FLAG", skillCfg, "CannotIgnite") then
output.IgniteChance = 0
else
local igniteMode = env.configInput.igniteMode or "AVERAGE"
output.IgniteChance = m_min(100, modDB:Sum("BASE", skillCfg, "EnemyIgniteChance") + enemyDB:Sum("BASE", nil, "SelfIgniteChance"))
local sourceDmg = 0
if canDeal.Fire and (output.IgniteChanceOnHit + output.IgniteChanceOnCrit) > 0 then
local sourceHitDmg = 0
local sourceCritDmg = 0
if canDeal.Fire and not modDB:Sum("FLAG", skillCfg, "FireCannotIgnite") then
sourceDmg = sourceDmg + output.FireAverage
sourceHitDmg = sourceHitDmg + output.FireHitAverage
sourceCritDmg = sourceCritDmg + output.FireCritAverage
end
if canDeal.Cold and modDB:Sum("FLAG", skillCfg, "ColdCanIgnite") then
sourceDmg = sourceDmg + output.ColdAverage
sourceHitDmg = sourceHitDmg + output.ColdHitAverage
sourceCritDmg = sourceCritDmg + output.ColdCritAverage
end
if canDeal.Fire and (output.IgniteChance > 0 or igniteMode == "CRIT") and sourceDmg > 0 then
if sourceHitDmg + sourceCritDmg > 0 then
skillFlags.ignite = true
local dotCfg = {
slotName = skillCfg.slotName,
@@ -2308,12 +2417,16 @@ local function performCalcs(env)
keywordFlags = skillCfg.keywordFlags,
}
env.mainSkill.igniteCfg = dotCfg
local baseVal
local igniteMode = env.configInput.igniteMode or "AVERAGE"
if igniteMode == "CRIT" then
baseVal = sourceDmg * output.CritMultiplier * 0.2
else
baseVal = sourceDmg * output.CritEffect * 0.2
output.IgniteChanceOnHit = 0
end
if breakdown then
breakdown.IgniteDPS = {
s_format("Ignite mode: %s ^8(can be changed in the Configuration tab)", igniteMode == "CRIT" and "Crit Damage" or "Average Damage")
}
end
local baseVal = calcSecondaryEffectBase("Ignite", sourceHitDmg, sourceCritDmg) * 0.2
local effMult = 1
if env.mode_effective then
local resist = m_min(enemyDB:Sum("BASE", nil, "FireResist", "ElementalResist"), 75)
@@ -2334,20 +2447,6 @@ local function performCalcs(env)
skillFlags.igniteCanStack = true
end
if breakdown then
breakdown.IgniteDPS = {
s_format("Ignite mode: %s ^8(can be changed in the Configuration tab)", igniteMode == "CRIT" and "Crit Damage" or "Average Damage"),
"Base damage:",
s_format("%.1f ^8(average non-crit damage from sources)", sourceDmg),
}
if igniteMode == "CRIT" then
if output.CritMultiplier ~= 1 then
t_insert(breakdown.IgniteDPS, s_format("x %.2f ^8(crit multiplier)", output.CritMultiplier))
end
else
if output.CritEffect ~= 1 then
t_insert(breakdown.IgniteDPS, s_format("x %.3f ^8(crit effect modifier)", output.CritEffect))
end
end
t_insert(breakdown.IgniteDPS, "x 0.2 ^8(ignite deals 20% per second)")
t_insert(breakdown.IgniteDPS, s_format("= %.1f", baseVal, 1))
t_insert(breakdown.IgniteDPS, "Ignite DPS:")
@@ -2377,43 +2476,59 @@ local function performCalcs(env)
-- Calculate shock and freeze chance + duration modifier
skillFlags.shock = false
if modDB:Sum("FLAG", skillCfg, "CannotShock") then
output.ShockChance = 0
else
output.ShockChance = m_min(100, modDB:Sum("BASE", skillCfg, "EnemyShockChance") + enemyDB:Sum("BASE", nil, "SelfShockChance"))
local sourceDmg = 0
if (output.ShockChanceOnHit + output.ShockChanceOnCrit) > 0 then
local sourceHitDmg = 0
local sourceCritDmg = 0
if canDeal.Lightning and not modDB:Sum("FLAG", skillCfg, "LightningCannotShock") then
sourceDmg = sourceDmg + output.LightningAverage
sourceHitDmg = sourceHitDmg + output.LightningHitAverage
sourceCritDmg = sourceCritDmg + output.LightningCritAverage
end
if canDeal.Physical and modDB:Sum("FLAG", skillCfg, "PhysicalCanShock") then
sourceDmg = sourceDmg + output.PhysicalAverage
sourceHitDmg = sourceHitDmg + output.PhysicalHitAverage
sourceCritDmg = sourceCritDmg + output.PhysicalCritAverage
end
if canDeal.Fire and modDB:Sum("FLAG", skillCfg, "FireCanShock") then
sourceDmg = sourceDmg + output.FireAverage
sourceHitDmg = sourceHitDmg + output.FireHitAverage
sourceCritDmg = sourceCritDmg + output.FireCritAverage
end
if canDeal.Chaos and modDB:Sum("FLAG", skillCfg, "ChaosCanShock") then
sourceDmg = sourceDmg + output.ChaosAverage
sourceHitDmg = sourceHitDmg + output.ChaosHitAverage
sourceCritDmg = sourceCritDmg + output.ChaosCritAverage
end
if output.ShockChance > 0 and sourceDmg > 0 then
if sourceHitDmg + sourceCritDmg > 0 then
skillFlags.shock = true
if breakdown then
breakdown.ShockDPS = { }
end
local baseVal = calcSecondaryEffectBase("Shock", sourceHitDmg, sourceCritDmg)
output.ShockDurationMod = 1 + modDB:Sum("INC", dotCfg, "EnemyShockDuration") / 100 + enemyDB:Sum("INC", nil, "SelfShockDuration") / 100
if breakdown then
t_insert(breakdown.ShockDPS, s_format("For shock to apply, target must have no more than %d life.", baseVal * 20 * output.ShockDurationMod))
end
end
end
skillFlags.freeze = false
if modDB:Sum("FLAG", skillCfg, "CannotFreeze") then
output.FreezeChance = 0
else
output.FreezeChance = m_min(100, modDB:Sum("BASE", skillCfg, "EnemyFreezeChance") + enemyDB:Sum("BASE", nil, "SelfFreezeChance"))
local sourceDmg = 0
if (output.FreezeChanceOnHit + output.FreezeChanceOnCrit) > 0 then
local sourceHitDmg = 0
local sourceCritDmg = 0
if canDeal.Cold and not modDB:Sum("FLAG", skillCfg, "ColdCannotFreeze") then
sourceDmg = sourceDmg + output.ColdAverage
sourceHitDmg = sourceHitDmg + output.ColdHitAverage
sourceCritDmg = sourceCritDmg + output.ColdCritAverage
end
if canDeal.Lightning and modDB:Sum("FLAG", skillCfg, "LightningCanFreeze") then
sourceDmg = sourceDmg + output.LightningAverage
sourceHitDmg = sourceHitDmg + output.LightningHitAverage
sourceCritDmg = sourceCritDmg + output.LightningCritAverage
end
if output.FreezeChance > 0 and sourceDmg > 0 then
if sourceHitDmg + sourceCritDmg > 0 then
skillFlags.freeze = true
if breakdown then
breakdown.FreezeDPS = { }
end
local baseVal = calcSecondaryEffectBase("Freeze", sourceHitDmg, sourceCritDmg)
output.FreezeDurationMod = 1 + modDB:Sum("INC", dotCfg, "EnemyFreezeDuration") / 100 + enemyDB:Sum("INC", nil, "SelfFreezeDuration") / 100
if breakdown then
t_insert(breakdown.FreezeDPS, s_format("For freeze to apply, target must have no more than %d life.", baseVal * 20 * output.FreezeDurationMod))
end
end
end

View File

@@ -288,6 +288,7 @@ local modFlagList = {
-- List of modifier flags/tags that appear at the start of a line
local preFlagList = {
["^hits deal "] = { flags = ModFlag.Hit },
["^critical strikes deal "] = { tag = { type = "Condition", var = "CriticalStrike" } },
["^minions have "] = { keywordFlags = KeywordFlag.Minion },
["^minions deal "] = { keywordFlags = KeywordFlag.Minion },
["^attacks used by totems have "] = { keywordFlags = KeywordFlag.Totem },
@@ -476,6 +477,8 @@ local specialModList = {
["(%d+)%% less totem damage per totem"] = function(num) return { mod("Damage", "MORE", -num, nil, 0, KeywordFlag.Totem, { type = "PerStat", stat = "ActiveTotemLimit", div = 1 }) } end,
["poison you inflict with critical strikes deals (%d+)%% more damage"] = function(num) return { mod("PoisonDamageOnCrit", "MORE", 100) } end,
["bleeding you inflict on maimed enemies deals (%d+)%% more damage"] = function(num) return { mod("Damage", "MORE", num, nil, 0, KeywordFlag.Bleed, { type = "Condition", var = "EnemyMaimed"}) } end,
["critical strikes ignore enemy monster elemental resistances"] = { flag("IgnoreElementalResistances", { type = "Condition", var = "CriticalStrike" }) },
["non%-critical strikes penetrate (%d+)%% of enemy elemental resistances"] = function(num) return { mod("ElementalPenetration", "BASE", num, { type = "Condition", var = "CriticalStrike", neg = true }) } end,
-- Special node types
["(%d+)%% of block chance applied to spells"] = function(num) return { mod("BlockChanceConv", "BASE", num) } end,
["(%d+)%% additional block chance with staves"] = function(num) return { mod("BlockChance", "BASE", num, { type = "Condition", var = "UsingStaff" }) } end,
@@ -501,7 +504,7 @@ local specialModList = {
["spells have an additional projectile"] = { mod("ProjectileCount", "BASE", 1, nil, ModFlag.Spell) },
["skills chain %+(%d) times"] = function(num) return { mod("ChainCount", "BASE", num) } end,
["reflects (%d+) physical damage to melee attackers"] = { },
["critical strikes with daggers have a (%d+)%% chance to poison the enemy"] = function(num) return { mod("PoisonChance", "BASE", 0.3, nil, ModFlag.Dagger, { type = "PerStat", stat = "CritChance", div = 1 }) } end,
["critical strikes with daggers have a (%d+)%% chance to poison the enemy"] = function(num) return { mod("PoisonChance", "BASE", num, nil, ModFlag.Dagger, { type = "Condition", var = "CriticalStrike" }) } end,
-- Special item local modifiers
["no physical damage"] = { mod("Misc", "LIST", { type = "WeaponData", key = "PhysicalMin" }), mod("Misc", "LIST", { type = "WeaponData", key = "PhysicalMax" }), mod("Misc", "LIST", { type = "WeaponData", key = "PhysicalDPS" }) },
["all attacks with this weapon are critical strikes"] = { mod("Misc", "LIST", { type = "WeaponData", key = "critChance", value = 100 }) },
@@ -539,11 +542,16 @@ local specialModList = {
["your chaos damage can shock"] = { flag("ChaosCanShock") },
["your physical damage can chill"] = { flag("PhysicalCanChill") },
["your physical damage can shock"] = { flag("PhysicalCanShock") },
["critical strikes do not always freeze"] = { flag("CritsDontAlwaysFreeze") },
["your chaos damage poisons enemies"] = { mod("PoisonChance", "BASE", 100) },
["you can inflict up to (%d+) ignites on an enemy"] = { flag("IgniteCanStack") },
["melee attacks cause bleeding"] = { mod("BleedChance", "BASE", 100, nil, ModFlag.Melee) },
["melee attacks poison on hit"] = { mod("PoisonChance", "BASE", 100, nil, ModFlag.Melee) },
["attacks cause bleeding when hitting cursed enemies"] = { mod("BleedChance", "BASE", 100, { type = "Condition", var = "EnemyCursed" }) },
["melee critical strikes cause bleeding"] = { mod("BleedChance", "BASE", 100, nil, ModFlag.Melee, { type = "Condition", var = "CriticalStrike" }) },
["melee critical strikes have (%d+)%% chance to cause bleeding"] = function(num) return { mod("BleedChance", "BASE", num, nil, ModFlag.Melee, { type = "Condition", var = "CriticalStrike" }) } end,
["melee critical strikes have (%d+)%% chance to poison the enemy"] = function(num) return { mod("PoisonChance", "BASE", num, nil, ModFlag.Melee, { type = "Condition", var = "CriticalStrike" }) } end,
["causes bleeding on melee critical strike"] = { mod("BleedChance", "BASE", num, nil, ModFlag.Melee, { type = "Condition", var = "CriticalStrike" }) },
["traps and mines deal (%d+)%-(%d+) additional physical damage"] = function(_, min, max) return { mod("PhysicalMin", "BASE", tonumber(min), nil, 0, bor(KeywordFlag.Trap, KeywordFlag.Mine)), mod("PhysicalMax", "BASE", tonumber(max), nil, 0, bor(KeywordFlag.Trap, KeywordFlag.Mine)) } end,
["traps and mines deal (%d+) to (%d+) additional physical damage"] = function(_, min, max) return { mod("PhysicalMin", "BASE", tonumber(min), nil, 0, bor(KeywordFlag.Trap, KeywordFlag.Mine)), mod("PhysicalMax", "BASE", tonumber(max), nil, 0, bor(KeywordFlag.Trap, KeywordFlag.Mine)) } end,
["traps and mines have a (%d+)%% chance to poison on hit"] = function(num) return { mod("PoisonChance", "BASE", num, nil, 0, bor(KeywordFlag.Trap, KeywordFlag.Mine)) } end,
@@ -568,11 +576,12 @@ local specialModList = {
["armour is increased by uncapped fire resistance"] = { mod("Armour", "INC", 1, { type = "PerStat", stat = "FireResistTotal", div = 1 }) },
["evasion rating is increased by uncapped cold resistance"] = { mod("Evasion", "INC", 1, { type = "PerStat", stat = "ColdResistTotal", div = 1 }) },
["critical strike chance is increased by uncapped lightning resistance"] = { mod("CritChance", "INC", 1, { type = "PerStat", stat = "LightningResistTotal", div = 1 }) },
["critical strikes deal no damage"] = { flag("NoCritDamage") },
["critical strikes deal no damage"] = { mod("Damage", "MORE", -100, { type = "Condition", var = "CriticalStrike" }) },
["enemies chilled by you take (%d+)%% increased burning damage"] = function(num) return { mod("Misc", "LIST", { type = "EnemyModifier", mod = mod("BurningDamageTaken", "INC", num) }, { type = "Condition", var = "EnemyChilled" }) } end,
["attacks with this weapon penetrate (%d+)%% elemental resistances"] = function(num) return { mod("ElementalPenetration", "BASE", num, { type = "Condition", var = "XHandAttack" }) } end,
["attacks with this weapon deal double damage to chilled enemies"] = { mod("Damage", "MORE", 100, nil, ModFlag.Hit, { type = "Condition", var = "XHandAttack" }, { type = "Condition", var = "EnemyChilled" }) },
["(%d+)%% of maximum life converted to energy shield"] = function(num) return { mod("LifeConvertToEnergyShield", "BASE", num) } end,
["non%-critical strikes deal (%d+)%% damage"] = function(num) return { mod("Damage", "MORE", -100+num, nil, ModFlag.Hit, { type = "Condition", var = "CriticalStrike", neg = true }) } end,
}
local keystoneList = {
-- List of keystones that can be found on uniques

View File

@@ -48,6 +48,25 @@ Head over to the [Releases](https://github.com/Openarl/PathOfBuilding/releases)
![ss3](https://cloud.githubusercontent.com/assets/19189971/18089780/f0ff234a-6f04-11e6-8c88-6193fe59a5c4.png)
## Changelog
### 1.2.35 - 2017/01/29
With this update, the way the program handles the calculation of crit damage has been improved.
Damage for crits and non-crits are now calculated and tallied separately, and combined later, instead of only
calculating non-crit damage, and deriving crit damage from that. This has allowed for the following changes:
* Inevitable Judgement is now supported!
* Other modifiers that only apply to crit or non-crit damage are now supported:
* Choir of the Storm's increased lightning damage modifier
* Marylene's Fallacy's less damage on non-critical strikes
Additionally, the handling of secondary effects (bleed, poison, ignite, shock, and freeze) has been improved.
The calculations for base damage and overall chance to inflict can now handle having different chances to inflict on
crits and non-crits. This has allowed for the following changes:
* Ignite/shock/freeze calculations now account for the guaranteed chance to inflict on critical strike
* This will greatly improve the accuracy of ignite DPS calculations for crit-based builds when in "Average Damage" mode,
as ignite's base damage will be heavily skewed in favour of crit
* Modifiers that grant a chance to poison/bleed on crit are now supported and correctly simulated
* The existing support for Adder's Touch has been reworked to use the new system
* The base damage for shock and freeze is now calculated, and used to compute the maximum enemy life against
which those effects will be able to apply; the results appear in the breakdowns for Shock/Freeze Dur. Mod
### 1.2.34 - 2017/01/27
* IIQ/IIR totals are now shown in the "Other Effects" section in the Calcs tab
* Enabling the "on Consecrated Ground" option now applies the 4% life regen granted by that ground effect

View File

@@ -1,3 +1,21 @@
VERSION[1.2.35][2017/01/29]
With this update, the way the program handles the calculation of crit damage has been improved.
Damage for crits and non-crits are now calculated and tallied separately, and combined later, instead of only
calculating non-crit damage, and deriving crit damage from that. This has allowed for the following changes:
* Inevitable Judgement is now supported!
* Other modifiers that only apply to crit or non-crit damage are now supported:
* Choir of the Storm's increased lightning damage modifier
* Marylene's Fallacy's less damage on non-critical strikes
Additionally, the handling of secondary effects (bleed, poison, ignite, shock, and freeze) has been improved.
The calculations for base damage and overall chance to inflict can now handle having different chances to inflict on
crits and non-crits. This has allowed for the following changes:
* Ignite/shock/freeze calculations now account for the guaranteed chance to inflict on critical strike
* This will greatly improve the accuracy of ignite DPS calculations for crit-based builds when in "Average Damage" mode,
as ignite's base damage will be heavily skewed in favour of crit
* Modifiers that grant a chance to poison/bleed on crit are now supported and correctly simulated
* The existing support for Adder's Touch has been reworked to use the new system
* The base damage for shock and freeze is now calculated, and used to compute the maximum enemy life against
which those effects will be able to apply; the results appear in the breakdowns for Shock/Freeze Dur. Mod
VERSION[1.2.34][2017/01/27]
* IIQ/IIR totals are now shown in the "Other Effects" section in the Calcs tab
* Enabling the "on Consecrated Ground" option now applies the 4% life regen granted by that ground effect

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<PoBVersion>
<Version number="1.2.34"/>
<Version number="1.2.35"/>
<Source part="program" url="https://raw.githubusercontent.com/Openarl/PathOfBuilding/{branch}/"/>
<Source part="tree" url="https://raw.githubusercontent.com/Openarl/PathOfBuilding/{branch}/tree.zip"/>
<Source url="https://raw.githubusercontent.com/Openarl/PathOfBuilding/{branch}/runtime-win32.zip" part="runtime" platform="win32"/>
<File sha1="46a39bc720b0339359fe598ea2828a9a43ecbcea" name="Launch.lua" part="program"/>
<File sha1="d8e42beeb38baabcc197d658e4c0af33419eeff3" name="UpdateCheck.lua" part="program"/>
<File sha1="4f17937f2b37784e169a3792b235f2a0a3961e61" name="UpdateApply.lua" part="program"/>
<File sha1="3809b7eb0bc552ddc81a8f3ecb07e468f2cfc83f" name="changelog.txt" part="program"/>
<File sha1="21c08636c16d13f0c3789eed1721243ab61de6ca" name="changelog.txt" part="program"/>
<File sha1="231a4fe264d84294427edacbf3e29ec4b301712e" name="Classes/BuildListControl.lua" part="program"/>
<File sha1="47c28993f5653955c9e76714775d87ac22b077da" name="Classes/ButtonControl.lua" part="program"/>
<File sha1="5a4b4930533a97f4d87231a6024b7f48ff0bad89" name="Classes/CalcBreakdownControl.lua" part="program"/>
@@ -44,13 +44,13 @@
<File sha1="4b7675c8b4fe71cade7dd3d70793df1ed8022d01" name="Classes/UndoHandler.lua" part="program"/>
<File sha1="b902b15ed69d661ed0eabb4c2a5a5e9fcd4ecc9d" name="Modules/Build.lua" part="program"/>
<File sha1="8a07fe01c53b785ebb6256236e781fbaabd36c0e" name="Modules/BuildList.lua" part="program"/>
<File sha1="c9714615726436cf4c44aa2cd3977cc32fdcb6d4" name="Modules/Calcs.lua" part="program"/>
<File sha1="891eabb423a7d4e14e14db910496e6fd3ab3e806" name="Modules/CalcSections.lua" part="program"/>
<File sha1="071c39f92e62919f53f5e94e551b574a9bdd88e7" name="Modules/Calcs.lua" part="program"/>
<File sha1="f57a5f264d88c9a1a39bc1200731b17ea7f00024" name="Modules/CalcSections.lua" part="program"/>
<File sha1="0f9df7b91a548b008693102854b108693205309c" name="Modules/Common.lua" part="program"/>
<File sha1="2b393e960721c36dc4c99645a507d7232cbd6f0e" name="Modules/Data.lua" part="program"/>
<File sha1="786d2dfd1fde410d5319d55b04878c44c26307cf" name="Modules/ItemTools.lua" part="program"/>
<File sha1="6165a0baf0c7d1cb6adf9bef68bfa9d9d3ad67ec" name="Modules/Main.lua" part="program"/>
<File sha1="6bb01cd18559618ae760e8074a8a4eed6543df6e" name="Modules/ModParser.lua" part="program"/>
<File sha1="cc5643ec578d785125287146cc0e1ace0867d458" name="Modules/ModParser.lua" part="program"/>
<File sha1="5f93a9d8f58e0d5990a1f84e1ab1d53fbd35fb56" name="Modules/ModTools.lua" part="program"/>
<File sha1="e7ee7e5b6388facb7bf568517ecc401590757df7" name="Assets/ring.png" part="program"/>
<File sha1="9a320bfe629b1cf3f14fc77fbbf2508d0a5b2841" name="Assets/small_ring.png" part="program"/>