view Scanner.lua @ 81:58617c7827fa

Item refilling should now be working. Probably very slow if your bags, bank or guild bank is filled with over 200 unique items or so (needs some real testing, but know that it is a known (possible) issue).
author Zerotorescue
date Thu, 06 Jan 2011 01:01:25 +0100
parents c0bf2ddb5288
children f885805da5d6
line wrap: on
line source
local addon = select(2, ...);
local mod = addon:NewModule("Scanner", "AceEvent-3.0");

addon.Locations = {
	Bag = 0,
	Bank = 1,
	Guild = 2,
};

local Mover, paused;
local itemCache = {};

local function GetItemID(link)
	return tonumber(link:match("|Hitem:([-0-9]+):"));
end

function mod:ClearCache()
	table.wipe(itemCache);
end

function mod:CacheLocation(location, remember)
	if location == addon.Locations.Bag or location == addon.Locations.Bank then
		-- Reset cache just in case it was filled
		self:ClearCache();
		
		local start, stop;
		if location == addon.Locations.Bag then
			start = 0;
			stop = NUM_BAG_SLOTS;
		else
			-- If we requested the bank then we don't want the bag info
			start = ( NUM_BAG_SLOTS + 1 );
			stop = ( NUM_BAG_SLOTS + NUM_BANKBAGSLOTS );
		end
		
		-- Go through all our bags, including the backpack
		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
			-- Scan the default 100 slots whenever we're at a non-existing index
			local bagId = (i == (stop + 1) and BANK_CONTAINER) or i;
			local slotId = GetContainerNumSlots(bagId);
			
			while slotId ~= 0 do
				-- A not equal-comparison should be quicker than a larger than-comparison
				
				local itemId = GetContainerItemID(bagId, slotId);
				local itemCount = itemId and select(2, GetContainerItemInfo(bagId, slotId));
				
				if itemId and itemCount and itemCount > 0 then
					local itemMove;
					if not itemCache[itemId] then
						-- If this is the first time we see this item, make a new object
						itemMove = addon.ContainerItem:New();
						itemCache[itemId] = itemMove;
					else
						-- If we had this item in another slot too
						itemMove = itemCache[itemId];
					end
					
					itemMove:AddLocation(bagId, slotId, itemCount);
				end
			
				-- Continue scanning a different slot
				slotId = (slotId - 1);
			end
		end
	elseif location == addon.Locations.Guild then
		-- Reset cache before we scan
		self:ClearCache();
		
		local tabId = GetCurrentGuildBankTab();
		local slotId = (MAX_GUILDBANK_SLOTS_PER_TAB or 98); -- start by scanning the last slot
		
		if tabId == nil or tabId < 1 then return; end
		
		while slotId ~= 0 do
			-- A not equal-comparison should be quicker than a larger than-comparison
			
				-- If there is actually an item in this slot
				
			local itemLink = GetGuildBankItemLink(tabId, slotId);
			local itemId = itemLink and GetItemId(itemLink);
			local itemCount = itemLink and select(2, GetGuildBankItemInfo(tabId, slotId));
				
			if itemLink and itemId and itemCount and itemCount > 0 then
				local itemMove;
				if not itemCache[itemId] then
					-- If this is the first time we see this item, make a new object
					itemMove = addon.ContainerItem:New();
					itemCache[itemId] = itemMove;
				else
					-- If we had this item in another slot too
					itemMove = itemCache[itemId];
				end
				
				itemMove:AddLocation(tabId, slotId, itemCount);
			end
			
			-- Continue scanning a different slot
			slotId = (slotId - 1);
		end
	else
		error("Invalid location provided for the local _GetItemCount. Must be Bank or Guild.");
	end
	
	if not remember then
		-- Copy the table as clearing the cache wipes it empty (and tables are passed by reference)
		local cacheCopy = CopyTable(itemCache);
		
		self:ClearCache();
		
		return cacheCopy;
	end
end

