diff Modules/Scanner.lua @ 110:67bd5057ecb7

Implemented vendor restocking with the mover. Comitting so I can always review this working version, but I?ll be disabling all part of it as it is not going to work properly without seriously compromising the code structure. Debug messages are now appended with ?Inventorium? (my MailOpener addon was making stuff difficult). Now properly removing the refill window from the displayed static popup windows list so new popups won?t be aligned at odd locations. Changed ?CreateMoverFrame? to not contain any scenario-specific info. All settings can be set with SetFrameSettings. Items that belong to speciality bags are now put there. Other items now ignore spaciality bags. Implemented test code for mailbox refill support. It has been disabled due to some issues but may be introduced later. The guild withdrawal limit is now taken into consideration. Queue is now reset before scanning again.
author Zerotorescue
date Fri, 14 Jan 2011 23:25:05 +0100
parents 3bbad0429d87
children 41f0689dfda1
line wrap: on
line diff
--- a/Modules/Scanner.lua	Wed Jan 12 22:48:25 2011 +0100
+++ b/Modules/Scanner.lua	Fri Jan 14 23:25:05 2011 +0100
@@ -1,30 +1,107 @@
 local addon = select(2, ...);
 local mod = addon:NewModule("Scanner", "AceEvent-3.0", "AceTimer-3.0");
 
-addon.Locations = {
-	Bag = 0,
-	Bank = 1,
-	Guild = 2,
-	Mailbox = 3,
-};
-
 local Mover, paused, currentLocation;
 local itemCache = {};
 
-local function OnMoveAccept(this)
+local function OnMoveAccept()
 	mod:Pause();
 	Mover:BeginMove(currentLocation, mod.Unpause);
 	
 	InventoriumItemMover:Hide();
 end
 
-local function OnMoveCancel(this)
+local function OnMoveCancel()
 	Mover:ResetQueue();
 	currentLocation = nil;
 	
 	InventoriumItemMover:Hide();
 end
 
+local function UseStorageRefillST(withPrices)
+	local frame = InventoriumItemMover; -- both for speed as code-consistency
+	
+	-- Scrolling table with a list of items to be moved
+	local scrollTableWidth = ( frame.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size
+	local headers = {
+		{
+			["name"] = "Item",
+			["width"] = (scrollTableWidth * ((withPrices and .5) or .60)),
+			["defaultsort"] = "asc",
+			["comparesort"] = function(this, aRow, bRow, column)
+				local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId);
+				local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId);
+				local template = "%d%s";
+				aName = template:format((10 - (aRarity or 10)), (aName or ""):lower());
+				bName = template:format((10 - (bRarity or 10)), (bName or ""):lower());
+				
+				if this.cols[column].sort == "dsc" then
+					return aName > bName;
+				else
+					return aName < bName;
+				end
+			end,
+			["sort"] = "asc", -- when the data is set, use this column so sort the default data
+			["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Item"),
+			["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by item quality then item name."),
+		},
+		{
+			["name"] = "Moving",
+			["width"] = (scrollTableWidth * .15),
+			["align"] = "RIGHT",
+			["defaultsort"] = "dsc",
+			["sortnext"] = 1,
+			["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Moving"),
+			["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of movable items."),
+		},
+		{
+			["name"] = "Available",
+			["width"] = (scrollTableWidth * ((withPrices and .2) or .25)),
+			["align"] = "RIGHT",
+			["defaultsort"] = "dsc",
+			["sortnext"] = 1,
+			["comparesort"] = function(this, aRow, bRow, column)
+				local aAvailablePercent = (this:GetRow(aRow).rowData.available / this:GetRow(aRow).rowData.missing);
+				local bAvailablePercent = (this:GetRow(bRow).rowData.available / this:GetRow(bRow).rowData.missing);
+				
+				if this.cols[column].sort == "dsc" then
+					return aAvailablePercent > bAvailablePercent;
+				else
+					return aAvailablePercent < bAvailablePercent;
+				end
+			end,
+			["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Item"),
+			["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the availibility percentage."),
+		},
+	};
+	if withPrices then
+		table.insert(headers, {
+			["name"] = "Price",
+			["width"] = (scrollTableWidth * .15),
+			["align"] = "RIGHT",
+			["defaultsort"] = "dsc",
+			["sortnext"] = 1,
+			["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Price"),
+			["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the price of this item at this vendor."),
+		});
+	end
+	
+	local proceedButton = {
+		text = "Move Items",
+		tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Move Items"),
+		tooltip = (not addon.db.profile.defaults.hideHelp and "Start moving these items from the bank."),
+		onClick = OnMoveAccept,
+	};
+	local cancelButton = {
+		text = "Cancel",
+		tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Cancel"),
+		tooltip = (not addon.db.profile.defaults.hideHelp and "Do not move anything and close the window."),
+		onClick = OnMoveCancel,
+	};
+	
+	addon:SetFrameSettings("Inventorium Bank Refill", "The items listed below can be refilled from this location, do you wish to move them to your bags?", proceedButton, cancelButton, headers);
+end
+
 function mod:ClearCache()
 	table.wipe(itemCache);
 end
