diff --git a/Classes/PassiveTreeView.lua b/Classes/PassiveTreeView.lua index c32fe495..fb8b270e 100644 --- a/Classes/PassiveTreeView.lua +++ b/Classes/PassiveTreeView.lua @@ -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 diff --git a/Gems/act_str.lua b/Gems/act_str.lua index f283ef7f..879cca1b 100644 --- a/Gems/act_str.lua +++ b/Gems/act_str.lua @@ -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 = { diff --git a/Gems/other.lua b/Gems/other.lua index 7075df5a..26de835b 100644 --- a/Gems/other.lua +++ b/Gems/other.lua @@ -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, diff --git a/Modules/Build.lua b/Modules/Build.lua index c1ef398e..e3131e2a 100644 --- a/Modules/Build.lua +++ b/Modules/Build.lua @@ -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" }, { }, diff --git a/Modules/Calcs.lua b/Modules/Calcs.lua index ee826c2e..43b8b5e4 100644 --- a/Modules/Calcs.lua +++ b/Modules/Calcs.lua @@ -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) + diff --git a/Modules/CalcsControl.lua b/Modules/CalcsControl.lua index 73848e77..49e8e615 100644 --- a/Modules/CalcsControl.lua +++ b/Modules/CalcsControl.lua @@ -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 diff --git a/Modules/CalcsView.lua b/Modules/CalcsView.lua index 60b391cc..ea3affcf 100644 --- a/Modules/CalcsView.lua +++ b/Modules/CalcsView.lua @@ -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" }, diff --git a/Modules/Data.lua b/Modules/Data.lua index fb539500..c86f05b3 100644 --- a/Modules/Data.lua +++ b/Modules/Data.lua @@ -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" }, diff --git a/Modules/Items.lua b/Modules/Items.lua index fcc7d305..a93777be 100644 --- a/Modules/Items.lua +++ b/Modules/Items.lua @@ -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 diff --git a/Modules/Main.lua b/Modules/Main.lua index f9451a62..d002ae43 100644 --- a/Modules/Main.lua +++ b/Modules/Main.lua @@ -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) diff --git a/Modules/ModParser.lua b/Modules/ModParser.lua index 6d4e2ba4..010429da 100644 --- a/Modules/ModParser.lua +++ b/Modules/ModParser.lua @@ -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 }