function mod:Scan(location)
	-- We might pause the scanning when we invoke moves ourself
	if paused then
		return;
	end
	
	local playerName = UnitName("player");
	
	self:CacheLocation(location, true);
	
	-- Go through all groups
	for groupName, values in pairs(addon.db.profile.groups) do
		local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters");
		
		if values.items and trackAt[playerName] then
			-- Is this character interested in this data?
			
			local minLocalStock = addon:GetOptionByKey(groupName, "minLocalStock");
			
			-- Go through all items
			for itemId, _ in pairs(values.items) do
				
				-- Check if we have enough items local (but only do so if this location also has enough available)
				local missingItems = itemCache[itemId] and (minLocalStock - addon:GetLocalItemCount(itemId, groupName));
				
				if itemCache[itemId] and missingItems > 0 then
					-- Check how many are available
					local availableItems = ((itemCache[itemId] and itemCache[itemId].totalCount) or 0);
					
					if availableItems > 0 then
						print("Insufficient " .. select(2, GetItemInfo(itemId)) .. " but this location has " .. availableItems .. " (moving " .. missingItems .. ")");
						
						Mover:AddMove(itemId, missingItems);
					else
						print("Insufficient " .. IdToItemLink(itemId));
					end
				end
			end
		end
	end
	
	self:ClearCache();
	
	if Mover:HasMoves() then
		StaticPopupDialogs["InventoriumRefill"] = {
			text = "There are items that can be refilled from this location, do you wish to proceed?",
			button1 = YES,
			button2 = NO,
			OnAccept = function()
				mod:Pause();
				Mover:BeginMove(location, self.Unpause);
			end,
			timeout = 0,
			whileDead = 1,
			hideOnEscape = 1,
		};
		StaticPopup_Show("InventoriumRefill");
	end
end

local function BANKFRAME_CLOSED()
	addon:Debug("Scanner:BANKFRAME_CLOSED");
	
	mod:UnregisterEvent("BANKFRAME_CLOSED");
	
	StaticPopup_Hide("InventoriumRefill");
end

local function BANKFRAME_OPENED()
	addon:Debug("Scanner:BANKFRAME_OPENED");
	
	mod:RegisterEvent("BANKFRAME_CLOSED", BANKFRAME_CLOSED);
	
	-- Scan once when the bank is opened, but no need to scan after
	mod:Scan(addon.Locations.Bank);
end

-- Remember which tabs were scanned and don't scan them again
local guildBankTabsScanned = {};

local function GUILDBANKFRAME_CLOSED()
	addon:Debug("Scanner:GUILDBANKFRAME_CLOSED");
	
	table.wipe(guildBankTabsScanned);
	
	mod:UnregisterEvent("GUILDBANKFRAME_CLOSED");
	mod:UnregisterEvent("GUILDBANKBAGSLOTS_CHANGED");
	
	StaticPopup_Hide("InventoriumRefill");
end

local function GUILDBANKBAGSLOTS_CHANGED()
	if not guildBankTabsScanned[GetCurrentGuildBankTab()] then
		addon:Debug("Scanner:GUILDBANKBAGSLOTS_CHANGED (" .. GetCurrentGuildBankTab() .. ") - scanning");
		
		mod:Scan(addon.Locations.Guild);
		guildBankTabsScanned[GetCurrentGuildBankTab()] = true;
	else
		addon:Debug("Scanner:GUILDBANKBAGSLOTS_CHANGED (" .. GetCurrentGuildBankTab() .. ") - not scanning");
	end
end

local function GUILDBANKFRAME_OPENED()
	addon:Debug("Scanner:GUILDBANKFRAME_OPENED");
	
	table.wipe(guildBankTabsScanned);
	
	mod:RegisterEvent("GUILDBANKFRAME_CLOSED", GUILDBANKFRAME_CLOSED);
	mod:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED", GUILDBANKBAGSLOTS_CHANGED);
end

function mod:OnEnable()
	-- Scan once when the bankframe is opened
	mod:RegisterEvent("BANKFRAME_OPENED", BANKFRAME_OPENED);
	mod:RegisterEvent("GUILDBANKFRAME_OPENED", GUILDBANKFRAME_OPENED);
	
	Mover = addon:GetModule("Mover");
end

function mod:OnDisable()
	Mover = nil;
	
	-- Bank
	mod:UnregisterEvent("BANKFRAME_OPENED");
	
	-- Guild
	GUILDBANKFRAME_CLOSED();
	mod:UnregisterEvent("GUILDBANKFRAME_OPENED");
end

function mod:Pause()
	paused = true;
end

function mod:Unpause()
	paused = nil;
end