From 79c37b11288e41aee51d438521625b024254c64b Mon Sep 17 00:00:00 2001 From: Openarl Date: Tue, 1 Nov 2016 02:22:08 +1000 Subject: [PATCH] Various minor fixes and optimisations --- Classes/CalcBreakdownControl.lua | 6 +- Classes/CalcsTab.lua | 2 +- Classes/ModDB.lua | 237 ++++++++++++++++++++ Classes/ModList.lua | 175 +++++++++++++++ Classes/PassiveTree.lua | 6 +- Classes/SkillListControl.lua | 2 +- Modules/CalcSections.lua | 10 +- Modules/Calcs.lua | 188 ++++++++-------- Modules/Data.lua | 1 + Modules/Main.lua | 2 + Modules/ModParser.lua | 17 +- Modules/ModTools.lua | 365 +------------------------------ PathOfBuilding.sln | 2 + README.md | 3 +- UpdateCheck.lua | 34 ++- changelog.txt | 3 +- manifest.xml | 26 ++- 17 files changed, 572 insertions(+), 507 deletions(-) create mode 100644 Classes/ModDB.lua create mode 100644 Classes/ModList.lua diff --git a/Classes/CalcBreakdownControl.lua b/Classes/CalcBreakdownControl.lua index 119649b1..b9cd9998 100644 --- a/Classes/CalcBreakdownControl.lua +++ b/Classes/CalcBreakdownControl.lua @@ -274,13 +274,13 @@ function CalcBreakdownClass:AddModSection(sectionData) build.itemsTab:AddItemTooltip(item, row.mod.sourceSlot) return data.colorCodes[item.rarity], true end - elseif sourceType == "Node" then - local nodeId = row.mod.source:match("Node:(%d+)") + elseif sourceType == "Tree" then + local nodeId = row.mod.source:match("Tree:(%d+)") if nodeId then local node = build.spec.nodes[tonumber(nodeId)] row.sourceName = node.dn row.sourceNameNode = node - elseif row.mod.source == "Node:Jewel" then + elseif row.mod.source == "Tree:Jewel" then row.sourceName = "Jewel conversion" end elseif sourceType == "Gem" then diff --git a/Classes/CalcsTab.lua b/Classes/CalcsTab.lua index 8ec2932b..dc359ea5 100644 --- a/Classes/CalcsTab.lua +++ b/Classes/CalcsTab.lua @@ -350,7 +350,7 @@ function CalcsTabClass:BuildPower() end local output = cache[node.modKey] node.power.dps = (output.CombinedDPS - calcBase.CombinedDPS) / calcBase.CombinedDPS - node.power.def = (output.LifeUnreserved - calcBase.LifeUnreserved) / m_max(3000, calcBase.Life) * 0.5 + + node.power.def = (output.LifeUnreserved - calcBase.LifeUnreserved) / m_max(3000, calcBase.Life) + (output.Armour - calcBase.Armour) / m_max(10000, calcBase.Armour) + (output.EnergyShield - calcBase.EnergyShield) / m_max(3000, calcBase.EnergyShield) + (output.Evasion - calcBase.Evasion) / m_max(10000, calcBase.Evasion) + diff --git a/Classes/ModDB.lua b/Classes/ModDB.lua new file mode 100644 index 00000000..fc5a397e --- /dev/null +++ b/Classes/ModDB.lua @@ -0,0 +1,237 @@ +-- Path of Building +-- +-- Module: Mod DB +-- Stores modifiers in a database, with modifiers separated by stat +-- +local launch, main = ... + +local pairs = pairs +local t_insert = table.insert +local m_floor = math.floor +local m_abs = math.abs +local band = bit.band +local bor = bit.bor + +local mod_createMod = modLib.createMod + +local hack = { } + +local ModDBClass = common.NewClass("ModDB", function(self) + self.multipliers = { } + self.conditions = { } + self.stats = { } + self.mods = { } +end) + +function ModDBClass:AddMod(mod) + local name = mod.name + if not self.mods[name] then + self.mods[name] = { } + end + t_insert(self.mods[name], mod) +end + +function ModDBClass:AddList(modList) + local mods = self.mods + for i = 1, #modList do + local mod = modList[i] + local name = mod.name + if not mods[name] then + mods[name] = { } + end + t_insert(mods[name], mod) + end +end + +function ModDBClass:AddDB(modDB) + local mods = self.mods + for modName, modList in pairs(modDB.mods) do + if not mods[modName] then + mods[modName] = { } + end + local modsName = mods[modName] + for i = 1, #modList do + t_insert(modsName, modList[i]) + end + end +end + +function ModDBClass:CopyList(modList) + for i = 1, #modList do + self:AddMod(copyTable(modList[i])) + end +end + +function ModDBClass:ScaleAddList(modList, scale) + if scale == 1 then + self:AddList(modList) + else + for i = 1, #modList do + local scaledMod = copyTable(modList[i]) + if type(scaledMod.value) == "number" then + scaledMod.value = (m_floor(scaledMod.value) == scaledMod.value) and m_floor(scaledMod.value * scale) or scaledMod.value * scale + end + self:AddMod(scaledMod) + end + end +end + +function ModDBClass:NewMod(...) + self:AddMod(mod_createMod(...)) +end + +function ModDBClass:Sum(modType, cfg, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + local flags, keywordFlags = 0, 0 + local skillName, skillGem, skillPart, slotName, source, tabulate + if cfg then + flags = cfg.flags or 0 + keywordFlags = cfg.keywordFlags or 0 + skillName = cfg.skillName + skillGem = cfg.skillGem + skillPart = cfg.skillPart + slotName = cfg.slotName + source = cfg.source + tabulate = cfg.tabulate + end + local result + local nullValue = 0 + if tabulate or modType == "LIST" then + result = { } + nullValue = nil + elseif modType == "MORE" then + result = 1 + elseif modType == "FLAG" then + result = false + nullValue = false + else + result = 0 + end + hack[1] = arg1 + if arg1 then + hack[2] = arg2 + if arg2 then + hack[3] = arg3 + if arg3 then + hack[4] = arg4 + if arg4 then + hack[5] = arg5 + if arg5 then + hack[6] = arg6 + if arg6 then + hack[7] = arg7 + if arg7 then + hack[8] = arg8 + end + end + end + end + end + end + end + for i = 1, #hack do --i = 1, select('#', ...) do + local modName = hack[i]--select(i, ...) + local modList = self.mods[modName] + if modList then + for i = 1, #modList do + local mod = modList[i] + if (not modType or mod.type == modType) and (mod.flags == 0 or band(flags, mod.flags) == mod.flags) and (mod.keywordFlags == 0 or band(keywordFlags, mod.keywordFlags) ~= 0) and (not source or mod.source:match("[^:]+") == source) then + local value = mod.value + for _, tag in pairs(mod.tagList) do + if tag.type == "Multiplier" then + local mult = (self.multipliers[tag.var] or 0) + if type(value) == "table" then + value = copyTable(value) + value.value = value.value * mult + else + value = value * mult + end + elseif tag.type == "PerStat" then + local mult = m_floor((self.stats[tag.stat] or 0) / tag.div + 0.0001) + (tag.base or 0) + if type(value) == "table" then + value = copyTable(value) + value.value = value.value * mult + else + value = value * mult + end + elseif tag.type == "Condition" then + if not self.conditions[tag.var] then + value = nullValue + end + elseif tag.type == "SocketedIn" then + if tag.slotName ~= slotName or (tag.keyword and (not skillGem or not gemIsType(skillGem, tag.keyword))) then + value = nullValue + end + elseif tag.type == "SkillName" then + if tag.skillName ~= skillName then + value = nullValue + end + elseif tag.type == "SkillPart" then + if tag.skillPart ~= skillPart then + value = nullValue + end + elseif tag.type == "SlotName" then + if tag.slotName ~= slotName then + value = nullValue + end + end + end + if tabulate then + if value and value ~= 0 then + t_insert(result, { value = value, mod = mod }) + end + elseif modType == "MORE" then + result = result * (1 + value / 100) + elseif modType == "FLAG" then + result = result or value + elseif modType == "LIST" then + if value then + t_insert(result, value) + end + else + result = result + value + end + end + end + end + hack[i] = nil + end + return result +end + +function ModDBClass:Print() + ConPrintf("=== Modifiers ===") + local modNames = { } + for modName in pairs(self.mods) do + t_insert(modNames, modName) + end + table.sort(modNames) + for _, modName in ipairs(modNames) do + ConPrintf("'%s' = {", modName) + for _, mod in ipairs(self.mods[modName]) do + ConPrintf("\t%s = %s|%s|%s|%s|%s", modLib.formatValue(mod.value), mod.type, modLib.formatFlags(mod.flags, ModFlag), modLib.formatFlags(mod.keywordFlags, KeywordFlag), modLib.formatTags(mod.tagList), mod.source or "?") + end + ConPrintf("},") + end + ConPrintf("=== Conditions ===") + local nameList = { } + for name, value in pairs(self.conditions) do + if value then + t_insert(nameList, name) + end + end + table.sort(nameList) + for i, name in ipairs(nameList) do + ConPrintf(name) + end + ConPrintf("=== Multipliers ===") + wipeTable(nameList) + for name, value in pairs(self.multipliers) do + if value > 0 then + t_insert(nameList, name) + end + end + table.sort(nameList) + for i, name in ipairs(nameList) do + ConPrintf("%s = %d", name, self.multipliers[name]) + end +end \ No newline at end of file diff --git a/Classes/ModList.lua b/Classes/ModList.lua new file mode 100644 index 00000000..4d806e41 --- /dev/null +++ b/Classes/ModList.lua @@ -0,0 +1,175 @@ +-- Path of Building +-- +-- Module: Mod List +-- Stores modifiers in a flat list +-- +local launch, main = ... + +local pairs = pairs +local t_insert = table.insert +local m_floor = math.floor +local m_abs = math.abs +local band = bit.band +local bor = bit.bor + +local mod_createMod = modLib.createMod + +local hack = { } + +local ModListClass = common.NewClass("ModList", function(self) + self.multipliers = { } + self.conditions = { } + self.stats = { } +end) + +function ModListClass:AddMod(mod) + t_insert(self, mod) +end + +function ModListClass:AddList(modList) + for i = 1, #modList do + t_insert(self, modList[i]) + end +end + +function ModListClass:CopyList(modList) + for i = 1, #modList do + self:AddMod(copyTable(modList[i])) + end +end + +function ModListClass:ScaleAddList(modList, scale) + for i = 1, #modList do + local scaledMod = copyTable(modList[i]) + if type(scaledMod.value) == "number" then + scaledMod.value = (m_floor(scaledMod.value) == scaledMod.value) and m_floor(scaledMod.value * scale) or scaledMod.value * scale + end + self:AddMod(scaledMod) + end +end + +function ModListClass:NewMod(...) + self:AddMod(mod_createMod(...)) +end + +function ModListClass:Sum(modType, cfg, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + local flags, keywordFlags = 0, 0 + local skillName, skillGem, skillPart, slotName, source, tabulate + if cfg then + flags = cfg.flags or 0 + keywordFlags = cfg.keywordFlags or 0 + skillName = cfg.skillName + skillGem = cfg.skillGem + skillPart = cfg.skillPart + slotName = cfg.slotName + source = cfg.source + tabulate = cfg.tabulate + end + local result + local nullValue = 0 + if tabulate or modType == "LIST" then + result = { } + nullValue = nil + elseif modType == "MORE" then + result = 1 + elseif modType == "FLAG" then + result = false + nullValue = false + else + result = 0 + end + hack[1] = arg1 + if arg1 then + hack[2] = arg2 + if arg2 then + hack[3] = arg3 + if arg3 then + hack[4] = arg4 + if arg4 then + hack[5] = arg5 + if arg5 then + hack[6] = arg6 + if arg6 then + hack[7] = arg7 + if arg7 then + hack[8] = arg8 + end + end + end + end + end + end + end + for i = 1, #hack do --i = 1, select('#', ...) do + local modName = hack[i]--select(i, ...) + for i = 1, #self do + local mod = self[i] + if mod.name == modName and (not modType or mod.type == modType) and band(flags, mod.flags) == mod.flags and (mod.keywordFlags == 0 or band(keywordFlags, mod.keywordFlags) ~= 0) and (not source or mod.source:match("[^:]+") == source) then + local value = mod.value + for _, tag in pairs(mod.tagList) do + if tag.type == "Multiplier" then + local mult = (self.multipliers[tag.var] or 0) + if type(value) == "table" then + value = copyTable(value) + value.value = value.value * mult + else + value = value * mult + end + elseif tag.type == "PerStat" then + local mult = m_floor((self.stats[tag.stat] or 0) / tag.div + 0.0001) + (tag.base or 0) + if type(value) == "table" then + value = copyTable(value) + value.value = value.value * mult + else + value = value * mult + end + elseif tag.type == "Condition" then + if not self.conditions[tag.var] then + value = nullValue + end + elseif tag.type == "SocketedIn" then + if tag.slotName ~= slotName or (tag.keyword and (not skillGem or not gemIsType(skillGem, tag.keyword))) then + value = nullValue + end + elseif tag.type == "SkillName" then + if tag.skillName ~= skillName then + value = nullValue + end + elseif tag.type == "SkillPart" then + if tag.skillPart ~= skillPart then + value = nullValue + end + elseif tag.type == "SlotName" then + if tag.slotName ~= slotName then + value = nullValue + end + end + end + if tabulate then + if value and value ~= 0 then + t_insert(result, { value = value, mod = mod }) + end + elseif modType == "MORE" then + result = result * (1 + value / 100) + elseif modType == "FLAG" then + result = result or value + elseif modType == "LIST" then + if value then + t_insert(result, value) + end + else + result = result + value + end + end + end + hack[i] = nil + end + return result +end + +function ModListClass:Print() + for _, mod in ipairs(self) do + ConPrintf("%s|%s", modLib.formatMod(mod), mod.source or "?") + end +end + diff --git a/Classes/PassiveTree.lua b/Classes/PassiveTree.lua index 8c5a32a7..3fc2cc62 100644 --- a/Classes/PassiveTree.lua +++ b/Classes/PassiveTree.lua @@ -266,7 +266,7 @@ local PassiveTreeClass = common.NewClass("PassiveTree", function(self) for _, mod in pairs(node.mods) do if mod.list and not mod.extra then for i, mod in ipairs(mod.list) do - mod.source = "Node:"..node.id + mod.source = "Tree:"..node.id if type(mod.value) == "table" and mod.value.mod then mod.value.mod.source = mod.source end @@ -275,10 +275,10 @@ local PassiveTreeClass = common.NewClass("PassiveTree", function(self) end end if node.passivePointsGranted > 0 then - node.modList:NewMod("ExtraPoints", "BASE", node.passivePointsGranted, "Node"..node.id) + node.modList:NewMod("ExtraPoints", "BASE", node.passivePointsGranted, "Tree"..node.id) end if node.type == "keystone" then - node.keystoneMod = modLib.createMod("Keystone", "LIST", node.dn, "Node"..node.id) + node.keystoneMod = modLib.createMod("Keystone", "LIST", node.dn, "Tree"..node.id) end end diff --git a/Classes/SkillListControl.lua b/Classes/SkillListControl.lua index 3758c7ce..03a41031 100644 --- a/Classes/SkillListControl.lua +++ b/Classes/SkillListControl.lua @@ -152,7 +152,7 @@ function SkillListClass:Draw(viewPort) main:AddTooltipLine(16, "^7Active Skill #"..index..":") for _, gem in ipairs(activeSkill.gemList) do main:AddTooltipLine(20, string.format("%s%s ^7%d%s/%d%s", - gem.srcGem.color, + data.skillColorMap[gem.data.color], gem.name, gem.level, (gem.srcGem and gem.level > gem.srcGem.level) and data.colorCodes.MAGIC.."+"..(gem.level - gem.srcGem.level).."^7" or "", diff --git a/Modules/CalcSections.lua b/Modules/CalcSections.lua index 42b4bd5b..6b87a071 100644 --- a/Modules/CalcSections.lua +++ b/Modules/CalcSections.lua @@ -227,7 +227,7 @@ return { { 1, "Life", 2, "Life", data.colorCodes.DEFENCE, { extra = "{0:output:LifeUnreserved}/{0:output:Life}", { label = "Base from Gear", { format = "{0:mod:1}", { modName = "Life", modType = "BASE", modSource = "Item" }, }, }, - { label = "Inc. from Tree", { format = "{0:mod:1}%", { modName = "Life", modType = "INC", modSource = "Node" }, }, }, + { label = "Inc. from Tree", { format = "{0:mod:1}%", { modName = "Life", modType = "INC", modSource = "Tree" }, }, }, { label = "Total Base", { format = "{0:mod:1}", { modName = "Life", modType = "BASE" }, }, }, { label = "Total Increased", { format = "{0:mod:1}%", { modName = "Life", modType = "INC", }, }, }, { label = "Total", { format = "{0:output:Life}", { breakdown = "Life" }, }, }, @@ -238,7 +238,7 @@ return { { 1, "Mana", 2, "Mana", data.colorCodes.DEFENCE, { extra = "{0:output:ManaUnreserved}/{0:output:Mana}", { label = "Base from Gear", { format = "{0:mod:1}", { modName = "Mana", modType = "BASE", modSource = "Item" }, }, }, - { label = "Inc. from Tree", { format = "{0:mod:1}%", { modName = "Mana", modType = "INC", modSource = "Node" }, }, }, + { label = "Inc. from Tree", { format = "{0:mod:1}%", { modName = "Mana", modType = "INC", modSource = "Tree" }, }, }, { label = "Total Base", { format = "{0:mod:1}", { modName = "Mana", modType = "BASE" }, }, }, { label = "Total Increased", { format = "{0:mod:1}%", { modName = "Mana", modType = "INC" }, }, }, { label = "Total", { format = "{0:output:Mana}", { breakdown = "Mana" }, }, }, @@ -252,7 +252,7 @@ return { extra = "{0:output:EnergyShield}", { label = "Base from Armours", { format = "{0:output:Gear:EnergyShield}", }, }, { label = "Global Base", { format = "{0:mod:1}", { modName = "EnergyShield", modType = "BASE" }, }, }, - { label = "Inc. from Tree", { format = "{0:mod:1}%", { modName = "EnergyShield", modType = "INC", modSource = "Node" }, }, }, + { label = "Inc. from Tree", { format = "{0:mod:1}%", { modName = "EnergyShield", modType = "INC", modSource = "Tree" }, }, }, { label = "Total Increased", { format = "{0:mod:1}%", { modName = { "EnergyShield", "Defences" }, modType = "INC" }, }, }, { label = "Total More", { format = "{0:mod:1}%", { modName = { "EnergyShield", "Defences" }, modType = "MORE" }, }, }, { label = "Total", { format = "{0:output:EnergyShield}", { breakdown = "EnergyShield" }, }, }, @@ -264,7 +264,7 @@ return { extra = "{0:output:Armour}", { label = "Base from Armours", { format = "{0:output:Gear:Armour}" }, }, { label = "Global Base", { format = "{0:mod:1}", { modName = "Armour", modType = "BASE" }, }, }, - { label = "Inc. from Tree", { format = "{0:mod:1}%", { modName = { "Armour", "ArmourAndEvasion" }, modType = "INC", modSource = "Node", }, }, }, + { label = "Inc. from Tree", { format = "{0:mod:1}%", { modName = { "Armour", "ArmourAndEvasion" }, modType = "INC", modSource = "Tree", }, }, }, { label = "Total Increased", { format = "{0:mod:1}%", { modName = { "Armour", "ArmourAndEvasion", "Defences" }, modType = "INC" }, }, }, { label = "Total More", { format = "{0:mod:1}%", { modName = { "Armour", "ArmourAndEvasion", "Defences" }, modType = "MORE" }, }, }, { label = "Total", { format = "{0:output:Armour}", { breakdown = "Armour" }, }, }, @@ -273,7 +273,7 @@ return { extra = "{0:output:Evasion}", { label = "Base from Armours", { format = "{0:output:Gear:Evasion}", }, }, { label = "Global Base", { format = "{0:mod:1}", { modName = "Evasion", modType = "BASE" }, }, }, - { label = "Inc. from Tree", { format = "{0:mod:1}%", { modName = { "Evasion", "ArmourAndEvasion" }, modType = "INC", modSource = "Node" }, }, }, + { label = "Inc. from Tree", { format = "{0:mod:1}%", { modName = { "Evasion", "ArmourAndEvasion" }, modType = "INC", modSource = "Tree" }, }, }, { label = "Total Increased", { format = "{0:mod:1}%", { modName = { "Evasion", "ArmourAndEvasion", "Defences" }, modType = "INC" }, }, }, { label = "Total More", { format = "{0:mod:1}%", { modName = { "Evasion", "ArmourAndEvasion", "Defences" }, modType = "MORE" }, }, }, { label = "Total", { format = "{0:output:Evasion}", { breakdown = "Evasion" }, }, }, diff --git a/Modules/Calcs.lua b/Modules/Calcs.lua index cda04de7..1312aee8 100644 --- a/Modules/Calcs.lua +++ b/Modules/Calcs.lua @@ -3,6 +3,7 @@ -- Module: Calcs -- Performs all the offense and defense calculations. -- Here be dragons! +-- This file is 2500 lines long, over half of which is in one function... -- local pairs = pairs @@ -419,7 +420,7 @@ local function buildNodeModList(env, nodeList, finishJewels) end -- Calculate min/max damage of a hit for the given damage type -local function calcHitDamage(env, damageType, ...) +local function calcHitDamage(env, source, damageType, ...) local modDB = env.modDB local skillCfg = env.mainSkill.skillCfg @@ -427,7 +428,6 @@ local function calcHitDamage(env, damageType, ...) local damageTypeMax = damageType.."Max" -- Calculate base values - local source = (env.mode_skillType == "ATTACK") and env.weaponData1 or env.mainSkill.skillData local damageEffectiveness = source.damageEffectiveness or 1 local addedMin = modDB:Sum("BASE", skillCfg, damageTypeMin) local addedMax = modDB:Sum("BASE", skillCfg, damageTypeMax) @@ -462,7 +462,7 @@ local function calcHitDamage(env, damageType, ...) local convMult = conversionTable[otherType][damageType] if convMult > 0 then -- Damage is being converted/gained from the other damage type - local min, max = calcHitDamage(env, otherType, damageType, ...) + local min, max = calcHitDamage(env, source, otherType, damageType, ...) addMin = addMin + min * convMult addMax = addMax + max * convMult end @@ -814,7 +814,14 @@ local function mergeMainMods(env, repSlotName, repItem) -- Add extra supports from the item this group is socketed in local gemData = data.gems[value.name] if gemData then - t_insert(supportList, { name = value.name, data = gemData, level = value.level, quality = 0, enabled = true, fromItem = true }) + t_insert(supportList, { + name = value.name, + data = gemData, + level = value.level, + quality = 0, + enabled = true, + fromItem = true + }) end end for _, gem in ipairs(socketGroup.gemList) do @@ -907,6 +914,7 @@ local function mergeMainMods(env, repSlotName, repItem) end -- Finalise environment and perform the calculations +-- This function is 1400 lines long. Enjoy! local function performCalcs(env) local modDB = env.modDB local enemyDB = env.enemyDB @@ -1442,7 +1450,6 @@ local function performCalcs(env) total = modDB:Sum("BASE", nil, elem.."Resist", isElemental[elem] and "ElementalResist") end output[elem.."ResistMax"] = max - output[elem.."ResistTotal"] = total output[elem.."Resist"] = m_min(total, max) output[elem.."ResistOverCap"] = m_max(0, total - max) if breakdown then @@ -1722,89 +1729,92 @@ local function performCalcs(env) -- Calculate hit damage for each damage type local totalMin, totalMax = 0, 0 - for _, damageType in ipairs(dmgTypeList) do - local min, max - if canDeal[damageType] then - if breakdown then - breakdown[damageType] = { - damageComponents = { } - } - end - min, max = calcHitDamage(env, damageType) - local convMult = env.conversionTable[damageType].mult - if breakdown then - t_insert(breakdown[damageType], "Hit damage:") - t_insert(breakdown[damageType], "^7"..min.." to "..max.." ^8(total damage)") - if convMult ~= 1 then - t_insert(breakdown[damageType], "^7x "..convMult.." ^8("..((1-convMult)*100).."% converted to other damage types)") + do + local hitSource = (env.mode_skillType == "ATTACK") and env.weaponData1 or env.mainSkill.skillData + for _, damageType in ipairs(dmgTypeList) do + local min, max + if canDeal[damageType] then + if breakdown then + breakdown[damageType] = { + damageComponents = { } + } end - end - min = min * convMult - max = max * convMult - if env.mode_effective then - -- Apply enemy resistances and damage taken modifiers - local preMult - local taken = enemyDB:Sum("INC", nil, "DamageTaken", damageType.."DamageTaken") - local resist = 0 - local pen = 0 - if isElemental[damageType] then - resist = output["Enemy"..damageType.."Resist"] - pen = modDB:Sum("BASE", skillCfg, damageType.."Penetration", "ElementalPenetration") - taken = taken + enemyDB:Sum("INC", nil, "ElementalDamageTaken") - elseif damageType == "Chaos" then - resist = output.EnemyChaosResist - else - resist = enemyDB:Sum("INC", nil, "PhysicalDamageReduction") - end - if skillFlags.projectile then - taken = taken + enemyDB:Sum("INC", nil, "ProjectileDamageTaken") - end - local mult = (1 - (resist - pen) / 100) * (1 + taken / 100) - min = min * mult - max = max * mult - if env.mode == "GRID" then - output[damageType.."EffMult"] = mult - end - if breakdown and mult ~= 1 then - t_insert(breakdown[damageType], s_format("x %.3f ^8(effective DPS modifier)", mult)) - local out = { } - local resistForm = (damageType == "Physical") and "physical damage reduction" or "resistance" - if resist ~= 0 then - t_insert(out, "Enemy "..resistForm..": "..resist.."%") + min, max = calcHitDamage(env, hitSource, damageType) + local convMult = env.conversionTable[damageType].mult + if breakdown then + t_insert(breakdown[damageType], "Hit damage:") + t_insert(breakdown[damageType], "^7"..min.." to "..max.." ^8(total damage)") + if convMult ~= 1 then + t_insert(breakdown[damageType], "^7x "..convMult.." ^8("..((1-convMult)*100).."% converted to other damage types)") end - if pen ~= 0 then - t_insert(out, "Effective resistance:") - t_insert(out, ""..resist.."% ^8(resistance)") - t_insert(out, "- "..pen.."% ^8(penetration)") - t_insert(out, "= "..(resist-pen).."%") + end + min = min * convMult + max = max * convMult + if env.mode_effective then + -- Apply enemy resistances and damage taken modifiers + local preMult + local taken = enemyDB:Sum("INC", nil, "DamageTaken", damageType.."DamageTaken") + local resist = 0 + local pen = 0 + if isElemental[damageType] then + resist = output["Enemy"..damageType.."Resist"] + pen = modDB:Sum("BASE", skillCfg, damageType.."Penetration", "ElementalPenetration") + taken = taken + enemyDB:Sum("INC", nil, "ElementalDamageTaken") + elseif damageType == "Chaos" then + resist = output.EnemyChaosResist + else + resist = enemyDB:Sum("INC", nil, "PhysicalDamageReduction") end - if (resist - pen) ~= 0 and taken ~= 0 then - t_insert(out, "Effective DPS modifier:") - t_insert(out, (1 - (resist - pen) / 100).." ^8("..resistForm..")") - t_insert(out, "x "..(1 + taken / 100).." ^8(increased/reduced damage taken)") - t_insert(out, s_format("= %.3f", mult)) + if skillFlags.projectile then + taken = taken + enemyDB:Sum("INC", nil, "ProjectileDamageTaken") end - breakdown[damageType.."EffMult"] = out + local mult = (1 - (resist - pen) / 100) * (1 + taken / 100) + min = min * mult + max = max * mult + if env.mode == "GRID" then + output[damageType.."EffMult"] = mult + end + if breakdown and mult ~= 1 then + t_insert(breakdown[damageType], s_format("x %.3f ^8(effective DPS modifier)", mult)) + local out = { } + local resistForm = (damageType == "Physical") and "physical damage reduction" or "resistance" + if resist ~= 0 then + t_insert(out, "Enemy "..resistForm..": "..resist.."%") + end + if pen ~= 0 then + t_insert(out, "Effective resistance:") + t_insert(out, ""..resist.."% ^8(resistance)") + t_insert(out, "- "..pen.."% ^8(penetration)") + t_insert(out, "= "..(resist-pen).."%") + end + if (resist - pen) ~= 0 and taken ~= 0 then + t_insert(out, "Effective DPS modifier:") + t_insert(out, (1 - (resist - pen) / 100).." ^8("..resistForm..")") + t_insert(out, "x "..(1 + taken / 100).." ^8(increased/reduced damage taken)") + t_insert(out, s_format("= %.3f", mult)) + end + breakdown[damageType.."EffMult"] = out + end + end + if breakdown then + t_insert(breakdown[damageType], "^7= "..round(min).." to "..round(max)) + end + else + min, max = 0, 0 + if breakdown then + breakdown[damageType] = { + "You can't deal "..damageType.." damage" + } end end - if breakdown then - t_insert(breakdown[damageType], "^7= "..round(min).." to "..round(max)) - end - else - min, max = 0, 0 - if breakdown then - breakdown[damageType] = { - "You can't deal "..damageType.." damage" - } + if env.mode == "GRID" then + output[damageType.."Min"] = min + output[damageType.."Max"] = max end + output[damageType.."Average"] = (min + max) / 2 + totalMin = totalMin + min + totalMax = totalMax + max end - if env.mode == "GRID" then - output[damageType.."Min"] = min - output[damageType.."Max"] = max - end - output[damageType.."Average"] = (min + max) / 2 - totalMin = totalMin + min - totalMax = totalMax + max end output.TotalMin = totalMin output.TotalMax = totalMax @@ -2353,15 +2363,11 @@ local function getCalculator(build, fullInit, modFunc) mergeMainMods(env) end local initModDB = common.New("ModDB") - for modName, modList in pairs(env.modDB.mods) do - initModDB:AddList(modList) - end + initModDB:AddDB(env.modDB) initModDB.multipliers = copyTable(env.modDB.multipliers) initModDB.conditions = copyTable(env.modDB.conditions) local initEnemyDB = common.New("ModDB") - for modName, modList in pairs(env.enemyDB.mods) do - initEnemyDB:AddList(modList) - end + initEnemyDB:AddDB(env.enemyDB) if not fullInit then mergeMainMods(env) end @@ -2373,15 +2379,11 @@ local function getCalculator(build, fullInit, modFunc) return function(...) -- Restore initial mod database env.modDB.mods = wipeTable(env.modDB.mods) - for modName, modList in pairs(initModDB.mods) do - env.modDB:AddList(modList) - end + env.modDB:AddDB(initModDB) env.modDB.conditions = copyTable(initModDB.conditions) env.modDB.multipliers = copyTable(initModDB.multipliers) env.enemyDB.mods = wipeTable(env.enemyDB.mods) - for modName, modList in pairs(initEnemyDB.mods) do - env.enemyDB:AddList(modList) - end + env.enemyDB:AddDB(initEnemyDB) -- Call function to make modifications to the enviroment modFunc(env, ...) @@ -2440,7 +2442,7 @@ function calcs.buildOutput(build, mode) output.ExtraPoints = env.modDB:Sum("BASE", nil, "ExtraPoints") local specCfg = { - source = "Node" + source = "Tree" } for _, stat in pairs({"Life", "Mana", "Armour", "Evasion", "EnergyShield"}) do output["Spec:"..stat.."Inc"] = env.modDB:Sum("INC", specCfg, stat) diff --git a/Modules/Data.lua b/Modules/Data.lua index e3b25d67..fc062676 100644 --- a/Modules/Data.lua +++ b/Modules/Data.lua @@ -185,6 +185,7 @@ data.colorCodes = { data.colorCodes.STRENGTH = data.colorCodes.MARAUDER data.colorCodes.DEXTERITY = data.colorCodes.RANGER data.colorCodes.INTELLIGENCE = data.colorCodes.WITCH +data.skillColorMap = { data.colorCodes.STRENGTH, data.colorCodes.DEXTERITY, data.colorCodes.INTELLIGENCE, data.colorCodes.NORMAL } data.jewelRadius = { { rad = 800, col = "^xBB6600", label = "Small" }, diff --git a/Modules/Main.lua b/Modules/Main.lua index a5ccb44f..eb59c581 100644 --- a/Modules/Main.lua +++ b/Modules/Main.lua @@ -39,6 +39,8 @@ local classList = { -- Mode: Build list "BuildListControl", -- Mode: Build + "ModList", + "ModDB", "ImportTab", "ConfigTab", "TreeTab", diff --git a/Modules/ModParser.lua b/Modules/ModParser.lua index 7379b1a5..3d844ebc 100644 --- a/Modules/ModParser.lua +++ b/Modules/ModParser.lua @@ -490,7 +490,6 @@ local specialModList = { ["you have no life regeneration"] = { flag("NoLifeRegen") }, ["cannot block attacks"] = { flag("CannotBlockAttacks") }, ["projectiles pierce while phasing"] = { mod("PierceChance", "BASE", 100, { type = "Condition", var = "Phasing" }) }, - ["reserves (%d+)%% of life"] = function(num) return { } end,--FIXME { reserved_lifePercent = num } end, } local keystoneList = { -- List of keystones that can be found on uniques @@ -556,8 +555,8 @@ local function getSimpleConv(src, dst, type, factor) if nodeMods then local nodeVal = nodeMods:Sum(type, nil, src) if nodeVal ~= 0 then - out:NewMod(src, type, -nodeVal, "Node:Jewel") - out:NewMod(dst, type, nodeVal * factor, "Node:Jewel") + out:NewMod(src, type, -nodeVal, "Tree:Jewel") + out:NewMod(dst, type, nodeVal * factor, "Tree:Jewel") end end end @@ -568,8 +567,8 @@ local function getMatchConv(others, dst, type) for _, mod in ipairs(nodeMods) do for _, other in pairs(others) do if mod.name:match(other) then - out:NewMod(mod.name, type, -mod.value, "Node:Jewel") - out:NewMod(mod.name:gsub(other, dst), type, mod.value, "Node:Jewel") + out:NewMod(mod.name, type, -mod.value, "Tree:Jewel") + out:NewMod(mod.name:gsub(other, dst), type, mod.value, "Tree:Jewel") end end end @@ -581,7 +580,7 @@ local function getPerStat(dst, type, flags, stat, factor) if nodeMods then data[stat] = (data[stat] or 0) + nodeMods:Sum("BASE", nil, stat) else - out:NewMod(dst, type, math.floor(data[stat] * factor + 0.5), "Node:Jewel", flags) + out:NewMod(dst, type, math.floor(data[stat] * factor + 0.5), "Tree:Jewel", flags) end end end @@ -606,8 +605,8 @@ local jewelFuncs = { local mask3 = bor(ModFlag.Weapon2H, ModFlag.WeaponMelee) for _, mod in ipairs(nodeMods) do if band(mod.flags, mask1) ~= 0 or band(mod.flags, mask2) == mask2 or band(mod.flags, mask3) == mask3 then - out:NewMod(mod.name, mod.type, -mod.value, "Node:Jewel", mod.flags, mod.keywordFlags, unpack(mod.tag)) - out:NewMod(mod.name, mod.type, mod.value, "Node:Jewel", bor(band(mod.flags, bnot(bor(mask1, mask2, mask3))), ModFlag.Bow), mod.keywordFlags, unpack(mod.tag)) + out:NewMod(mod.name, mod.type, -mod.value, "Tree:Jewel", mod.flags, mod.keywordFlags, unpack(mod.tag)) + out:NewMod(mod.name, mod.type, mod.value, "Tree:Jewel", bor(band(mod.flags, bnot(bor(mask1, mask2, mask3))), ModFlag.Bow), mod.keywordFlags, unpack(mod.tag)) end end end @@ -626,7 +625,7 @@ local jewelFuncs = { data.Dex = (data.Dex or 0) + nodeMods:Sum("BASE", 0, "Dex") data.Int = (data.Int or 0) + nodeMods:Sum("BASE", 0, "Int") else - out:NewMod("DexIntToMeleeBonus", "BASE", data.Dex + data.Int, "Node:Jewel") + out:NewMod("DexIntToMeleeBonus", "BASE", data.Dex + data.Int, "Tree:Jewel") end end, } diff --git a/Modules/ModTools.lua b/Modules/ModTools.lua index f0a2324f..79690ff6 100644 --- a/Modules/ModTools.lua +++ b/Modules/ModTools.lua @@ -1,9 +1,10 @@ -- Path of Building -- -- Module: Mod Tools --- Various functions for dealing with modifier lists and databases. +-- Various functions for dealing with modifiers -- +local pairs = pairs local t_insert = table.insert local m_floor = math.floor local m_abs = math.abs @@ -12,7 +13,7 @@ local bor = bit.bor modLib = { } -local function createMod(modName, modType, modVal, ...) +function modLib.createMod(modName, modType, modVal, ...) local flags = 0 local keywordFlags = 0 local tagStart = 1 @@ -39,11 +40,10 @@ local function createMod(modName, modType, modVal, ...) tagList = { select(tagStart, ...) } } end -modLib.createMod = createMod modLib.parseMod = LoadModule("Modules/ModParser") -local function formatFlags(flags, src) +function modLib.formatFlags(flags, src) local flagNames = { } for name, val in pairs(src) do if band(flags, val) == val then @@ -57,9 +57,8 @@ local function formatFlags(flags, src) end return ret or "-" end -modLib.formatFlags = formatFlags -local function formatTags(tagList) +function modLib.formatTags(tagList) local ret for _, tag in ipairs(tagList) do local paramNames = { } @@ -87,7 +86,7 @@ local function formatTags(tagList) return ret or "-" end -local function formatValue(value) +function modLib.formatValue(value) if type(value) ~= "table" then return tostring(value) end @@ -115,355 +114,5 @@ local function formatValue(value) end function modLib.formatMod(mod) - return string.format("%s = %s|%s|%s|%s|%s", formatValue(mod.value), mod.name, mod.type, formatFlags(mod.flags, ModFlag), formatFlags(mod.keywordFlags, KeywordFlag), formatTags(mod.tagList)) + return string.format("%s = %s|%s|%s|%s|%s", modLib.formatValue(mod.value), mod.name, mod.type, modLib.formatFlags(mod.flags, ModFlag), modLib.formatFlags(mod.keywordFlags, KeywordFlag), modLib.formatTags(mod.tagList)) end - -local hack = { } - -local ModListClass = common.NewClass("ModList", function(self) - self.multipliers = { } - self.conditions = { } - self.stats = { } -end) - -function ModListClass:AddMod(mod) - t_insert(self, mod) -end - -function ModListClass:AddList(modList) - for i = 1, #modList do - t_insert(self, modList[i]) - end -end - -function ModListClass:CopyList(modList) - for i = 1, #modList do - self:AddMod(copyTable(modList[i])) - end -end - -function ModListClass:ScaleAddList(modList, scale) - for i = 1, #modList do - local scaledMod = copyTable(modList[i]) - if type(scaledMod.value) == "number" then - scaledMod.value = (m_floor(scaledMod.value) == scaledMod.value) and m_floor(scaledMod.value * scale) or scaledMod.value * scale - end - self:AddMod(scaledMod) - end -end - -function ModListClass:NewMod(...) - self:AddMod(createMod(...)) -end - -function ModListClass:Sum(type, cfg, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) - local flags = cfg and cfg.flags or 0 - local keywordFlags = cfg and cfg.keywordFlags or 0 - local skillName = cfg and cfg.skillName - local skillGem = cfg and cfg.skillGem - local skillPart = cfg and cfg.skillPart - local slotName = cfg and cfg.slotName - local source = cfg and cfg.source - local tabulate = cfg and cfg.tabulate - local result - local nullValue = 0 - if tabulate or type == "LIST" then - result = { } - nullValue = nil - elseif type == "MORE" then - result = 1 - elseif type == "FLAG" then - result = false - nullValue = false - else - result = 0 - end - hack[1] = arg1 - if arg1 then - hack[2] = arg2 - if arg2 then - hack[3] = arg3 - if arg3 then - hack[4] = arg4 - if arg4 then - hack[5] = arg5 - if arg5 then - hack[6] = arg6 - if arg6 then - hack[7] = arg7 - if arg7 then - hack[8] = arg8 - end - end - end - end - end - end - end - for i = 1, #hack do --i = 1, select('#', ...) do - local modName = hack[i]--select(i, ...) - for i = 1, #self do - local mod = self[i] - if mod.name == modName and mod.type == type and band(flags, mod.flags) == mod.flags and (mod.keywordFlags == 0 or band(keywordFlags, mod.keywordFlags) ~= 0) and (not source or mod.source:match(source)) then - local value = mod.value - for _, tag in pairs(mod.tagList) do - if tag.type == "Multiplier" then - local mult = (self.multipliers[tag.var] or 0) - if _G.type(value) == "table" then - value = copyTable(value) - value.value = value.value * mult - else - value = value * mult - end - elseif tag.type == "PerStat" then - local mult = m_floor((self.stats[tag.stat] or 0) / tag.div + 0.0001) + (tag.base or 0) - if _G.type(value) == "table" then - value = copyTable(value) - value.value = value.value * mult - else - value = value * mult - end - elseif tag.type == "Condition" then - if not self.conditions[tag.var] then - value = nullValue - end - elseif tag.type == "SocketedIn" then - if tag.slotName ~= slotName or (tag.keyword and (not skillGem or not gemIsType(skillGem, tag.keyword))) then - value = nullValue - end - elseif tag.type == "SkillName" then - if tag.skillName ~= skillName then - value = nullValue - end - elseif tag.type == "SkillPart" then - if tag.skillPart ~= skillPart then - value = nullValue - end - elseif tag.type == "SlotName" then - if tag.slotName ~= slotName then - value = nullValue - end - end - end - if tabulate or type == "LIST" then - if value then - t_insert(result, value) - end - elseif type == "MORE" then - result = result * (1 + value / 100) - elseif type == "FLAG" then - result = result or value - else - result = result + value - end - end - end - hack[i] = nil - end - return result -end - -function ModListClass:Print() - for _, mod in ipairs(self) do - ConPrintf("%s|%s", modLib.formatMod(mod), mod.source or "?") - end -end - -local ModDBClass = common.NewClass("ModDB", function(self) - self.mods = { } - self.multipliers = { } - self.conditions = { } - self.stats = { } -end) - -function ModDBClass:AddMod(mod) - local name = mod.name - if not self.mods[name] then - self.mods[name] = { } - end - t_insert(self.mods[name], mod) -end - -function ModDBClass:AddList(modList) - local mods = self.mods - for i = 1, #modList do - local mod = modList[i] - local name = mod.name - if not mods[name] then - mods[name] = { } - end - t_insert(mods[name], mod) - end -end - -function ModDBClass:CopyList(modList) - for i = 1, #modList do - self:AddMod(copyTable(modList[i])) - end -end - -function ModDBClass:ScaleAddList(modList, scale) - for i = 1, #modList do - local scaledMod = copyTable(modList[i]) - if type(scaledMod.value) == "number" then - scaledMod.value = (m_floor(scaledMod.value) == scaledMod.value) and m_floor(scaledMod.value * scale) or scaledMod.value * scale - end - self:AddMod(scaledMod) - end -end - -function ModDBClass:NewMod(...) - self:AddMod(createMod(...)) -end - -function ModDBClass:Sum(type, cfg, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) - local flags = cfg and cfg.flags or 0 - local keywordFlags = cfg and cfg.keywordFlags or 0 - local skillName = cfg and cfg.skillName - local skillGem = cfg and cfg.skillGem - local skillPart = cfg and cfg.skillPart - local slotName = cfg and cfg.slotName - local source = cfg and cfg.source - local tabulate = cfg and cfg.tabulate - local result - local nullValue = 0 - if tabulate or type == "LIST" then - result = { } - nullValue = nil - elseif type == "MORE" then - result = 1 - elseif type == "FLAG" then - result = false - nullValue = false - else - result = 0 - end - hack[1] = arg1 - if arg1 then - hack[2] = arg2 - if arg2 then - hack[3] = arg3 - if arg3 then - hack[4] = arg4 - if arg4 then - hack[5] = arg5 - if arg5 then - hack[6] = arg6 - if arg6 then - hack[7] = arg7 - if arg7 then - hack[8] = arg8 - end - end - end - end - end - end - end - for i = 1, #hack do --i = 1, select('#', ...) do - local modName = hack[i]--select(i, ...) - local modList = self.mods[modName] - if modList then - for i = 1, #modList do - local mod = modList[i] - if (not type or mod.type == type )and band(flags, mod.flags) == mod.flags and (mod.keywordFlags == 0 or band(keywordFlags, mod.keywordFlags) ~= 0) and (not source or mod.source:match("[^:]+") == source) then - local value = mod.value - for _, tag in pairs(mod.tagList) do - if tag.type == "Multiplier" then - local mult = (self.multipliers[tag.var] or 0) - if _G.type(value) == "table" then - value = copyTable(value) - value.value = value.value * mult - else - value = value * mult - end - elseif tag.type == "PerStat" then - local mult = m_floor((self.stats[tag.stat] or 0) / tag.div + 0.0001) + (tag.base or 0) - if _G.type(value) == "table" then - value = copyTable(value) - value.value = value.value * mult - else - value = value * mult - end - elseif tag.type == "Condition" then - if not self.conditions[tag.var] then - value = nullValue - end - elseif tag.type == "SocketedIn" then - if tag.slotName ~= slotName or (tag.keyword and (not skillGem or not gemIsType(skillGem, tag.keyword))) then - value = nullValue - end - elseif tag.type == "SkillName" then - if tag.skillName ~= skillName then - value = nullValue - end - elseif tag.type == "SkillPart" then - if tag.skillPart ~= skillPart then - value = nullValue - end - elseif tag.type == "SlotName" then - if tag.slotName ~= slotName then - value = nullValue - end - end - end - if tabulate then - if value and value ~= 0 then - t_insert(result, { value = value, mod = mod }) - end - elseif type == "MORE" then - result = result * (1 + value / 100) - elseif type == "FLAG" then - result = result or value - elseif type == "LIST" then - if value then - t_insert(result, value) - end - else - result = result + value - end - end - end - end - hack[i] = nil - end - return result -end - -function ModDBClass:Print() - ConPrintf("=== Modifiers ===") - local modNames = { } - for modName in pairs(self.mods) do - t_insert(modNames, modName) - end - table.sort(modNames) - for _, modName in ipairs(modNames) do - ConPrintf("'%s' = {", modName) - for _, mod in ipairs(self.mods[modName]) do - ConPrintf("\t%s = %s|%s|%s|%s|%s", formatValue(mod.value), mod.type, formatFlags(mod.flags, ModFlag), formatFlags(mod.keywordFlags, KeywordFlag), formatTags(mod.tagList), mod.source or "?") - end - ConPrintf("},") - end - ConPrintf("=== Conditions ===") - local nameList = { } - for name, value in pairs(self.conditions) do - if value then - t_insert(nameList, name) - end - end - table.sort(nameList) - for i, name in ipairs(nameList) do - ConPrintf(name) - end - ConPrintf("=== Multipliers ===") - wipeTable(nameList) - for name, value in pairs(self.multipliers) do - if value > 0 then - t_insert(nameList, name) - end - end - table.sort(nameList) - for i, name in ipairs(nameList) do - ConPrintf("%s = %d", name, self.multipliers[name]) - end -end \ No newline at end of file diff --git a/PathOfBuilding.sln b/PathOfBuilding.sln index e302e21f..a76a34cf 100644 --- a/PathOfBuilding.sln +++ b/PathOfBuilding.sln @@ -79,6 +79,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Classes", "Classes", "{7EE4 Classes\ItemSlotControl.lua = Classes\ItemSlotControl.lua Classes\ItemsTab.lua = Classes\ItemsTab.lua Classes\LabelControl.lua = Classes\LabelControl.lua + Classes\ModDB.lua = Classes\ModDB.lua + Classes\ModList.lua = Classes\ModList.lua Classes\PassiveSpec.lua = Classes\PassiveSpec.lua Classes\PassiveTree.lua = Classes\PassiveTree.lua Classes\PassiveTreeView.lua = Classes\PassiveTreeView.lua diff --git a/README.md b/README.md index 52213025..1cd29d99 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ significant upgrades: * You can click on a stat to pin the breakdown open so you can interact with it * Each breakdown view shows all the information used to calculate that stat, including ALL modifiers * You can hover over a modifier's source name to show the item's tooltip or passive node's location - * Hovering over a modifier source type ('Item', 'Node', 'Gem' etc) will show the totals from that source type + * Hovering over a modifier source type ('Item', 'Tree', 'Gem' etc) will show the totals from that source type * Most modifier totals are no longer displayed in the tab itself, since they can be found in the breakdown views. The most important ones (such as increased life from tree) are still present, however. * Per-stat modifiers are now supported, including, but not limited to, the modifiers from: @@ -81,6 +81,7 @@ Other changes: * The names of many options have been changed to clarify their function * Some options now have tooltips that explain aspects of their function * The new class background artworks have been added to the passive skill tree + * Unsupported modifiers are now shown in red instead of white to help convey the fact that they won't work * Support gem compatability is now determined using the same data the game itself uses, and should now be 100% accurate ### 1.1.11 - 2016/10/25 diff --git a/UpdateCheck.lua b/UpdateCheck.lua index 0abc84b6..53110bef 100644 --- a/UpdateCheck.lua +++ b/UpdateCheck.lua @@ -179,6 +179,7 @@ for index, data in ipairs(updateFiles) do source = source:gsub("{branch}", localBranch) local fileName = scriptPath.."/Update/"..data.name:gsub("[\\/]","{slash}") data.updateFileName = fileName + local content local zipName = source:match("/([^/]+%.zip)$") if zipName then if not zipFiles[zipName] then @@ -191,36 +192,29 @@ for index, data in ipairs(updateFiles) do if zip then local zippedFile = zip:OpenFile(data.name) if zippedFile then - local file = io.open(fileName, "w+b") - if not file then - ConPrintf("%s", fileName) - end - file:write(zippedFile:Read("*a")) - file:close() + content = zippedFile:Read("*a") zippedFile:Close() else ConPrintf("Couldn't extract '%s' from '%s' (extract failed)", data.name, zipName) - failedFile = true end else ConPrintf("Couldn't extract '%s' from '%s' (zip open failed)", data.name, zipName) - failedFile = true end else - ConPrintf("Downloading %s...", data.name) - local content = downloadFileText(source..data.name) - if content then - if data.sha1 ~= sha1(content) and data.sha1 ~= sha1(content:gsub("\n","\r\n")) then - ConPrintf("Hash mismatch on '%s'", data.name) - failedFile = true - else - local file = io.open(fileName, "w+b") - file:write(content) - file:close() - end - else + ConPrintf("Downloading %s... (%d of %d)", data.name, index, #updateFiles) + content = downloadFileText(source..data.name) + end + if content then + if data.sha1 ~= sha1(content) and data.sha1 ~= sha1(content:gsub("\n","\r\n")) then + ConPrintf("Hash mismatch on '%s'", data.name) failedFile = true + else + local file = io.open(fileName, "w+b") + file:write(content) + file:close() end + else + failedFile = true end end for name, zip in pairs(zipFiles) do diff --git a/changelog.txt b/changelog.txt index 442690be..e22dca6e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -9,7 +9,7 @@ significant upgrades: * You can click on a stat to pin the breakdown open so you can interact with it * Each breakdown view shows all the information used to calculate that stat, including ALL modifiers * You can hover over a modifier's source name to show the item's tooltip or passive node's location - * Hovering over a modifier source type ('Item', 'Node', 'Gem' etc) will show the totals from that source type + * Hovering over a modifier source type ('Item', 'Tree', 'Gem' etc) will show the totals from that source type * Most modifier totals are no longer displayed in the tab itself, since they can be found in the breakdown views. The most important ones (such as increased life from tree) are still present, however. * Per-stat modifiers are now supported, including, but not limited to, the modifiers from: @@ -30,6 +30,7 @@ Other changes: * The names of many options have been changed to clarify their function * Some options now have tooltips that explain aspects of their function * The new class background artworks have been added to the passive skill tree + * Unsupported modifiers are now shown in red instead of white to help convey the fact that they won't work * Support gem compatability is now determined using the same data the game itself uses, and should now be 100% accurate VERSION[1.1.11][2016/10/25] * Added flat mana to ES armour rare templates diff --git a/manifest.xml b/manifest.xml index e4a3d509..cacf6585 100644 --- a/manifest.xml +++ b/manifest.xml @@ -5,14 +5,14 @@ - + - + - + - + @@ -26,13 +26,15 @@ + + - + - + @@ -41,14 +43,14 @@ - - + + - + - - - + + +