@@ -76,9 +153,9 @@
 		end
 	elseif location == addon.Locations.Guild then
 		for tabId = 1, GetNumGuildBankTabs() do
-			local isViewable = select(3, GetGuildBankTabInfo(tabId));
+			local _, _, isViewable, _, _, remainingWithdrawals = GetGuildBankTabInfo(tabId);
 			
-			if isViewable == 1 then
+			if isViewable and (remainingWithdrawals > 0 or remainingWithdrawals == -1) then
 				local slotId = (MAX_GUILDBANK_SLOTS_PER_TAB or 98); -- start by scanning the last slot
 				
 				while slotId ~= 0 do
@@ -108,6 +185,54 @@
 				end
 			end
 		end
+	elseif location == addon.Locations.Mailbox then
+		for mailIndex = 1, GetInboxNumItems() do
+			-- All mail items
+			
+			for attachIndex = 1, ATTACHMENTS_MAX_RECEIVE do
+				-- All attachments
+				
+				local itemLink = GetInboxItemLink(mailIndex, attachIndex);
+				local itemId = itemLink and addon:GetItemId(itemLink);
+				local itemCount = itemLink and select(3, GetInboxItem(mailIndex, attachIndex));
+				
+				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(mailIndex, attachIndex, itemCount);
+				end
+			end
+		end
+	elseif location == addon.Locations.Merchant then
+		for itemIndex = 1, GetMerchantNumItems() do
+			-- All merchant items
+			
+			local itemLink = GetMerchantItemLink(itemIndex);
+			local itemId = itemLink and addon:GetItemId(itemLink);
+			local _, _, vendorValue, _, numAvailable, _, extendedCost = GetMerchantItemInfo(index);
+			
+			if itemLink and itemId and numAvailable ~= 0 and not extendedCost 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(1, itemIndex, numAvailable, vendorValue);
+			end
+		end
 	else
 		error("Invalid location provided for CacheLocation. Must be Bank or Guild.");
 	end
@@ -125,6 +250,7 @@
 function mod:Scan(location)
 	-- We might pause the scanning when we invoke moves ourself
 	if paused then
+		addon:Debug("Not scanning; paused...");
 		return;
 	end
 	
@@ -133,6 +259,9 @@
 	currentLocation = location;
 	self:CacheLocation(location, true);
 	
+	-- Ensure previous queue isn't remaining
+	Mover:ResetQueue();
+	
 	-- Go through all groups
 	for groupName, values in pairs(addon.db.profile.groups) do
 		local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters");
@@ -153,14 +282,12 @@
 					-- Check how many are available
 					local availableItems = ((itemCache[itemId] and itemCache[itemId].totalCount) or 0);
 					-- Calculate how many we'll be moving (less missing than available? use missing, otherwise use available)
-					local moving = (((missingItems <= availableItems) and missingItems) or availableItems);
+					local moving = (((availableItems == -1 or missingItems <= availableItems) and missingItems) or availableItems);
 					
-					if availableItems > 0 then
-						--addon:Print("Insufficient " .. IdToItemLink(itemId) .. " but this location has " .. availableItems .. " (moving " .. moving .. ")");
+					if availableItems ~= 0 then
+						addon:Debug("Insufficient %s but this location has %s (moving %d)", IdToItemLink(itemId), ((availableItems == -1 and "unlimited") or availableItems), moving);
 						
-						Mover:AddMove(itemId, moving, missingItems, availableItems);
-					else
-						--addon:Print("Insufficient " .. IdToItemLink(itemId));
+						Mover:AddMove(itemId, moving, missingItems, availableItems, itemCache[itemId]:GetVendorPrice());
 					end
 				end
 			end
@@ -171,29 +298,38 @@
 	
 	if Mover:HasMoves() then
 		if addon.db.profile.defaults.autoRefillSkipConfirm then
-			OnMoveAccept(true);
+			OnMoveAccept();
 		else
