view Scanner.lua @ 80:c0bf2ddb5288

Added initial item refilling from the bank/guild. Not yet fully functional.
author Zerotorescue
date Wed, 05 Jan 2011 13:05:15 +0100
parents
children 58617c7827fa
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 _GetItemCount(itemId, location)
	if location == addon.Locations.Bank then
		-- No longer using GetItemCount as this includes equiped items and containers (e.g. bank bags)
		--return (GetItemCount(itemId, true) - GetItemCount(itemId, false)); -- GetItemCount(X, true) provides count for bag+bank, GetItemCount(X, false) provides just bag, so (GetItemCount(X, true) - GetItemCount(X, false)) = just bank
		return ((itemCache[itemId] and itemCache[itemId].totalCount) or 0);
	elseif location == addon.Locations.Guild then
		return ((itemCache[itemId] and itemCache[itemId].totalCount) or 0);
	else
		error("Invalid location provided for the local _GetItemCount. Must be Bag or Bank.");
	end
end

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, ((addon.Locations.Bag and stop) or (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.ItemMove:New();
					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.ItemMove:New();
				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
				local missingItems = (minLocalStock - addon:GetLocalItemCount(itemId, groupName));
				
				if missingItems > 0 then
					-- Check how many are available
					local availableItems = _GetItemCount(itemId, location);
					
					if availableItems > 0 then
						print("Insufficient " .. select(2, GetItemInfo(itemId)) .. " but this location has " .. availableItems .. " (moving " .. missingItems .. ")");
						
						Mover:AddMove(itemId, missingItems);
					else
						print("Insufficient " .. select(2, GetItemInfo(itemId)));
					end
				end
			end
		end
	end
	
	self:ClearCache();
	
	self:Pause();
	Mover:BeginMove(location, self.Unpause);
end

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

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

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

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

local function GUILDBANKFRAME_OPENED()
	table.wipe(guildBankTabsScanned);
	
	mod:RegisterEvent("GUILDBANKFRAME_CLOSED", GUILDBANKFRAME_CLOSED);
	mod:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED", GUILDBANKBAGSLOTS_CHANGED);
	
	addon:Debug("Scanner:GUILDBANKFRAME_OPENED");
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