diff --git a/EnchantIDs.lua b/EnchantIDs.lua index 8fabf5a..9639e2d 100644 --- a/EnchantIDs.lua +++ b/EnchantIDs.lua @@ -2,7 +2,7 @@ local normalWeapon = { "weapon", weapon = { [false] = { "fishing pole", "shield" local normalTwoHand = { "two-hand", ["two-hand"] = { [false] = { "fishing pole" } } } local normalRanged = { "ranged", ranged = { [false] = { "wand" } } } -EnchantIDs = { +local EnchantIDs = { [15] = { itemID = { 2304 }, name = { @@ -5097,7 +5097,7 @@ ww_reputations = { [8] = 43000, -- Exalted } -EnchantItems = { +local EnchantItems = { [2304] = { enchID = 15, name = "Light Armor Kit", @@ -8261,7 +8261,7 @@ EnchantItems = { }, } -EnchantSpells = { +local EnchantSpells = { [7418] = { enchID = 41, name = "Enchant Bracer - Minor Health", @@ -10891,3 +10891,269 @@ EnchantSpells = { source = "Crafted", }, } + +local EnchantOptions = {} + +ww_slotsToCheck = { + back = {"back"}, + chest = {"chest"}, + feet = {"feet"}, + finger = {"finger"}, + hands = {"hands"}, + head = {"head"}, + ["held in off-hand"] = {"held in off-hand"}, + legs = {"legs"}, + ["main hand"] = {"main hand", "one hand", "weapon"}, + neck = {"neck"}, + ["off hand"] = {"off hand", "one hand", "weapon"}, + ["one-hand"] = {"one-hand", "weapon"}, + projectile = {"projectile"}, + ranged = {"ranged"}, + relic = {"relic"}, + shirt = {"shirt"}, + shoulder = {"shoulder"}, + tabard = {"tabard"}, + thrown = {"thrown"}, + trinket = {"trinket"}, + ["two-hand"] = {"two-hand", "weapon"}, + waist = {"waist"}, + wrist = {"wrist"}, +} + +ww_factionsToTrack = {} + +for item, info in pairs(EnchantItems) do + if info.enchID and info.source ~= "Unavailable" then + local class = info.class or "all" + if not EnchantOptions[class] then + EnchantOptions[class] = {} + end + for _, slot in ipairs(info.slot) do + if not EnchantOptions[class][slot] then + EnchantOptions[class][slot] = {} + end + local subslots = {} + if info.slot[slot] then + if info.slot[slot][true] then + for _, subslot in ipairs(info.slot[slot][true]) do + subslots[subslot] = true + end + elseif info.slot[slot][false] then + for subslot in pairs(ww_slotsToSubslots[slot]) do + subslots[subslot] = true + end + for _, subslot in ipairs(info.slot[slot][false]) do + subslots[subslot] = nil + end + end + else + subslots["all"] = true + end + for subslot in pairs(subslots) do + if not EnchantOptions[class][slot][subslot] then + EnchantOptions[class][slot][subslot] = {} + end + if not EnchantOptions[class][slot][subslot][info.source] then + EnchantOptions[class][slot][subslot][info.source] = {} + end + if not EnchantOptions[class][slot][subslot][info.source][info.boa or false] then + EnchantOptions[class][slot][subslot][info.source][info.boa or false] = {} + end + local reputations = info.rep or { ["none"] = 0 } + for faction, reputation in pairs(reputations) do + ww_factionsToTrack[faction] = true + if not EnchantOptions[class][slot][subslot][info.source][info.boa or false][faction] then + EnchantOptions[class][slot][subslot][info.source][info.boa or false][faction] = IntervalTree.create() + end + local repInterval = EnchantOptions[class][slot][subslot][info.source][info.boa or false][faction].findInterval(reputation, math.huge) + if not repInterval then + repInterval = {} + EnchantOptions[class][slot][subslot][info.source][info.boa or false][faction].insert(reputation, math.huge, repInterval) + end + local skills = info.skill or { ["none"] = 0 } + for skill, level in pairs(skills) do + if not repInterval[skill] then + repInterval[skill] = IntervalTree.create() + end + local skillInterval = repInterval[skill].findInterval(level, math.huge) + if not skillInterval then + skillInterval = IntervalTree.create() + repInterval[skill].insert(level, math.huge, skillInterval) + end + local iLvlInterval = skillInterval.findInterval(info.minIlvl or 0, info.maxIlvl or math.huge) + if not iLvlInterval then + iLvlInterval = IntervalTree.create() + skillInterval.insert(info.minIlvl or 0, info.maxIlvl or math.huge, iLvlInterval) + end + local pLvlInterval = iLvlInterval.findInterval(info.minLvl or 0, info.maxLvl or math.huge) + if not pLvlInterval then + pLvlInterval = {} + iLvlInterval.insert(info.minLvl or 0, info.maxLvl or math.huge, pLvlInterval) + end + if not pLvlInterval[info.name] then + pLvlInterval[info.name] = {} + end + pLvlInterval[info.name][info.enchID] = true + end + end + end + end + end +end + +for item, info in pairs(EnchantSpells) do + if info.source ~= "Unavailable" and info.source ~= "Crafted (undetectable)" then + local class = info.class or "all" + if not EnchantOptions[class] then + EnchantOptions[class] = {} + end + for _, slot in ipairs(info.slot) do + if not EnchantOptions[class][slot] then + EnchantOptions[class][slot] = {} + end + local subslots = {} + if info.slot[slot] then + if info.slot[slot][true] then + for _, subslot in ipairs(info.slot[slot][true]) do + subslots[subslot] = true + end + elseif info.slot[slot][false] then + for subslot in pairs(ww_slotsToSubslots[slot]) do + subslots[subslot] = true + end + for _, subslot in ipairs(info.slot[slot][false]) do + subslots[subslot] = nil + end + end + else + subslots["all"] = true + end + for subslot in pairs(subslots) do + if not EnchantOptions[class][slot][subslot] then + EnchantOptions[class][slot][subslot] = {} + end + if not EnchantOptions[class][slot][subslot][info.source] then + EnchantOptions[class][slot][subslot][info.source] = {} + end + if not EnchantOptions[class][slot][subslot][info.source][info.boa or false] then + EnchantOptions[class][slot][subslot][info.source][info.boa or false] = {} + end + local reputations = info.rep or { ["none"] = 0 } + for faction, reputation in pairs(reputations) do + ww_factionsToTrack[faction] = true + if not EnchantOptions[class][slot][subslot][info.source][info.boa or false][faction] then + EnchantOptions[class][slot][subslot][info.source][info.boa or false][faction] = IntervalTree.create() + end + local repInterval = EnchantOptions[class][slot][subslot][info.source][info.boa or false][faction].findInterval(reputation, math.huge) + if not repInterval then + repInterval = {} + EnchantOptions[class][slot][subslot][info.source][info.boa or false][faction].insert(reputation, math.huge, repInterval) + end + local skills = info.skill or { ["none"] = 0 } + for skill, level in pairs(skills) do + if not repInterval[skill] then + repInterval[skill] = IntervalTree.create() + end + local skillInterval = repInterval[skill].findInterval(level, math.huge) + if not skillInterval then + skillInterval = IntervalTree.create() + repInterval[skill].insert(level, math.huge, skillInterval) + end + local iLvlInterval = skillInterval.findInterval(info.minIlvl or 0, info.maxIlvl or math.huge) + if not iLvlInterval then + iLvlInterval = IntervalTree.create() + skillInterval.insert(info.minIlvl or 0, info.maxIlvl or math.huge, iLvlInterval) + end + local pLvlInterval = iLvlInterval.findInterval(info.minLvl or 0, info.maxLvl or math.huge) + if not pLvlInterval then + pLvlInterval = {} + iLvlInterval.insert(info.minLvl or 0, info.maxLvl or math.huge, pLvlInterval) + end + if not pLvlInterval[info.name] then + pLvlInterval[info.name] = {} + end + pLvlInterval[info.name][info.enchID] = true + end + end + end + end + end +end + +local enchantItemMetatable = { + __index = function(tbl, key) + local bestScore, bestEnchants = 0, {} + local bareStats = ww_bareItemCache[key] + for _, choices in ipairs(tbl.enchants) do + for _, slot in ipairs(ww_slotsToCheck[bareStats.nonStats.slot]) do + if choices[slot] then + local subslots = { "all" } + table.insert(subslots, bareStats.nonStats.subslot) + for _, subslot in ipairs(subslots) do + for source, enchants in pairs(choices[slot][subslot] or {}) do + for boa, enchants in pairs(enchants) do + for faction, enchantIntervals in pairs(enchants) do + for _, enchants in ipairs(enchantIntervals.find(ww_vars.options.useBoa and boa and #(ww_reputations) or getRep(faction))) do + for profession, intervals in pairs(enchants) do + for _, intervals in ipairs(intervals.find(getSkill(profession))) do + for _, intervals in ipairs(intervals.find(bareStats.normalStats["item level"] or 1)) do + for _, interval in ipairs(intervals.find(WeightsWatcher.playerLevel or 85)) do + for name, ids in pairs(interval) do + for id in pairs(ids) do + local score = WeightsWatcher.calculateWeight({}, { enchantStats = WeightsWatcher.enchantStats(id).stats }, tbl.weight) + if score > bestScore then + bestScore = score + bestEnchants = { [name] = { id } } + elseif score == bestScore then + if not bestEnchants[name] then + bestEnchants[name] = {} + end + table.insert(bestEnchants[name], id) + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + tbl[key] = bestEnchants + return tbl[key] + end, +} + +local enchantWeightMetatable = { + __index = function(tbl, key) + tbl[key] = setmetatable({ enchants = tbl.enchants, weight = ww_vars.weightsList[tbl.class][key] }, enchantItemMetatable) + return tbl[key] + end, +} + +local enchantClassMetatable = { + __index = function(tbl, key) + local enchants = {} + for _, class in ipairs({ key, "all" }) do + table.insert(enchants, EnchantOptions[class]) + end + tbl[key] = setmetatable({ class = key, enchants = enchants }, enchantWeightMetatable) + return tbl[key] + end, +} + +function WeightsWatcher.ResetEnchantCache() + ww_bestEnchantsCache = setmetatable({}, enchantClassMetatable) +end + +function WeightsWatcher.enchantStats(id) + if type(id) == "string" then + id = tonumber(id) + end + return EnchantIDs[id] or {} +end diff --git a/WeightsWatcher.lua b/WeightsWatcher.lua index 1e97961..f83daa9 100644 --- a/WeightsWatcher.lua +++ b/WeightsWatcher.lua @@ -245,6 +245,8 @@ function WeightsWatcher.ResetTables() ww_ignored_lines = setmetatable({}, metatable) ww_temp_ignored_lines = setmetatable({}, metatable) ww_unweighted_lines = setmetatable({}, metatable) + + WeightsWatcher.ResetEnchantCache() end local function upgradeData(dataType, varsName) diff --git a/WeightsWatcher.toc b/WeightsWatcher.toc index 30183a0..3a20d8b 100644 --- a/WeightsWatcher.toc +++ b/WeightsWatcher.toc @@ -19,6 +19,8 @@ Locales\locales.xml GemIds.lua config.xml weights.xml +IntervalTree.lua +slots.lua EnchantIDs.lua Upgrade.lua defaults.lua