-- ------------------------------------------------------------------------------ -- -- TradeSkillMaster -- -- https://tradeskillmaster.com -- -- All Rights Reserved - Detailed license information included with addon. -- -- ------------------------------------------------------------------------------ -- local _, TSM = ... local Conversions = TSM.Init("Service.Conversions") local DisenchantInfo = TSM.Include("Data.DisenchantInfo") local Mill = TSM.Include("Data.Mill") local Prospect = TSM.Include("Data.Prospect") local Transform = TSM.Include("Data.Transform") local VendorTrade = TSM.Include("Data.VendorTrade") local TempTable = TSM.Include("Util.TempTable") local ItemString = TSM.Include("Util.ItemString") local Table = TSM.Include("Util.Table") local ItemInfo = TSM.Include("Service.ItemInfo") Conversions.METHOD = { DISENCHANT = newproxy(), MILL = newproxy(), PROSPECT = newproxy(), TRANSFORM = newproxy(), VENDOR_TRADE = newproxy(), CRAFT = newproxy(), } local private = { data = {}, sourceItemCache = {}, skippedConversions = {}, } local MAX_CONVERSION_DEPTH = 3 local EMPTY_CONVERSION = newproxy() -- ============================================================================ -- Module Loading -- ============================================================================ Conversions:OnModuleLoad(function() Table.SetReadOnly(Conversions.METHOD) for itemString in DisenchantInfo.TargetItemIterator() do ItemInfo.FetchInfo(itemString) end for targetItemString in Mill.TargetItemIterator() do for sourceItemString in Mill.SourceItemIterator(targetItemString) do local rate = Mill.GetRate(targetItemString, sourceItemString) private.Add(targetItemString, sourceItemString, Conversions.METHOD.MILL, rate) end end for targetItemString in Prospect.TargetItemIterator() do for sourceItemString in Prospect.SourceItemIterator(targetItemString) do local rate, amount, minAmount, maxAmount = Prospect.GetRate(targetItemString, sourceItemString) private.Add(targetItemString, sourceItemString, Conversions.METHOD.PROSPECT, rate, amount, minAmount, maxAmount) end end for targetItemString in Transform.TargetItemIterator() do for sourceItemString in Transform.SourceItemIterator(targetItemString) do local rate = Transform.GetRate(targetItemString, sourceItemString) private.Add(targetItemString, sourceItemString, Conversions.METHOD.TRANSFORM, rate) end end for targetItemString in VendorTrade.TargetItemIterator() do for sourceItemString in VendorTrade.SourceItemIterator(targetItemString) do local rate = VendorTrade.GetRate(targetItemString, sourceItemString) private.Add(targetItemString, sourceItemString, Conversions.METHOD.VENDOR_TRADE, rate) end end end) -- ============================================================================ -- Module Functions -- ============================================================================ function Conversions.AddCraft(targetItemString, sourceItemString, rate) private.Add(targetItemString, sourceItemString, Conversions.METHOD.CRAFT, rate) end function Conversions.TargetItemsByMethodIterator(sourceItemString, method) local context = TempTable.Acquire() context.sourceItemString = sourceItemString context.method = method return private.TargetItemsByMethodIteratorHelper, context, nil end function Conversions.GetTargetItemByName(targetItemName) targetItemName = strlower(targetItemName) for targetItemString in pairs(private.data) do local name = ItemInfo.GetName(targetItemString) if name and strlower(name) == targetItemName then return targetItemString end end for targetItemString in DisenchantInfo.TargetItemIterator() do local name = ItemInfo.GetName(targetItemString) if name and strlower(name) == targetItemName then return targetItemString end end end function Conversions.GetSourceItems(targetItemString) if not targetItemString or not private.data[targetItemString] or private.sourceItemCache[targetItemString] == EMPTY_CONVERSION then return end if not private.sourceItemCache[targetItemString] then local depthLookup = TempTable.Acquire() depthLookup[targetItemString] = -1 -- set this so we don't loop back through the target item private.sourceItemCache[targetItemString] = {} private.GetSourceItemsHelper(targetItemString, private.sourceItemCache[targetItemString], depthLookup, 0, 1) TempTable.Release(depthLookup) if not next(private.sourceItemCache[targetItemString]) then private.sourceItemCache[targetItemString] = EMPTY_CONVERSION return end end return private.sourceItemCache[targetItemString] end -- ============================================================================ -- Private Helper Functions -- ============================================================================ function private.Add(targetItemString, sourceItemString, method, rate, amount, minAmount, maxAmount) targetItemString = ItemString.GetBase(targetItemString) sourceItemString = ItemString.GetBase(sourceItemString) assert(targetItemString and sourceItemString) private.data[targetItemString] = private.data[targetItemString] or {} if private.data[targetItemString][sourceItemString] then -- if there is more than one way to go from source to target, then just skip all conversions between these items private.skippedConversions[targetItemString..sourceItemString] = true private.data[targetItemString][sourceItemString] = nil end if private.skippedConversions[targetItemString..sourceItemString] then return end private.data[targetItemString][sourceItemString] = { method = method, rate = rate, amount = amount, minAmount = minAmount, maxAmount = maxAmount, } ItemInfo.FetchInfo(targetItemString) ItemInfo.FetchInfo(sourceItemString) wipe(private.sourceItemCache) end function private.GetSourceItemsHelper(targetItemString, result, depthLookup, currentDepth, currentRate) if currentDepth >= MAX_CONVERSION_DEPTH or not private.data[targetItemString] then return end for sourceItemString, info in pairs(private.data[targetItemString]) do if not result[sourceItemString] or depthLookup[sourceItemString] > currentDepth then local rate = info.rate * currentRate result[sourceItemString] = rate depthLookup[sourceItemString] = currentDepth private.GetSourceItemsHelper(sourceItemString, result, depthLookup, currentDepth + 1, rate) end end end function private.TargetItemsByMethodIteratorHelper(context, index) while true do index = next(private.data, index) local items = private.data[index] if not items then TempTable.Release(context) return end local info = items[context.sourceItemString] if info and ((not context.method and info.method ~= Conversions.METHOD.CRAFT) or info.method == context.method) then return index, info.rate, info.amount, info.minAmount, info.maxAmount end end end