+			UseStorageRefillST((location == addon.Locations.Merchant));
+			
 			-- This table is never copied, just referenced. It is the same for every row.
 			local columns = {
 				{
-					value = function(data, cols, realrow, column, table)
-						return IdToItemLink(data[realrow].rowData.id);
+					["value"] = function(data, cols, realrow, column, table)
+						return IdToItemLink(data[realrow].rowData.itemId);
 					end,
 				}, -- item
 				{
-					value = function(data, cols, realrow, column, table)
+					["value"] = function(data, cols, realrow, column, table)
 						return data[realrow].rowData.num;
 					end,
 				}, -- moving
 				{
-					value = function(data, cols, realrow, column, table)
+					["value"] = function(data, cols, realrow, column, table)
 						return addon:DisplayItemCount(data[realrow].rowData.available, data[realrow].rowData.missing); -- available / missing
 					end,
-					color = function(data, cols, realrow, column, table)
+					["color"] = function(data, cols, realrow, column, table)
 						return ((data[realrow].rowData.available < data[realrow].rowData.missing) and { r = 1, g = 0, b = 0, a = 1 }) or { r = 1, g = 1, b = 1, a = 1 };
 					end,
 				}, -- missing / available
 			};
+			if location == addon.Locations.Merchant then
+				table.insert(columns, {
+					["value"] = function(data, cols, realrow, column, table)
+						return GetCoinTextureString(data[realrow].rowData.price * data[realrow].rowData.num);
+					end,
+				});
+			end
 			
 			-- Store the list with rows in this
 			local data = {};
@@ -279,8 +415,9 @@
 	
 	-- Get the contents for every tab into our cache
 	for tabId = 1, GetNumGuildBankTabs() do
-		local isViewable = select(3, GetGuildBankTabInfo(tabId));
-		if isViewable == 1 then		
+		local _, _, isViewable, _, _, remainingWithdrawals = GetGuildBankTabInfo(tabId);
+		
+		if isViewable and (remainingWithdrawals > 0 or remainingWithdrawals == -1) then
 			QueryGuildBankTab(tabId);
 		end
 	end
@@ -289,10 +426,79 @@
 	self:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED");
 end
 
+function mod:MERCHANT_SHOW()
+	addon:Debug("Scanner:MERCHANT_SHOW");
+	
+	self:RegisterEvent("MERCHANT_CLOSED");
+	
+	self:Scan(addon.Locations.Merchant);
+end
+
+function mod:MERCHANT_CLOSED()
+	addon:Debug("Scanner:MERCHANT_CLOSED");
+	
+	self:ClearCache();
+	
+	self:UnregisterEvent("MERCHANT_CLOSED");
+	
+	InventoriumItemMover:Hide();
+	Mover:ResetQueue();
+end
+
+--local previousMailCount;
+--function mod:MAIL_SHOW()
+--	addon:Debug("Scanner:MAIL_SHOW");
+--	
+--	self:RegisterEvent("MAIL_INBOX_UPDATE");
+--	self:RegisterEvent("MAIL_CLOSED");
+--	
+--	scanned = nil;
+--	previousMailCount = nil;
+--	
+--	self:Scan(addon.Locations.Mailbox);
+--end
+
+--function mod:MAIL_INBOX_UPDATE()
+--	if not scanned then
+--		addon:Debug("Scanner:MAIL_INBOX_UPDATE");
+--		
+--		local current, total = GetInboxNumItems();
+--		
+--		if not previousMailCount or current > previousMailCount then
+--			-- New mail received
+--			
+--			scanned = true;
+--			
+--			self:Scan(addon.Locations.Mailbox);
+--		end
+--		
+--		-- Also remember the new mailcount when losing items, otherwise deleting item 50 and getting to 50 again wouldn't trigger a re-scan
+--		previousMailCount = current;
+--	else
+--		addon:Debug("Scanner:MAIL_INBOX_UPDATE skipped, already scanned");
+--	end
+--end
+
+--function mod:MAIL_CLOSED()
+--	addon:Debug("Scanner:MAIL_CLOSED");
+--	
+--	previousMailCount = nil;
+--	scanned = nil;
+--	self:ClearCache();
+--	
+--	self:UnregisterEvent("MAIL_INBOX_UPDATE");
+--	self:UnregisterEvent("MAIL_CLOSED");
+--	
+--	InventoriumItemMover:Hide();
+--	Mover:ResetQueue();
+--end
+
 function mod:OnEnable()
 	-- Scan once when the bankframe is opened
 	self:RegisterEvent("BANKFRAME_OPENED");
 	self:RegisterEvent("GUILDBANKFRAME_OPENED");
+--	self:RegisterEvent("MAIL_SHOW");
+	self:RegisterEvent("MERCHANT_SHOW");
 	
 	Mover = addon:GetModule("Mover");
 	
@@ -307,11 +513,16 @@
 	paused = nil;
 	
 	-- Bank
+	self:BANKFRAME_CLOSED();
 	self:UnregisterEvent("BANKFRAME_OPENED");
 	
 	-- Guild
 	self:GUILDBANKFRAME_CLOSED();
 	self:UnregisterEvent("GUILDBANKFRAME_OPENED");
+	
+--	-- Mailbox
+--	self:MAIL_CLOSED();
+--	self:UnregisterEvent("MAIL_SHOW");
 end
 
 function mod:Pause()