Mercurial > wow > inventory
changeset 119:dc6f405c1a5d
Now resizing the mover frame based on text size.
addon.Locations table now uses location names as value, rather than random numbers.
Added proper Merchant restocking support. Please note this currently doesn?t take the bonus queue nor the min crafting queue options into account.
author | Zerotorescue |
---|---|
date | Sat, 15 Jan 2011 17:03:05 +0100 |
parents | de18ef96983b |
children | 00cf4fc1697f |
files | Classes/ContainerItem.class.lua Frames.lua Modules/Mover.lua Modules/Scanner.lua |
diffstat | 4 files changed, 282 insertions(+), 62 deletions(-) [+] |
line wrap: on
line diff
--- a/Classes/ContainerItem.class.lua Sat Jan 15 16:24:39 2011 +0100 +++ b/Classes/ContainerItem.class.lua Sat Jan 15 17:03:05 2011 +0100 @@ -14,6 +14,7 @@ -- Standard info everything needs self.totalCount = 0; self.locations = {}; + self.price = nil; -- usually unused return self; end
--- a/Frames.lua Sat Jan 15 16:24:39 2011 +0100 +++ b/Frames.lua Sat Jan 15 17:03:05 2011 +0100 @@ -89,7 +89,9 @@ titleBackground:SetPoint("TOP", 0, 12); titleBackground:SetWidth(150); titleBackground:SetHeight(40); - + + frame.titleBackground = titleBackground; + local titleBackgroundLeft = frame:CreateTexture(nil, "OVERLAY"); titleBackgroundLeft:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header"); titleBackgroundLeft:SetTexCoord(0.21, 0.31, 0, 0.63); @@ -225,6 +227,8 @@ local frame = InventoriumItemMover; frame.lblTitle:SetText(title); + -- Adjust size for the title background + frame.titleBackground:SetWidth((frame.lblTitle:GetWidth() or 0) + 10); -- 10 pixels margin frame.lblDescription:SetText(description);
--- a/Modules/Mover.lua Sat Jan 15 16:24:39 2011 +0100 +++ b/Modules/Mover.lua Sat Jan 15 17:03:05 2011 +0100 @@ -7,10 +7,11 @@ local movesSource; addon.Locations = { - Bag = 0, - Bank = 1, - Guild = 2, - Mailbox = 3, + ["Bag"] = "Bag", + ["Bank"] = "Bank", + ["Guild"] = "Guild", + ["Mailbox"] = "Mailbox", + ["Merchant"] = "Merchant", }; local ContainerFunctions = { @@ -50,14 +51,27 @@ Synchronous = true, -- wait after every single move Event = "BAG_UPDATE", }, + [addon.Locations.Merchant] = { + GetItemId = function(_, merchantIndex) + return addon:GetItemId(GetMerchantItemLink(merchantIndex)); + end, + PickupItem = function(_, merchantIndex, num) + return BuyMerchantItem(merchantIndex, num); + end, + IsLocked = function() return false; end, + DoNotDrop = true, -- BuyMerchantItem does not support picking up + Burst = true, -- spam buy items, the source can take it + Event = "BAG_UPDATE", + }, }; -function mod:AddMove(itemId, amount, numMissing, numAvailable) +function mod:AddMove(itemId, amount, numMissing, numAvailable, cost) table.insert(queuedMoves, { ["itemId"] = itemId, ["num"] = amount, -- can not be unlimited ["missing"] = numMissing, ["available"] = numAvailable, + ["cost"] = cost, }); end @@ -149,12 +163,42 @@ else -- We want to move the smallest stacks first to keep stuff pretty (and minimize space usage, splitting a stack takes 2 slots, moving something only 1) table.sort(sourceItem.locations, function(a, b) + -- -1 indicates unlimited, this is always more than an actual amount + if a.count == -1 then + return false; + elseif b.count == -1 then + return true; + end + return a.count < b.count; end); for _, itemLocation in pairs(sourceItem.locations) do -- if this location has more items than we need, only move what we need, otherwise move everything in this stack - local movingNum = ((itemLocation.count > singleMove.num and singleMove.num) or itemLocation.count); + -- -1 items indicates unlimited amount, in that case we must cap at missing items + local movingNum = (((itemLocation.count == -1 or itemLocation.count > singleMove.num) and singleMove.num) or itemLocation.count); + + if itemLocation.count == -1 then + -- If the source has an unlimited quantity, makes moves based on the max stacksize + + local stackSize = select(8, GetItemInfo(singleMove.itemId)); -- 8 = stacksize + + if stackSize then + while movingNum > stackSize do + -- Move a single stack size while the amount remaining to be moved is above the stack size num + + table.insert(outgoingMoves, { + ["itemId"] = singleMove.itemId, + ["num"] = stackSize, + ["container"] = itemLocation.container, + ["slot"] = itemLocation.slot, + }); + + movingNum = (movingNum - stackSize); + singleMove.num = (singleMove.num - stackSize); + end + end + end table.insert(outgoingMoves, { ["itemId"] = singleMove.itemId,
--- a/Modules/Scanner.lua Sat Jan 15 16:24:39 2011 +0100 +++ b/Modules/Scanner.lua Sat Jan 15 17:03:05 2011 +0100 @@ -18,6 +18,19 @@ InventoriumItemMover:Hide(); end +local function GetSmallCoinTextureString(coins) + if coins >= 10000000 then + -- When we have1000g, hide silver and copper + coins = (math.ceil(coins / 10000) * 10000); + elseif coins >= 10000 then + -- When we have 1g, hide copper + coins = (math.ceil(coins / 100) * 100); + end + + return GetCoinTextureString(coins); +end + +-- Refill moves window: refill form storage such as the bank, guild bank and mailbox local function UseStorageRefillST() local frame = InventoriumItemMover; -- both for speed as code-consistency @@ -88,7 +101,71 @@ 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); + addon:SetFrameSettings("Inventorium Storage Refill", "The items listed below can be refilled from this location, do you wish to move them to your bags?", proceedButton, cancelButton, headers); +end + +-- Merchant restock window: restock from a merchant by buying items needed +local function UseMerchantRestockST(totalCost) + 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 * .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"] = "Buying", + ["width"] = (scrollTableWidth * .20), + ["align"] = "RIGHT", + ["defaultsort"] = "dsc", + ["sortnext"] = 1, + ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Buying"), + ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of purchasable items."), + }, + { + ["name"] = "Cost", + ["width"] = (scrollTableWidth * .20), + ["align"] = "RIGHT", + ["defaultsort"] = "dsc", + ["sortnext"] = 1, + ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Cost"), + ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the total cost of buying all these items."), + }, + }; + + local proceedButton = { + text = "Purchase Items", + tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Purchase Items"), + tooltip = (not addon.db.profile.defaults.hideHelp and "Start purchasing these items from this merchant."), + 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 purchase anything and close the window."), + onClick = OnMoveCancel, + }; + + addon:SetFrameSettings("Inventorium Merchant Restock", ("The following items can be restocked from this merchant for a total of %s. Do you wish to proceed?"):format(GetSmallCoinTextureString(totalCost)), proceedButton, cancelButton, headers); end function mod:ClearCache() @@ -123,17 +200,17 @@ local itemCount = itemId and select(2, GetContainerItemInfo(bagId, slotId)); if itemId and itemCount and itemCount > 0 then - local itemMove; + local containerItem; 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; + containerItem = addon.ContainerItem:New(); + itemCache[itemId] = containerItem; else -- If we had this item in another slot too - itemMove = itemCache[itemId]; + containerItem = itemCache[itemId]; end - itemMove:AddLocation(bagId, slotId, itemCount); + containerItem:AddLocation(bagId, slotId, itemCount); end -- Continue scanning a different slot @@ -156,17 +233,17 @@ if itemLink and itemId and itemCount and itemCount > 0 then -- If there is actually an item in this slot - local itemMove; + local containerItem; 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; + containerItem = addon.ContainerItem:New(); + itemCache[itemId] = containerItem; else -- If we had this item in another slot too - itemMove = itemCache[itemId]; + containerItem = itemCache[itemId]; end - itemMove:AddLocation(tabId, slotId, itemCount); + containerItem:AddLocation(tabId, slotId, itemCount); end -- Continue scanning a different slot @@ -186,22 +263,46 @@ local itemCount = itemLink and select(3, GetInboxItem(mailIndex, attachIndex)); if itemLink and itemId and itemCount and itemCount > 0 then - local itemMove; + local containerItem; 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; + containerItem = addon.ContainerItem:New(); + itemCache[itemId] = containerItem; else -- If we had this item in another slot too - itemMove = itemCache[itemId]; + containerItem = itemCache[itemId]; end - itemMove:AddLocation(mailIndex, attachIndex, itemCount); + containerItem: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, quantity, numAvailable, _, extendedCost = GetMerchantItemInfo(itemIndex); + + if itemLink and itemId and numAvailable ~= 0 and not extendedCost then + local containerItem; + if not itemCache[itemId] then + -- If this is the first time we see this item, make a new object + containerItem = addon.ContainerItem:New(); + containerItem.price = (vendorValue / quantity); -- remember the price for this item. We assume it's the same for this entire item id + + itemCache[itemId] = containerItem; + else + -- If we had this item in another slot too + containerItem = itemCache[itemId]; + end + + containerItem:AddLocation(1, itemIndex, numAvailable); + end + end else - error("Invalid location provided for CacheLocation. Must be Bank or Guild."); + error("Invalid location provided for CacheLocation."); end if not remember then @@ -229,32 +330,48 @@ -- Ensure previous queue isn't remaining Mover:ResetQueue(); + -- Restock = obtaining more, refill = merely moving local. IsRestock = are we buying/making more? + local isRestock = (location == addon.Locations.Merchant); + -- Go through all groups for groupName, values in pairs(addon.db.profile.groups) do + -- Settings local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters"); local localItemData = addon:GetOptionByKey(groupName, "localItemData"); + local isRefillEnabled = addon:GetOptionByKey(groupName, "autoRefill"); + local requiredItems = ((isRestock and addon:GetOptionByKey(groupName, "restockTarget")) or addon:GetOptionByKey(groupName, "minLocalStock")); - if values.items and trackAt[playerName] and addon:GetOptionByKey(groupName, "autoRefill") and (location ~= addon.Locations.Bank or not localItemData or not localItemData["Bank"]) then - -- Is this character interested in this data? + local isTracked = (trackAt and trackAt[playerName]); -- Is this character interested in this data? + local isConsideredLocal = (localItemData and localItemData[location]); -- if this location was checked as local storage, don't refill from it + + if values.items and isTracked and (isRefillEnabled or isRestock) and not isConsideredLocal then + addon:Debug("Scanning |cff00ff00%s|r", groupName); - local minLocalStock = addon:GetOptionByKey(groupName, "minLocalStock"); - - -- Go through all items for itemId, _ in pairs(values.items) do + -- Find this item in the source + local containerItem = itemCache[itemId]; - -- 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); - -- Calculate how many we'll be moving (less missing than available? use missing, otherwise use available) - local moving = ((missingItems <= availableItems and missingItems) or availableItems); + if containerItem then + -- Only do all the CPU intensive checks if this item is available - if availableItems > 0 then - addon:Debug("Insufficient %s but this location has %d (moving %d)", IdToItemLink(itemId), availableItems, moving); + -- When restocking use the global item count, when refilling use the local + local currentItemCount = ((isRestock and addon:GetItemCount(itemId, groupName)) or addon:GetLocalItemCount(itemId, groupName)); + + -- Check if we have enough items local (but only do so if this location also has enough available) + local missingItems = (requiredItems - currentItemCount); + + if missingItems > 0 then + -- Check how many are available + local availableItems = ((containerItem.totalCount) or 0); + -- Calculate how many we'll be moving (less missing than available? use missing, otherwise use available) + -- -1 available items indicates unlimited amount, in that case we must cap at missing items + local moving = (((availableItems == -1 or missingItems <= availableItems) and missingItems) or availableItems); - Mover:AddMove(itemId, moving, missingItems, availableItems); + if availableItems == -1 or availableItems > 0 then + addon:Debug("Insufficient %s but this location has %d (moving %d)", IdToItemLink(itemId), availableItems, moving); + + Mover:AddMove(itemId, moving, missingItems, availableItems, containerItem.price); + end end end end @@ -267,34 +384,64 @@ if addon.db.profile.defaults.autoRefillSkipConfirm then OnMoveAccept(); else - UseStorageRefillST(); + local moves = Mover:GetMoves(); -- 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.itemId); - end, - }, -- item - { - ["value"] = function(data, cols, realrow, column, table) - return data[realrow].rowData.num; - end, - }, -- moving - { - ["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) - 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 - }; + local columns; + + if isRestock then + local totalCost = 0; + for _, move in pairs(moves) do + totalCost = (totalCost + (move.cost * move.num)); + end + UseMerchantRestockST(totalCost); + + columns = { + { + ["value"] = function(data, cols, realrow, column, table) + return IdToItemLink(data[realrow].rowData.itemId); + end, + }, -- item + { + ["value"] = function(data, cols, realrow, column, table) + return data[realrow].rowData.num; + end, + }, -- buying + { + ["value"] = function(data, cols, realrow, column, table) + return GetSmallCoinTextureString((data[realrow].rowData.cost * data[realrow].rowData.num)); + end, + }, -- cost + }; + else + UseStorageRefillST(); + + columns = { + { + ["value"] = function(data, cols, realrow, column, table) + return IdToItemLink(data[realrow].rowData.itemId); + end, + }, -- item + { + ["value"] = function(data, cols, realrow, column, table) + return data[realrow].rowData.num; + end, + }, -- moving + { + ["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) + 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 + }; + end -- Store the list with rows in this local data = {}; - for i, move in pairs(Mover:GetMoves()) do + for i, move in pairs(moves) do table.insert(data, { ["rowData"] = move, -- this is not a key usually found in a row item and ignored by the library ["cols"] = columns, @@ -386,6 +533,25 @@ 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"); @@ -439,6 +605,7 @@ self:RegisterEvent("BANKFRAME_OPENED"); self:RegisterEvent("GUILDBANKFRAME_OPENED"); self:RegisterEvent("MAIL_SHOW"); + self:RegisterEvent("MERCHANT_SHOW"); Mover = addon:GetModule("Mover"); @@ -463,6 +630,10 @@ -- Mailbox self:MAIL_CLOSED(); self:UnregisterEvent("MAIL_SHOW"); + + -- Merchant + self:MERCHANT_CLOSED(); + self:UnregisterEvent("MERCHANT_SHOW"); end function mod:Pause()