Various minor improvements
Added more skills Added support for ZO and ES regen
This commit is contained in:
@@ -171,34 +171,36 @@ function TreeViewClass:DrawTree(build, viewPort, inputEvents)
|
||||
local vX = curTreeX - node.x
|
||||
local vY = curTreeY - node.y
|
||||
if vX * vX + vY * vY <= node.rsq then
|
||||
if self.traceMode then
|
||||
if not node.path then
|
||||
break
|
||||
elseif not self.tracePath[1] then
|
||||
for _, pathNode in ipairs(node.path) do
|
||||
t_insert(self.tracePath, 1, pathNode)
|
||||
end
|
||||
else
|
||||
local lastPathNode = self.tracePath[#self.tracePath]
|
||||
if node ~= lastPathNode then
|
||||
if isValueInArray(self.tracePath, node) then
|
||||
break
|
||||
end
|
||||
if not isValueInArray(node.linked, lastPathNode) then
|
||||
break
|
||||
end
|
||||
t_insert(self.tracePath, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
hoverNode = node
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local hoverPath, hoverDep
|
||||
if self.traceMode then
|
||||
if hoverNode then
|
||||
if not hoverNode.path then
|
||||
-- Don't highlight the node if it can't be pathed to
|
||||
hoverNode = nil
|
||||
elseif not self.tracePath[1] then
|
||||
-- Initialise the trace path using this node's path
|
||||
for _, pathNode in ipairs(hoverNode.path) do
|
||||
t_insert(self.tracePath, 1, pathNode)
|
||||
end
|
||||
else
|
||||
local lastPathNode = self.tracePath[#self.tracePath]
|
||||
if hoverNode ~= lastPathNode then
|
||||
-- If node is not in the trace path, but is directly linked to the last node in the path, then add it
|
||||
if not isValueInArray(hoverNode, self.tracePath) and isValueInArray(hoverNode.linked, lastPathNode) then
|
||||
t_insert(self.tracePath, hoverNode)
|
||||
else
|
||||
hoverNode = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
hoverPath = { }
|
||||
for _, pathNode in pairs(self.tracePath) do
|
||||
hoverPath[pathNode] = true
|
||||
@@ -401,7 +403,7 @@ function TreeViewClass:DrawTree(build, viewPort, inputEvents)
|
||||
DrawImage(self.ring, scrX - size, scrY - size, size * 2, size * 2)
|
||||
end
|
||||
elseif node.alloc then
|
||||
local socket, jewel = build.items:GetSocketJewel(nodeId)
|
||||
local socket, jewel = build.items:GetSocketAndJewel(nodeId)
|
||||
if jewel and jewel.radius then
|
||||
local scrX, scrY = treeToScreen(node.x, node.y)
|
||||
local radData = data.jewelRadius[jewel.radius]
|
||||
@@ -452,7 +454,7 @@ end
|
||||
function TreeViewClass:AddNodeTooltip(node, build)
|
||||
-- Special case for sockets
|
||||
if node.type == "socket" and node.alloc then
|
||||
local socket, jewel = build.items:GetSocketJewel(node.id)
|
||||
local socket, jewel = build.items:GetSocketAndJewel(node.id)
|
||||
if jewel then
|
||||
build.items:AddItemTooltip(jewel, build)
|
||||
else
|
||||
|
||||
@@ -585,7 +585,52 @@ gems["Leap Slam"] = {
|
||||
}
|
||||
}
|
||||
gems["Molten Shell"] = {
|
||||
unsupported = true,
|
||||
spell = true,
|
||||
aoe = true,
|
||||
duration = true,
|
||||
fire = true,
|
||||
showAverage = true,
|
||||
base = {
|
||||
skill_castTime = 0.5,
|
||||
skill_damageEff = 2,
|
||||
skill_critChanceBase = 5,
|
||||
skill_durationBase = 10,
|
||||
},
|
||||
quality = {
|
||||
igniteChance = 1,
|
||||
},
|
||||
levels = {
|
||||
[1] = { skill_manaCostBase = 8, skill_fireMin = 14, skill_fireMax = 20, buff_armourBase = 17, },
|
||||
[2] = { skill_manaCostBase = 9, skill_fireMin = 17, skill_fireMax = 26, buff_armourBase = 20, },
|
||||
[3] = { skill_manaCostBase = 9, skill_fireMin = 24, skill_fireMax = 35, buff_armourBase = 26, },
|
||||
[4] = { skill_manaCostBase = 10, skill_fireMin = 32, skill_fireMax = 47, buff_armourBase = 33, },
|
||||
[5] = { skill_manaCostBase = 11, skill_fireMin = 45, skill_fireMax = 68, buff_armourBase = 44, },
|
||||
[6] = { skill_manaCostBase = 12, skill_fireMin = 64, skill_fireMax = 96, buff_armourBase = 58, },
|
||||
[7] = { skill_manaCostBase = 13, skill_fireMin = 88, skill_fireMax = 132, buff_armourBase = 75, },
|
||||
[8] = { skill_manaCostBase = 14, skill_fireMin = 120, skill_fireMax = 180, buff_armourBase = 97, },
|
||||
[9] = { skill_manaCostBase = 16, skill_fireMin = 161, skill_fireMax = 241, buff_armourBase = 123, },
|
||||
[10] = { skill_manaCostBase = 17, skill_fireMin = 214, skill_fireMax = 321, buff_armourBase = 156, },
|
||||
[11] = { skill_manaCostBase = 19, skill_fireMin = 283, skill_fireMax = 425, buff_armourBase = 196, },
|
||||
[12] = { skill_manaCostBase = 20, skill_fireMin = 372, skill_fireMax = 558, buff_armourBase = 245, },
|
||||
[13] = { skill_manaCostBase = 22, skill_fireMin = 486, skill_fireMax = 729, buff_armourBase = 304, },
|
||||
[14] = { skill_manaCostBase = 23, skill_fireMin = 631, skill_fireMax = 947, buff_armourBase = 376, },
|
||||
[15] = { skill_manaCostBase = 25, skill_fireMin = 766, skill_fireMax = 1149, buff_armourBase = 440, },
|
||||
[16] = { skill_manaCostBase = 25, skill_fireMin = 928, skill_fireMax = 1392, buff_armourBase = 515, },
|
||||
[17] = { skill_manaCostBase = 26, skill_fireMin = 1122, skill_fireMax = 1683, buff_armourBase = 600, },
|
||||
[18] = { skill_manaCostBase = 27, skill_fireMin = 1354, skill_fireMax = 2031, buff_armourBase = 698, },
|
||||
[19] = { skill_manaCostBase = 27, skill_fireMin = 1631, skill_fireMax = 2447, buff_armourBase = 812, },
|
||||
[20] = { skill_manaCostBase = 28, skill_fireMin = 1962, skill_fireMax = 2943, buff_armourBase = 943, },
|
||||
[21] = { skill_manaCostBase = 29, skill_fireMin = 2217, skill_fireMax = 3326, buff_armourBase = 1040, },
|
||||
[22] = { skill_manaCostBase = 29, skill_fireMin = 2504, skill_fireMax = 3756, buff_armourBase = 1148, },
|
||||
[23] = { skill_manaCostBase = 29, skill_fireMin = 2827, skill_fireMax = 4240, buff_armourBase = 1265, },
|
||||
[24] = { skill_manaCostBase = 30, skill_fireMin = 3189, skill_fireMax = 4784, buff_armourBase = 1394, },
|
||||
[25] = { skill_manaCostBase = 30, skill_fireMin = 3596, skill_fireMax = 5394, buff_armourBase = 1536, },
|
||||
[26] = { skill_manaCostBase = 31, skill_fireMin = 4053, skill_fireMax = 6080, buff_armourBase = 1691, },
|
||||
[27] = { skill_manaCostBase = 31, skill_fireMin = 4566, skill_fireMax = 6849, buff_armourBase = 1861, },
|
||||
[28] = { skill_manaCostBase = 31, skill_fireMin = 5141, skill_fireMax = 7712, buff_armourBase = 2047, },
|
||||
[29] = { skill_manaCostBase = 32, skill_fireMin = 5787, skill_fireMax = 8680, buff_armourBase = 2251, },
|
||||
[30] = { skill_manaCostBase = 32, skill_fireMin = 6510, skill_fireMax = 9766, buff_armourBase = 2474, },
|
||||
}
|
||||
}
|
||||
gems["Molten Strike"] = {
|
||||
attack = true,
|
||||
@@ -1092,7 +1137,7 @@ gems["Vigilant Strike"] = {
|
||||
melee = true,
|
||||
base = {
|
||||
skill_manaCostBase = 6,
|
||||
skill_noEvade = true,
|
||||
skill_cannotBeEvaded = true,
|
||||
cond_Fortify = true,
|
||||
},
|
||||
quality = {
|
||||
|
||||
@@ -877,7 +877,53 @@ gems["Vaal Lightning Warp"] = {
|
||||
}
|
||||
}
|
||||
gems["Vaal Molten Shell"] = {
|
||||
unsupported = true
|
||||
spell = true,
|
||||
aoe = true,
|
||||
duration = true,
|
||||
fire = true,
|
||||
vaal = true,
|
||||
showAverage = true,
|
||||
base = {
|
||||
skill_castTime = 0.5,
|
||||
skill_damageEff = 2,
|
||||
skill_critChanceBase = 5,
|
||||
skill_durationBase = 10,
|
||||
},
|
||||
quality = {
|
||||
igniteChance = 1,
|
||||
},
|
||||
levels = {
|
||||
[1] = { skill_fireMin = 9, skill_fireMax = 14, buff_armourBase = 17, },
|
||||
[2] = { skill_fireMin = 12, skill_fireMax = 18, buff_armourBase = 20, },
|
||||
[3] = { skill_fireMin = 16, skill_fireMax = 25, buff_armourBase = 26, },
|
||||
[4] = { skill_fireMin = 22, skill_fireMax = 33, buff_armourBase = 33, },
|
||||
[5] = { skill_fireMin = 32, skill_fireMax = 48, buff_armourBase = 44, },
|
||||
[6] = { skill_fireMin = 45, skill_fireMax = 67, buff_armourBase = 58, },
|
||||
[7] = { skill_fireMin = 62, skill_fireMax = 92, buff_armourBase = 75, },
|
||||
[8] = { skill_fireMin = 84, skill_fireMax = 126, buff_armourBase = 97, },
|
||||
[9] = { skill_fireMin = 113, skill_fireMax = 169, buff_armourBase = 123, },
|
||||
[10] = { skill_fireMin = 150, skill_fireMax = 225, buff_armourBase = 156, },
|
||||
[11] = { skill_fireMin = 198, skill_fireMax = 297, buff_armourBase = 196, },
|
||||
[12] = { skill_fireMin = 260, skill_fireMax = 391, buff_armourBase = 245, },
|
||||
[13] = { skill_fireMin = 340, skill_fireMax = 510, buff_armourBase = 304, },
|
||||
[14] = { skill_fireMin = 442, skill_fireMax = 663, buff_armourBase = 376, },
|
||||
[15] = { skill_fireMin = 536, skill_fireMax = 805, buff_armourBase = 440, },
|
||||
[16] = { skill_fireMin = 650, skill_fireMax = 975, buff_armourBase = 515, },
|
||||
[17] = { skill_fireMin = 785, skill_fireMax = 1178, buff_armourBase = 600, },
|
||||
[18] = { skill_fireMin = 948, skill_fireMax = 1422, buff_armourBase = 698, },
|
||||
[19] = { skill_fireMin = 1142, skill_fireMax = 1713, buff_armourBase = 812, },
|
||||
[20] = { skill_fireMin = 1373, skill_fireMax = 2060, buff_armourBase = 943, },
|
||||
[21] = { skill_fireMin = 1552, skill_fireMax = 2328, buff_armourBase = 1040, },
|
||||
[22] = { skill_fireMin = 1753, skill_fireMax = 2629, buff_armourBase = 1148, },
|
||||
[23] = { skill_fireMin = 1979, skill_fireMax = 2968, buff_armourBase = 1265, },
|
||||
[24] = { skill_fireMin = 2232, skill_fireMax = 3349, buff_armourBase = 1394, },
|
||||
[25] = { skill_fireMin = 2517, skill_fireMax = 3776, buff_armourBase = 1536, },
|
||||
[26] = { skill_fireMin = 2837, skill_fireMax = 4256, buff_armourBase = 1691, },
|
||||
[27] = { skill_fireMin = 3196, skill_fireMax = 4794, buff_armourBase = 1861, },
|
||||
[28] = { skill_fireMin = 3599, skill_fireMax = 5398, buff_armourBase = 2047, },
|
||||
[29] = { skill_fireMin = 4051, skill_fireMax = 6076, buff_armourBase = 2251, },
|
||||
[30] = { skill_fireMin = 4557, skill_fireMax = 6836, buff_armourBase = 2474, },
|
||||
}
|
||||
}
|
||||
gems["Vaal Power Siphon"] = {
|
||||
attack = true,
|
||||
|
||||
@@ -109,6 +109,8 @@ function buildMode:Init(dbFileName, buildName)
|
||||
{ mod = "total_critMultiplier", label = "Crit Multiplier", fmt = "d%%", pc = true },
|
||||
{ mod = "total_hitChance", label = "Hit Chance", fmt = "d%%", pc = true },
|
||||
{ mod = "total_dps", label = "Total DPS", fmt = ".1f" },
|
||||
{ mod = "total_dot", label = "DoT DPS", fmt = ".1f" },
|
||||
{ mod = "bleed_dps", label = "Bleed DPS", fmt = ".1f" },
|
||||
{ mod = "ignite_dps", label = "Ignite DPS", fmt = ".1f" },
|
||||
{ mod = "poison_dps", label = "Poison DPS", fmt = ".1f" },
|
||||
{ },
|
||||
|
||||
@@ -149,7 +149,7 @@ function calcs:BuildPower()
|
||||
cache[node.modKey] = calcFunc({node})
|
||||
end
|
||||
local output = cache[node.modKey]
|
||||
local dpsKey = base.mode_average and "total_avg" or "total_dps"
|
||||
local dpsKey = (base.total_dot > 0 and "total_dot") or (base.mode_average and "total_avg") or "total_dps"
|
||||
node.power.dps = (output[dpsKey] - base[dpsKey]) / base[dpsKey]
|
||||
node.power.def = (output.total_life - base.total_life) / m_max(2000, base.total_life) * 0.5 +
|
||||
(output.total_armour - base.total_armour) / m_max(10000, base.total_armour) +
|
||||
|
||||
@@ -82,7 +82,7 @@ local function parseGemSpec(spec, out)
|
||||
end
|
||||
|
||||
-- Combine specified modifiers from all current namespaces
|
||||
function sumMods(modDB, mult, ...)
|
||||
local function sumMods(modDB, mult, ...)
|
||||
local activeWatchers = modDB._activeWatchers
|
||||
local val = mult and 1 or 0
|
||||
for i = 1, select('#', ...) do
|
||||
@@ -106,7 +106,7 @@ function sumMods(modDB, mult, ...)
|
||||
end
|
||||
|
||||
-- Get value of misc modifier
|
||||
function getMiscVal(modDB, spaceName, modName, default)
|
||||
local function getMiscVal(modDB, spaceName, modName, default)
|
||||
local space = modDB[spaceName or "global"]
|
||||
local val = default
|
||||
if space and space[modName] ~= nil then
|
||||
@@ -125,11 +125,17 @@ function getMiscVal(modDB, spaceName, modName, default)
|
||||
end
|
||||
|
||||
-- Calculate value, optionally adding additional base or increased
|
||||
function calcVal(modDB, name, base, inc)
|
||||
local function calcVal(modDB, name, base, inc)
|
||||
local baseVal = sumMods(modDB, false, name.."Base") + (base or 0)
|
||||
return baseVal * (1 + (sumMods(modDB, false, name.."Inc") + (inc or 0)) / 100) * sumMods(modDB, true, name.."More")
|
||||
end
|
||||
|
||||
-- Calculate hit chance
|
||||
local function calcHitChance(evasion, accuracy)
|
||||
local rawChance = accuracy / (accuracy + (evasion / 4) ^ 0.8) * 100
|
||||
return m_max(m_min(m_floor(rawChance + 0.5) / 100, 0.95), 0.05)
|
||||
end
|
||||
|
||||
-- Merge gem modifiers
|
||||
local function mergeGemMods(modList, gem)
|
||||
for k, v in pairs(gem.data.base) do
|
||||
@@ -175,7 +181,7 @@ local function mergeItemMods(env, build, repSlot, repItem)
|
||||
env.radList = wipeTable(env.radList)
|
||||
for nodeId, node in pairs(build.spec.allocNodes) do
|
||||
if node.type == "socket" then
|
||||
local socket, jewel = build.items:GetSocketJewel(nodeId)
|
||||
local socket, jewel = build.items:GetSocketAndJewel(nodeId)
|
||||
if socket.slotName == repSlot then
|
||||
jewel = repItem
|
||||
end
|
||||
@@ -247,7 +253,7 @@ local function buildSpaceTable(modDB, spaceFlags)
|
||||
for spaceName, val in pairs(spaceFlags) do
|
||||
if val then
|
||||
modDB[spaceName] = modDB[spaceName] or { }
|
||||
if next(modDB[spaceName]) then
|
||||
if modDB._activeWatchers or next(modDB[spaceName]) then
|
||||
modDB._spaces[modDB[spaceName]] = spaceName
|
||||
end
|
||||
end
|
||||
@@ -562,6 +568,10 @@ local function initEnv(input, build)
|
||||
-- Merge active skill part mods
|
||||
mod_dbMergeList(modDB, modDB["part"..input.skill_part])
|
||||
end
|
||||
if modDB.buff then
|
||||
-- Merge buff modifers for this skill
|
||||
mod_dbMergeList(modDB, modDB.buff)
|
||||
end
|
||||
|
||||
-- Merge buff skill modifiers (auras are added later)
|
||||
for k, v in pairs(buffSkillModList) do
|
||||
@@ -871,21 +881,12 @@ local function calcPrimary(env, output)
|
||||
local modDB = env.modDB
|
||||
|
||||
-- Calculate defences
|
||||
if startWatch(env, "life") then
|
||||
if startWatch(env, "lifeES") then
|
||||
if getMiscVal(modDB, nil, "chaosInoculation", false) then
|
||||
output.total_life = 1
|
||||
else
|
||||
output.total_life = calcVal(modDB, "life")
|
||||
end
|
||||
output.total_lifeRegen = sumMods(modDB, false, "lifeRegenBase") + sumMods(modDB, false, "lifeRegenPercent") / 100 * output.total_life
|
||||
endWatch(env, "life")
|
||||
end
|
||||
if startWatch(env, "mana") then
|
||||
output.total_mana = calcVal(modDB, "mana")
|
||||
output.total_manaRegen = calcVal(modDB, "manaRegen", output.total_mana * 0.0175)
|
||||
endWatch(env, "mana")
|
||||
end
|
||||
if startWatch(env, "energyShield") then
|
||||
output.total_energyShield = sumMods(modDB, false, "manaBase") * (1 + sumMods(modDB, false, "energyShieldInc", "defencesInc", "manaInc") / 100) * sumMods(modDB, true, "energyShieldMore", "defencesMore", "manaMore") * getMiscVal(modDB, nil, "manaGainAsES", 0) / 100
|
||||
output.total_gear_energyShieldBase = env.itemModList.energyShieldBase or 0
|
||||
for _, slot in pairs({"global","Helmet","Body Armour","Gloves","Boots","Shield"}) do
|
||||
@@ -899,7 +900,24 @@ local function calcPrimary(env, output)
|
||||
end
|
||||
end
|
||||
buildSpaceTable(modDB)
|
||||
endWatch(env, "energyShield")
|
||||
output.total_energyShieldRecharge = calcVal(modDB, "energyShieldRecharge", output.total_energyShield * 0.2)
|
||||
output.total_energyShieldRechargeDelay = 2 / (1 + getMiscVal(modDB, nil, "energyShieldRechargeFaster", 0) / 100)
|
||||
if getMiscVal(modDB, nil, "vaalPact", false) then
|
||||
output.total_lifeRegen = 0
|
||||
elseif getMiscVal(modDB, nil, "zealotsOath", false) then
|
||||
output.total_lifeRegen = 0
|
||||
mod_dbMerge(modDB, "", "energyShieldRegenBase", sumMods(modDB, false, "lifeRegenBase"))
|
||||
mod_dbMerge(modDB, "", "energyShieldRegenPercent", sumMods(modDB, false, "lifeRegenPercent"))
|
||||
else
|
||||
output.total_lifeRegen = sumMods(modDB, false, "lifeRegenBase") + sumMods(modDB, false, "lifeRegenPercent") / 100 * output.total_life
|
||||
end
|
||||
output.total_energyShieldRegen = sumMods(modDB, false, "energyShieldRegenBase") + sumMods(modDB, false, "energyShieldRegenPercent") / 100 * output.total_energyShield
|
||||
endWatch(env, "lifeES")
|
||||
end
|
||||
if startWatch(env, "mana") then
|
||||
output.total_mana = calcVal(modDB, "mana")
|
||||
output.total_manaRegen = calcVal(modDB, "manaRegen", output.total_mana * 0.0175)
|
||||
endWatch(env, "mana")
|
||||
end
|
||||
if startWatch(env, "otherDef") then
|
||||
output.total_evasion = 0
|
||||
@@ -928,6 +946,12 @@ local function calcPrimary(env, output)
|
||||
output.total_gear_armourBase = output.total_gear_armourBase + armourBase
|
||||
end
|
||||
end
|
||||
if getMiscVal(modDB, nil, "cannotEvade", false) then
|
||||
output.total_evadeChance = 0
|
||||
else
|
||||
local attackerLevel = getMiscVal(modDB, "misc", "evadeMonsterLevel", false) and m_min(getMiscVal(modDB, "monster", "level", 1), #data.enemyAccuracyTable) or m_min(getMiscVal(modDB, "player", "level", 1), 80)
|
||||
output.total_evadeChance = 1 - calcHitChance(output.total_evasion, data.enemyAccuracyTable[attackerLevel])
|
||||
end
|
||||
output.total_blockChance = sumMods(modDB, false, "blockChance")
|
||||
output.total_dodgeAttacks = sumMods(modDB, false, "dodgeAttacks")
|
||||
output.total_dodgeSpells = sumMods(modDB, false, "dodgeSpells")
|
||||
@@ -949,13 +973,16 @@ local function calcPrimary(env, output)
|
||||
-- Enable skill namespaces
|
||||
buildSpaceTable(modDB, env.skillSpaceFlags)
|
||||
|
||||
-- Calculate pierce chance
|
||||
if startWatch(env, "pierce") then
|
||||
output.total_pierce = m_min(100, sumMods(modDB, false, "pierceChance")) / 100
|
||||
endWatch(env, "pierce")
|
||||
end
|
||||
if getMiscVal(modDB, nil, "drillneck", false) then
|
||||
mod_dbMerge(modDB, "projectile", "damageInc", output.total_pierce * 100)
|
||||
-- Calculate projectile stats
|
||||
if env.skillFlags.projectile then
|
||||
if startWatch(env, "pierce") then
|
||||
output.total_pierce = m_min(100, sumMods(modDB, false, "pierceChance")) / 100
|
||||
endWatch(env, "pierce")
|
||||
end
|
||||
if getMiscVal(modDB, nil, "drillneck", false) then
|
||||
mod_dbMerge(modDB, "projectile", "damageInc", output.total_pierce * 100)
|
||||
end
|
||||
output.total_projectileSpeedMod = (1 + sumMods(modDB, false, "projectileSpeedInc") / 100) * sumMods(modDB, true, "projectileSpeedMore")
|
||||
end
|
||||
|
||||
-- Run skill setup function
|
||||
@@ -986,8 +1013,8 @@ local function calcPrimary(env, output)
|
||||
output.total_combMin = combMin
|
||||
output.total_combMax = combMax
|
||||
|
||||
-- Calculate crit chance, crit multiplier, and their combined effect
|
||||
if startWatch(env, "dps_crit") then
|
||||
-- Calculate crit chance, crit multiplier, and their combined effect
|
||||
if getMiscVal(modDB, nil, "noCrit", false) then
|
||||
output.total_critChance = 0
|
||||
output.total_critMultiplier = 0
|
||||
@@ -1010,8 +1037,8 @@ local function calcPrimary(env, output)
|
||||
endWatch(env, "dps_crit")
|
||||
end
|
||||
|
||||
-- Calculate skill speed
|
||||
if startWatch(env, "dps_speed") then
|
||||
-- Calculate skill speed
|
||||
if isAttack then
|
||||
local baseSpeed
|
||||
local attackTime = getMiscVal(modDB, "skill", "attackTime", 0)
|
||||
@@ -1030,15 +1057,14 @@ local function calcPrimary(env, output)
|
||||
endWatch(env, "dps_speed")
|
||||
end
|
||||
|
||||
-- Calculate hit chance
|
||||
if startWatch(env, "dps_hitChance") then
|
||||
-- Calculate hit chance
|
||||
if not isAttack or getMiscVal(modDB, "skill", "noEvade", false) or getMiscVal(modDB, nil, "noEvade", false) or getMiscVal(modDB, "weapon1", "noEvade", false) then
|
||||
if not isAttack or getMiscVal(modDB, "skill", "cannotBeEvaded", false) or getMiscVal(modDB, nil, "cannotBeEvaded", false) or getMiscVal(modDB, "weapon1", "cannotBeEvaded", false) then
|
||||
output.total_hitChance = 1
|
||||
else
|
||||
output.total_accuracy = calcVal(modDB, "accuracy")
|
||||
local targetLevel = getMiscVal(modDB, "misc", "hitMonsterLevel", false) and m_min(getMiscVal(modDB, "monster", "level", 1), #data.evasionTable) or m_min(getMiscVal(modDB, "player", "level", 1), 79)
|
||||
local rawChance = output.total_accuracy / (output.total_accuracy + (data.evasionTable[targetLevel] / 4) ^ 0.8) * 100
|
||||
output.total_hitChance = m_max(m_min(m_floor(rawChance + 0.5) / 100, 0.95), 0.05)
|
||||
local targetLevel = getMiscVal(modDB, "misc", "hitMonsterLevel", false) and m_min(getMiscVal(modDB, "monster", "level", 1), #data.enemyEvasionTable) or m_min(getMiscVal(modDB, "player", "level", 1), 79)
|
||||
output.total_hitChance = calcHitChance(data.enemyEvasionTable[targetLevel], output.total_accuracy)
|
||||
end
|
||||
endWatch(env, "dps_hitChance")
|
||||
end
|
||||
@@ -1050,6 +1076,11 @@ local function calcPrimary(env, output)
|
||||
-- Calculate mana cost (may be slightly off due to rounding differences)
|
||||
output.total_manaCost = m_max(0, getMiscVal(modDB, "skill", "manaCostBase", 0) * (1 + sumMods(modDB, false, "manaCostInc") / 100) * sumMods(modDB, true, "manaCostMore") - sumMods(modDB, false, "manaCostBase"))
|
||||
|
||||
-- Calculate AoE stats
|
||||
if env.skillFlags.aoe then
|
||||
output.total_aoeRadiusMod = (1 + sumMods(modDB, false, "aoeRadiusInc") / 100) * sumMods(modDB, true, "aoeRadiusMore")
|
||||
end
|
||||
|
||||
-- Calculate skill duration
|
||||
if startWatch(env, "duration") then
|
||||
local durationBase = getMiscVal(modDB, "skill", "durationBase", 0)
|
||||
@@ -1060,6 +1091,7 @@ local function calcPrimary(env, output)
|
||||
endWatch(env, "duration")
|
||||
end
|
||||
|
||||
-- Calculate trap stats
|
||||
if env.skillFlags.trap then
|
||||
output.total_trapCooldown = 3 / (1 + getMiscVal(modDB, nil, "trapCooldownRecoveryInc", 0) / 100)
|
||||
end
|
||||
@@ -1084,22 +1116,27 @@ local function calcPrimary(env, output)
|
||||
end
|
||||
|
||||
-- Calculate skill DOT components
|
||||
output.total_dot = 0
|
||||
for _, damageType in pairs(dmgTypeList) do
|
||||
local baseVal = getMiscVal(modDB, "skill", damageType.."DotBase", 0)
|
||||
if baseVal > 0 then
|
||||
env.skillFlags.dot = true
|
||||
buildSpaceTable(modDB, {
|
||||
dot = not getMiscVal(modDB, "skill", "dotIsDegen", false),
|
||||
degen = true,
|
||||
spell = getMiscVal(modDB, "skill", "dotIsSpell", false),
|
||||
projectile = env.skillSpaceFlags.projectile,
|
||||
aoe = env.skillSpaceFlags.aoe,
|
||||
totem = env.skillSpaceFlags.totem,
|
||||
trap = env.skillSpaceFlags.trap,
|
||||
mine = env.skillSpaceFlags.mine,
|
||||
})
|
||||
output["total_"..damageType.."Dot"] = baseVal * (1 + sumMods(modDB, false, "damageInc", damageType.."Inc", isElemental[damageType] and "elemInc" or nil) / 100) * sumMods(modDB, true, "damageMore", damageType.."More", isElemental[damageType] and "elemMore" or nil)
|
||||
if startWatch(env, damageType.."Dot") then
|
||||
local baseVal = getMiscVal(modDB, "skill", damageType.."DotBase", 0)
|
||||
if baseVal > 0 then
|
||||
env.skillFlags.dot = true
|
||||
buildSpaceTable(modDB, {
|
||||
dot = not getMiscVal(modDB, "skill", "dotIsDegen", false),
|
||||
degen = true,
|
||||
spell = getMiscVal(modDB, "skill", "dotIsSpell", false),
|
||||
projectile = env.skillSpaceFlags.projectile,
|
||||
aoe = env.skillSpaceFlags.aoe,
|
||||
totem = env.skillSpaceFlags.totem,
|
||||
trap = env.skillSpaceFlags.trap,
|
||||
mine = env.skillSpaceFlags.mine,
|
||||
})
|
||||
output["total_"..damageType.."Dot"] = baseVal * (1 + sumMods(modDB, false, "damageInc", damageType.."Inc", isElemental[damageType] and "elemInc" or nil) / 100) * sumMods(modDB, true, "damageMore", damageType.."More", isElemental[damageType] and "elemMore" or nil)
|
||||
end
|
||||
endWatch(env, damageType.."Dot")
|
||||
end
|
||||
output.total_dot = output.total_dot + (output["total_"..damageType.."Dot"] or 0)
|
||||
end
|
||||
|
||||
-- Calculate bleeding chance and damage
|
||||
|
||||
@@ -202,6 +202,7 @@ columns[3] = {
|
||||
{ "output", "Total:", "total_energyShield", formatRound },
|
||||
{ "output", "Recharge rate:", "total_energyShieldRecharge", getFormatRound(1) },
|
||||
{ "output", "Recharge delay:", "total_energyShieldRechargeDelay", formatSec },
|
||||
{ "output", "Regen:", "total_energyShieldRegen", getFormatRound(1) },
|
||||
{ },
|
||||
{ "Evasion:" },
|
||||
{ "output", "Spec +:", "spec_evasionBase" },
|
||||
@@ -209,6 +210,8 @@ columns[3] = {
|
||||
{ "output", "Gear +:", "total_gear_evasionBase" },
|
||||
{ "output", "Gear %:", "gear_evasionInc" },
|
||||
{ "output", "Total:", "total_evasion", formatRound },
|
||||
{ "input", "Use Monster Level?", "misc_evadeMonsterLevel", "check" },
|
||||
{ "output", "Evade Chance:", "total_evadeChance", formatPercent },
|
||||
{ },
|
||||
{ "Armour:" },
|
||||
{ "output", "Spec +:", "spec_armourBase" },
|
||||
@@ -245,6 +248,7 @@ columns[5] = {
|
||||
{ "output", "Max Endurance:", "enduranceMax" },
|
||||
}, {
|
||||
{ "input", "Onslaught?", "condBuff_Onslaught", "check" },
|
||||
{ "input", "Phasing?", "condBuff_Phasing", "check" },
|
||||
{ "input", "Fortify?", "condBuff_Fortify", "check" },
|
||||
{ "input", "Using a Flask?", "condBuff_UsingFlask", "check" },
|
||||
}, {
|
||||
@@ -426,6 +430,10 @@ columns[7] = {
|
||||
{ "output", "Spec Pierce Chance %:", "spec_pierceChance" },
|
||||
{ "output", "Gear Pierce Chance %:", "gear_pierceChance" },
|
||||
{ "output", "Pierce Chance:", "total_pierce", formatPercent },
|
||||
{ "output", "Projectile Speed Mod:", "total_projectileSpeedMod", formatPercent },
|
||||
}, {
|
||||
flag = "aoe",
|
||||
{ "output", "AoE Radius Mod:", "total_aoeRadiusMod", formatPercent },
|
||||
}, {
|
||||
flag = "duration",
|
||||
{ "output", "Spec Duration %:", "spec_durationInc" },
|
||||
|
||||
@@ -41,7 +41,7 @@ data.jewelRadius = {
|
||||
{ rad = 1500, col = "^x2222CC", label = "Large" }
|
||||
}
|
||||
|
||||
data.evasionTable = { 36, 42, 49, 56, 64, 72, 80, 89, 98, 108,
|
||||
data.enemyEvasionTable = {36, 42, 49, 56, 64, 72, 80, 89, 98, 108,
|
||||
118, 128, 140, 151, 164, 177, 190, 204, 219, 235,
|
||||
251, 268, 286, 305, 325, 345, 367, 389, 412, 437,
|
||||
463, 489, 517, 546, 577, 609, 642, 676, 713, 750,
|
||||
@@ -50,6 +50,15 @@ data.evasionTable = { 36, 42, 49, 56, 64, 72, 80, 89, 98, 10
|
||||
2033, 2125, 2221, 2321, 2425, 2533, 2645, 2761, 2883, 3009,
|
||||
3140, 3276, 3418, 3565, 3717, 3876, 4041, 4213, 4391, 4574,
|
||||
4767, 4969, 5179, 5398 }
|
||||
data.enemyAccuracyTable = { 18, 19, 20, 21, 23, 24, 25, 27, 28, 30,
|
||||
31, 33, 35, 36, 38, 40, 42, 44, 46, 49,
|
||||
51, 54, 56, 59, 62, 65, 68, 71, 74, 78,
|
||||
81, 85, 89, 93, 97, 101, 106, 111, 116, 121,
|
||||
126, 132, 137, 143, 149, 156, 162, 169, 177, 184,
|
||||
192, 200, 208, 217, 226, 236, 245, 255, 266, 277,
|
||||
288, 300, 312, 325, 338, 352, 366, 381, 396, 412,
|
||||
428, 445, 463, 481, 500, 520, 540, 562, 584, 607,
|
||||
632, 657, 683, 711 }
|
||||
|
||||
data.weaponTypeInfo = {
|
||||
["None"] = { oneHand = true, melee = true, space = "unarmed" },
|
||||
|
||||
@@ -169,7 +169,7 @@ function items:UpdateJewels()
|
||||
end
|
||||
end
|
||||
|
||||
function items:GetSocketJewel(nodeId)
|
||||
function items:GetSocketAndJewel(nodeId)
|
||||
return self.sockets[nodeId], self.list[self.sockets[nodeId].selItem]
|
||||
end
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ function main:SaveSettings()
|
||||
end
|
||||
t_insert(setXML, mode)
|
||||
t_insert(setXML, { elem = "BuildPath", attrib = { path = self.buildPath } })
|
||||
t_insert(setXML, { elem = "DevMode", attrib = { enable = launch.devMode and "true" or "false" } })
|
||||
t_insert(setXML, { elem = "DevMode", attrib = { enable = tostring(launch.devMode) } })
|
||||
local res, errMsg = common.xml.SaveXMLFile(setXML, "Settings.xml")
|
||||
if not res then
|
||||
launch:ShowErrMsg("Error saving 'Settings.xml': %s", errMsg)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- Path of Building
|
||||
--
|
||||
-- Module: ModParser
|
||||
-- Module: Mod Parser
|
||||
-- Parser function for modifier names
|
||||
--
|
||||
|
||||
@@ -295,13 +295,15 @@ local specialSpaceList = {
|
||||
-- List of special modifiers
|
||||
local specialModList = {
|
||||
-- Keystones
|
||||
["your hits can't be evaded"] = { noEvade = true },
|
||||
["your hits can't be evaded"] = { cannotBeEvaded = true },
|
||||
["never deal critical strikes"] = { noCrit = true },
|
||||
["no critical strike multiplier"] = { noCritMult = true },
|
||||
["the increase to physical damage from strength applies to projectile attacks as well as melee attacks"] = { ironGrip = true },
|
||||
["converts all evasion rating to armour%. dexterity provides no bonus to evasion rating"] = { ironReflexes = true },
|
||||
["30%% chance to dodge attacks%. 50%% less armour and energy shield, 30%% less chance to block spells and attacks"] = { dodgeAttacks = 30, armourMore = 0.5, energyShieldMore = 0.5 },
|
||||
["maximum life becomes 1, immune to chaos damage"] = { chaosInoculation = true },
|
||||
["life regeneration is applied to energy shield instead"] = { zealotsOath = true },
|
||||
["life leech applies instantly%. life regeneration has no effect%."] = { vaalPact = true },
|
||||
["deal no non%-fire damage"] = { physicalFinalMore = 0, lightningFinalMore = 0, coldFinalMore = 0, chaosFinalMore = 0 },
|
||||
-- Ascendancy notables
|
||||
["movement skills cost no mana"] = { movement_manaCostMore = 0 },
|
||||
@@ -318,21 +320,21 @@ local specialModList = {
|
||||
["(%d+)%% faster start of energy shield recharge"] = function(num) return { energyShieldRechargeFaster = num } end,
|
||||
["(%d+)%% additional block chance while dual wielding or holding a shield"] = function(num) return { condMod_DualWielding_blockChance = num, condMod_UsingShield_blockChance = num } end,
|
||||
-- Other modifiers
|
||||
-- ["adds (%d+)%-(%d+) (%a+) damage ?t?o? ?a?t?t?a?c?k?s?"] = function(_, min, max, type) local pre = "attack_"..type return { [pre.."Min"] = tonumber(min), [pre.."Max"] = tonumber(max) } end,
|
||||
-- ["adds (%d+)%-(%d+) (%a+) damage to attacks with bows"] = function(_, min, max, type) local pre = "bow_"..type return { [pre.."Min"] = tonumber(min), [pre.."Max"] = tonumber(max) } end,
|
||||
-- ["adds (%d+)%-(%d+) (%a+) damage to spells"] = function(_, min, max, type) local pre = "spell_"..type return { [pre.."Min"] = tonumber(min), [pre.."Max"] = tonumber(max) } end,
|
||||
["cannot be shocked"] = { avoidShock = 100 },
|
||||
["cannot be frozen"] = { avoidFreeze = 100 },
|
||||
["cannot be chilled"] = { avoidChill = 100 },
|
||||
["cannot be ignited"] = { avoidIgnite = 100 },
|
||||
["cannot be stunned"] = { stunImmunity = true },
|
||||
["cannot evade enemy attacks"] = { cannotEvade = true },
|
||||
["deal no physical damage"] = { physicalFinalMore = 0 },
|
||||
["your critical strikes do not deal extra damage"] = { noCritMult = true },
|
||||
["iron will"] = { ironWill = true },
|
||||
["zealot's oath"] = { zealotsOath = true },
|
||||
["pain attunement"] = { condMod_LowLife_spell_damageMore = 1.3 },
|
||||
-- Special item local modifiers
|
||||
["no physical damage"] = { weaponNoPhysical = true },
|
||||
["all attacks with this weapon are critical strikes"] = { weaponAlwaysCrit = true },
|
||||
["hits can't be evaded"] = { weaponX_noEvade = true },
|
||||
["hits can't be evaded"] = { weaponX_cannotBeEvaded = true },
|
||||
["no block chance"] = { shieldNoBlock = true },
|
||||
["causes bleeding on hit"] = { bleedChance = 100 },
|
||||
["poisonous hit"] = { poisonChance = 100 },
|
||||
@@ -374,7 +376,7 @@ local regenTypes = {
|
||||
["life"] = "lifeRegen{suf}",
|
||||
["maximum life"] = "lifeRegen{suf}",
|
||||
["mana"] = "manaRegen{suf}",
|
||||
["energyShield"] = "energyShieldRegen{suf}",
|
||||
["energy shield"] = "energyShieldRegen{suf}",
|
||||
}
|
||||
|
||||
-- Build active skill name lookup
|
||||
@@ -449,7 +451,7 @@ local jewelFuncs = {
|
||||
}
|
||||
|
||||
-- Scan a line for the earliest and longest match from the pattern list
|
||||
-- If a match is found, returns the corresponding value from the pattern table, plus the remainder of the line and a table of captures
|
||||
-- If a match is found, returns the corresponding value from the pattern list, plus the remainder of the line and a table of captures
|
||||
local function scan(line, patternList, plain)
|
||||
local bestIndex, bestEndIndex
|
||||
local bestMatch = { nil, line, nil }
|
||||
|
||||
Reference in New Issue
Block a user