Zerotorescue@80: local addon = select(2, ...); Zerotorescue@80: local mod = addon:NewModule("Scanner", "AceEvent-3.0"); Zerotorescue@80: Zerotorescue@80: addon.Locations = { Zerotorescue@80: Bag = 0, Zerotorescue@80: Bank = 1, Zerotorescue@80: Guild = 2, Zerotorescue@80: }; Zerotorescue@80: Zerotorescue@80: local Mover, paused; Zerotorescue@80: local itemCache = {}; Zerotorescue@80: Zerotorescue@80: local function GetItemID(link) Zerotorescue@80: return tonumber(link:match("|Hitem:([-0-9]+):")); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: function mod:ClearCache() Zerotorescue@80: table.wipe(itemCache); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: function mod:CacheLocation(location, remember) Zerotorescue@80: if location == addon.Locations.Bag or location == addon.Locations.Bank then Zerotorescue@80: -- Reset cache just in case it was filled Zerotorescue@80: self:ClearCache(); Zerotorescue@80: Zerotorescue@80: local start, stop; Zerotorescue@80: if location == addon.Locations.Bag then Zerotorescue@80: start = 0; Zerotorescue@80: stop = NUM_BAG_SLOTS; Zerotorescue@80: else Zerotorescue@80: -- If we requested the bank then we don't want the bag info Zerotorescue@80: start = ( NUM_BAG_SLOTS + 1 ); Zerotorescue@80: stop = ( NUM_BAG_SLOTS + NUM_BANKBAGSLOTS ); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: -- Go through all our bags, including the backpack Zerotorescue@81: for i = start, ((location == addon.Locations.Bag and stop) or (location == addon.Locations.Bank and (stop + 1))) do -- if scanning bags stop at normal bag slot, if scanning bank, stop one later to allow BANK_CONTAINER to be scanned too Zerotorescue@80: -- Scan the default 100 slots whenever we're at a non-existing index Zerotorescue@80: local bagId = (i == (stop + 1) and BANK_CONTAINER) or i; Zerotorescue@80: local slotId = GetContainerNumSlots(bagId); Zerotorescue@80: Zerotorescue@80: while slotId ~= 0 do Zerotorescue@80: -- A not equal-comparison should be quicker than a larger than-comparison Zerotorescue@80: Zerotorescue@80: local itemId = GetContainerItemID(bagId, slotId); Zerotorescue@80: local itemCount = itemId and select(2, GetContainerItemInfo(bagId, slotId)); Zerotorescue@80: Zerotorescue@80: if itemId and itemCount and itemCount > 0 then Zerotorescue@80: local itemMove; Zerotorescue@80: if not itemCache[itemId] then Zerotorescue@80: -- If this is the first time we see this item, make a new object Zerotorescue@81: itemMove = addon.ContainerItem:New(); Zerotorescue@81: itemCache[itemId] = itemMove; Zerotorescue@80: else Zerotorescue@80: -- If we had this item in another slot too Zerotorescue@80: itemMove = itemCache[itemId]; Zerotorescue@80: end Zerotorescue@80: Zerotorescue@81: itemMove:AddLocation(bagId, slotId, itemCount); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: -- Continue scanning a different slot Zerotorescue@80: slotId = (slotId - 1); Zerotorescue@80: end Zerotorescue@80: end Zerotorescue@80: elseif location == addon.Locations.Guild then Zerotorescue@80: -- Reset cache before we scan Zerotorescue@80: self:ClearCache(); Zerotorescue@80: Zerotorescue@80: local tabId = GetCurrentGuildBankTab(); Zerotorescue@80: local slotId = (MAX_GUILDBANK_SLOTS_PER_TAB or 98); -- start by scanning the last slot Zerotorescue@80: Zerotorescue@80: if tabId == nil or tabId < 1 then return; end Zerotorescue@80: Zerotorescue@80: while slotId ~= 0 do Zerotorescue@80: -- A not equal-comparison should be quicker than a larger than-comparison Zerotorescue@80: Zerotorescue@80: -- If there is actually an item in this slot Zerotorescue@80: Zerotorescue@80: local itemLink = GetGuildBankItemLink(tabId, slotId); Zerotorescue@80: local itemId = itemLink and GetItemId(itemLink); Zerotorescue@80: local itemCount = itemLink and select(2, GetGuildBankItemInfo(tabId, slotId)); Zerotorescue@80: Zerotorescue@80: if itemLink and itemId and itemCount and itemCount > 0 then Zerotorescue@80: local itemMove; Zerotorescue@80: if not itemCache[itemId] then Zerotorescue@80: -- If this is the first time we see this item, make a new object Zerotorescue@81: itemMove = addon.ContainerItem:New(); Zerotorescue@81: itemCache[itemId] = itemMove; Zerotorescue@80: else Zerotorescue@80: -- If we had this item in another slot too Zerotorescue@80: itemMove = itemCache[itemId]; Zerotorescue@80: end Zerotorescue@80: Zerotorescue@81: itemMove:AddLocation(tabId, slotId, itemCount); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: -- Continue scanning a different slot Zerotorescue@80: slotId = (slotId - 1); Zerotorescue@80: end Zerotorescue@80: else Zerotorescue@80: error("Invalid location provided for the local _GetItemCount. Must be Bank or Guild."); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: if not remember then Zerotorescue@80: -- Copy the table as clearing the cache wipes it empty (and tables are passed by reference) Zerotorescue@80: local cacheCopy = CopyTable(itemCache); Zerotorescue@80: Zerotorescue@80: self:ClearCache(); Zerotorescue@80: Zerotorescue@80: return cacheCopy; Zerotorescue@80: end Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: function mod:Scan(location) Zerotorescue@80: -- We might pause the scanning when we invoke moves ourself Zerotorescue@80: if paused then Zerotorescue@80: return; Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: local playerName = UnitName("player"); Zerotorescue@80: Zerotorescue@80: self:CacheLocation(location, true); Zerotorescue@80: Zerotorescue@80: -- Go through all groups Zerotorescue@80: for groupName, values in pairs(addon.db.profile.groups) do Zerotorescue@80: local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters"); Zerotorescue@80: Zerotorescue@80: if values.items and trackAt[playerName] then Zerotorescue@80: -- Is this character interested in this data? Zerotorescue@80: Zerotorescue@80: local minLocalStock = addon:GetOptionByKey(groupName, "minLocalStock"); Zerotorescue@80: Zerotorescue@80: -- Go through all items Zerotorescue@80: for itemId, _ in pairs(values.items) do Zerotorescue@80: Zerotorescue@81: -- Check if we have enough items local (but only do so if this location also has enough available) Zerotorescue@81: local missingItems = itemCache[itemId] and (minLocalStock - addon:GetLocalItemCount(itemId, groupName)); Zerotorescue@80: Zerotorescue@81: if itemCache[itemId] and missingItems > 0 then Zerotorescue@80: -- Check how many are available Zerotorescue@81: local availableItems = ((itemCache[itemId] and itemCache[itemId].totalCount) or 0); Zerotorescue@80: Zerotorescue@80: if availableItems > 0 then Zerotorescue@80: print("Insufficient " .. select(2, GetItemInfo(itemId)) .. " but this location has " .. availableItems .. " (moving " .. missingItems .. ")"); Zerotorescue@80: Zerotorescue@80: Mover:AddMove(itemId, missingItems); Zerotorescue@80: else Zerotorescue@81: print("Insufficient " .. IdToItemLink(itemId)); Zerotorescue@80: end Zerotorescue@80: end Zerotorescue@80: end Zerotorescue@80: end Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: self:ClearCache(); Zerotorescue@80: Zerotorescue@81: if Mover:HasMoves() then Zerotorescue@81: StaticPopupDialogs["InventoriumRefill"] = { Zerotorescue@81: text = "There are items that can be refilled from this location, do you wish to proceed?", Zerotorescue@81: button1 = YES, Zerotorescue@81: button2 = NO, Zerotorescue@81: OnAccept = function() Zerotorescue@81: mod:Pause(); Zerotorescue@81: Mover:BeginMove(location, self.Unpause); Zerotorescue@81: end, Zerotorescue@81: timeout = 0, Zerotorescue@81: whileDead = 1, Zerotorescue@81: hideOnEscape = 1, Zerotorescue@81: }; Zerotorescue@81: StaticPopup_Show("InventoriumRefill"); Zerotorescue@81: end Zerotorescue@81: end Zerotorescue@81: Zerotorescue@81: local function BANKFRAME_CLOSED() Zerotorescue@81: addon:Debug("Scanner:BANKFRAME_CLOSED"); Zerotorescue@81: Zerotorescue@81: mod:UnregisterEvent("BANKFRAME_CLOSED"); Zerotorescue@81: Zerotorescue@81: StaticPopup_Hide("InventoriumRefill"); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: local function BANKFRAME_OPENED() Zerotorescue@81: addon:Debug("Scanner:BANKFRAME_OPENED"); Zerotorescue@81: Zerotorescue@81: mod:RegisterEvent("BANKFRAME_CLOSED", BANKFRAME_CLOSED); Zerotorescue@81: Zerotorescue@80: -- Scan once when the bank is opened, but no need to scan after Zerotorescue@80: mod:Scan(addon.Locations.Bank); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: -- Remember which tabs were scanned and don't scan them again Zerotorescue@80: local guildBankTabsScanned = {}; Zerotorescue@80: Zerotorescue@80: local function GUILDBANKFRAME_CLOSED() Zerotorescue@81: addon:Debug("Scanner:GUILDBANKFRAME_CLOSED"); Zerotorescue@81: Zerotorescue@81: table.wipe(guildBankTabsScanned); Zerotorescue@81: Zerotorescue@80: mod:UnregisterEvent("GUILDBANKFRAME_CLOSED"); Zerotorescue@80: mod:UnregisterEvent("GUILDBANKBAGSLOTS_CHANGED"); Zerotorescue@80: Zerotorescue@81: StaticPopup_Hide("InventoriumRefill"); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: local function GUILDBANKBAGSLOTS_CHANGED() Zerotorescue@80: if not guildBankTabsScanned[GetCurrentGuildBankTab()] then Zerotorescue@81: addon:Debug("Scanner:GUILDBANKBAGSLOTS_CHANGED (" .. GetCurrentGuildBankTab() .. ") - scanning"); Zerotorescue@81: Zerotorescue@80: mod:Scan(addon.Locations.Guild); Zerotorescue@80: guildBankTabsScanned[GetCurrentGuildBankTab()] = true; Zerotorescue@80: else Zerotorescue@80: addon:Debug("Scanner:GUILDBANKBAGSLOTS_CHANGED (" .. GetCurrentGuildBankTab() .. ") - not scanning"); Zerotorescue@80: end Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: local function GUILDBANKFRAME_OPENED() Zerotorescue@81: addon:Debug("Scanner:GUILDBANKFRAME_OPENED"); Zerotorescue@81: Zerotorescue@80: table.wipe(guildBankTabsScanned); Zerotorescue@80: Zerotorescue@80: mod:RegisterEvent("GUILDBANKFRAME_CLOSED", GUILDBANKFRAME_CLOSED); Zerotorescue@80: mod:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED", GUILDBANKBAGSLOTS_CHANGED); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: function mod:OnEnable() Zerotorescue@80: -- Scan once when the bankframe is opened Zerotorescue@80: mod:RegisterEvent("BANKFRAME_OPENED", BANKFRAME_OPENED); Zerotorescue@80: mod:RegisterEvent("GUILDBANKFRAME_OPENED", GUILDBANKFRAME_OPENED); Zerotorescue@80: Zerotorescue@80: Mover = addon:GetModule("Mover"); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: function mod:OnDisable() Zerotorescue@80: Mover = nil; Zerotorescue@80: Zerotorescue@80: -- Bank Zerotorescue@80: mod:UnregisterEvent("BANKFRAME_OPENED"); Zerotorescue@80: Zerotorescue@80: -- Guild Zerotorescue@80: GUILDBANKFRAME_CLOSED(); Zerotorescue@80: mod:UnregisterEvent("GUILDBANKFRAME_OPENED"); Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: function mod:Pause() Zerotorescue@80: paused = true; Zerotorescue@80: end Zerotorescue@80: Zerotorescue@80: function mod:Unpause() Zerotorescue@80: paused = nil; Zerotorescue@80: end