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 @@
-
-
+
+
-
+
-
-
-
+
+
+