Mercurial > wow > inventory
diff Modules/Queue.lua @ 132:8460855e3d90
Rewrote queueing module to insert a GUI.
Minor mover window changes.
author | Zerotorescue |
---|---|
date | Tue, 18 Jan 2011 00:30:15 +0100 |
parents | 67bd5057ecb7 |
children | 396c2960d54d |
line wrap: on
line diff
--- a/Modules/Queue.lua Tue Jan 18 00:28:24 2011 +0100 +++ b/Modules/Queue.lua Tue Jan 18 00:30:15 2011 +0100 @@ -1,7 +1,209 @@ local addon = select(2, ...); local mod = addon:NewModule("Queue", "AceEvent-3.0", "AceTimer-3.0"); -local pairs = pairs; +local _G = _G; +local tonumber, pairs, sformat, smatch, floor, ceil, tinsert, twipe = _G.tonumber, _G.pairs, _G.string.format, _G.string.match, _G.floor, _G.ceil, _G.table.insert, _G.table.wipe; + +local queue, skipped = {}, {}; + +-- strings are passed by reference, so it takes no additional memory if one string was used in a thousand tables compared to any other reference type +local skipReasons = { + ["LOW_VALUE"] = { "|cffff6633Underpriced|r", "The recorded auction value of this item is below your price threshold." }, + ["CAPPED"] = { "|cff66ff33Fully stocked|r", "The recorded item count is above or equal to your minimum global stock setting." }, + ["MIN_CRAFTING_QUEUE"] = { "|cffffff00Min crafting queue|r", "The amount of missing items is below or equal to your \"don't queue if I only miss\"-setting." }, + ["NO_ITEMCOUNT_ADDON"] = { "|cffff0000No itemcount addon|r", "No compatible item count could be found." }, + ["NOT_CRAFTABLE"] = { "|cff3d3d3dNot in profession|r", "This item is not part of this profession." }, +}; + +local function OnQueueCancel() + twipe(queue); + twipe(skipped); + + InventoriumQueuer:Hide(); +end + +local function OnQueueAccept() + -- Prepare a table with all possible tradeskill craftables + local craftables = mod:GetTradeskillCraftables(); + + for _, q in pairs(queue) do + if craftables[q.itemId] then + if mod:QueueWithAddon(craftables[q.itemId].no, ceil(q.amount / craftables[q.itemId].quantity), q.groupName) == -1 then + addon:Print("Couldn't queue, no supported crafting addon found.", addon.Colors.Red); + + OnQueueCancel(); + return; + end + else + addon:Debug("Lost %s", IdToItemLink(q.itemId)); + end + end + + twipe(queue); + twipe(skipped); + + InventoriumQueuer:Hide(); +end + +local function MakeQueueWindow() + do + local frame = InventoriumQueuer; -- 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"] = "Amount", + ["width"] = (scrollTableWidth * .20), + ["align"] = "RIGHT", + ["defaultsort"] = "dsc", + ["sortnext"] = 1, + ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Amount"), + ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of items to be queued."), + }, + { + ["name"] = "Extra", + ["width"] = (scrollTableWidth * .20), + ["align"] = "RIGHT", + ["defaultsort"] = "dsc", + ["sortnext"] = 1, + ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Extra"), + ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of bonus items."), + }, + }; + + local scrollTableWidth = ( InventoriumQueuerUnqueueables.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size + local unqueueablesHeaders = { + { + ["name"] = "Item", + ["width"] = (scrollTableWidth * .6), + ["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"] = "Reason", + ["width"] = (scrollTableWidth * .4), + ["defaultsort"] = "dsc", + ["sortnext"] = 1, + ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Reason"), + ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the reason the items couldn't be queued."), + }, + }; + + local proceedButton = { + text = "Queue", + tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Queue"), + tooltip = (not addon.db.profile.defaults.hideHelp and "Add these items to the queue of your crafting addon."), + onClick = OnQueueAccept, + }; + local cancelButton = { + text = "Cancel", + tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Cancel"), + tooltip = (not addon.db.profile.defaults.hideHelp and "Do not queue anything and close the window."), + onClick = OnQueueCancel, + }; + + addon:SetQueueFrameSettings("Inventorium Queue", "The following items can be added to the queue of your crafting addon. Do you wish to proceed?", proceedButton, cancelButton, headers, unqueueablesHeaders); + end +end + +local function DisplayQueue() + MakeQueueWindow(); + + -- This table is never copied, just referenced. It is the same for every row. + local queueablesColumns = { + { + ["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.amount; + end, + }, -- amount + { + ["value"] = function(data, cols, realrow, column, table) + return (data[realrow].rowData.bonus == 0 and 0) or "+" .. data[realrow].rowData.bonus; + end, + ["color"] = function(data, cols, realrow, column, table) + return ((data[realrow].rowData.bonus == 0) and { r = 1, g = 1, b = 1, a = 0.5 }) or { r = 0, g = 1, b = 0, a = 1 }; + end, + }, -- extra + }; + + -- Store the list with rows in this + local queueables = {}; + + for _, q in pairs(queue) do + tinsert(queueables, { + ["rowData"] = q, -- this is not a key usually found in a row item and ignored by the library + ["cols"] = queueablesColumns, + }); + end + + -- This table is never copied, just referenced. It is the same for every row. + local unqueueablesColumns = { + { + ["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.reason[1]; + end, + }, -- reason + }; + + -- Store the list with rows in this + local unqueueables = {}; + + for _, s in pairs(skipped) do + tinsert(unqueueables, { + ["rowData"] = s, -- this is not a key usually found in a row item and ignored by the library + ["cols"] = unqueueablesColumns, + }); + end + + addon:SetQueueFrameData(queueables, unqueueables); +end function mod:OnEnable() -- Register our own slash commands @@ -12,6 +214,10 @@ self:RegisterMessage("IM_QUEUE_ALL"); self:RegisterMessage("IM_QUEUE_GROUP"); + + if not InventoriumQueuer then + addon:CreateQueueFrame(OnMoveAccept, OnMoveCancel); + end end function mod:IM_QUEUE_ALL() @@ -23,6 +229,13 @@ end function mod:QueueAll() + -- Prepare a table with all possible tradeskill craftables + local craftables = self:GetTradeskillCraftables(); + + -- Forget old queue + twipe(queue); + twipe(skipped); + local playerName = UnitName("player"); -- Go through all groups @@ -30,108 +243,108 @@ local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters"); if trackAt[playerName] then - self:QueueGroup(groupName); + self:QueueGroup(groupName, craftables); end end + + DisplayQueue(); end -function mod:QueueGroup(groupName) - if not addon.db.profile.groups[groupName] then - addon:Print(("Tried to queue items from a group named \"%s\", but no such group exists."):format(groupName), addon.Colors.Red); +function mod:QueueGroup(groupName, craftables) + -- Prepare a table with all possible tradeskill craftables + if not craftables then + craftables = self:GetTradeskillCraftables(); -- nil when no tradeskill window is open + end + + if not craftables then + addon:Print("No tradeskill window detected.", addon.Colors.Red); + return; + elseif not addon.db.profile.groups[groupName] then + addon:Print(sformat("Tried to queue items from a group named \"%s\", but no such group exists.", groupName), addon.Colors.Red); + return; + elseif not addon.db.profile.groups[groupName].items then + addon:Debug("This group (%s) has no items.", groupName); return; end - local temp = {}; + -- Retrieve group settings + local restockTarget = addon:GetOptionByKey(groupName, "restockTarget"); + local bonusQueue = addon:GetOptionByKey(groupName, "bonusQueue"); + local minCraftingQueue = floor( addon:GetOptionByKey(groupName, "minCraftingQueue") * restockTarget ); -- If the minCraftingQueue is 5% and restockTarget is 60, this will result in 3 + local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold"); - local tradeskillName, currentLevel, maxLevel = GetTradeSkillLine(); - - if tradeskillName ~= "UNKNOWN" then - -- Go through all trade skills for the profession - for i = 1, GetNumTradeSkills() do - -- Process every single tradeskill - self:ProcessTradeSkill(i, groupName, temp); - end - end - - if addon.db.profile.groups[groupName].items then - for itemId, _ in pairs(addon.db.profile.groups[groupName].items) do - if not temp[itemId] then - local itemLink = select(2, GetItemInfo(itemId)); - - addon:Print(("Couldn't queue %s (not part of this profession)"):format((itemLink or itemId or "???")), addon.Colors.Orange); - end - end - end -end - -function mod:ProcessTradeSkill(i, groupName, temp) - -- Try to retrieve the itemlink, this will be nil if current item is a group instead - local itemLink = GetTradeSkillItemLink(i); - - if itemLink then - local itemId = addon:GetItemId(itemLink); - if not itemId then - -- If this isn't an item, it can only be an enchant instead - itemId = tonumber(itemLink:match("|Henchant:([-0-9]+)|h")); - - itemId = addon.scrollIds[itemId]; -- change enchantIds into scrollIds - end - - if addon.db.profile.groups[groupName].items and addon.db.profile.groups[groupName].items[itemId] then - -- This item is in this group, queue it! - - if temp then - -- Remember which items have been processed - temp[itemId] = true; - end - + for itemId in pairs(addon.db.profile.groups[groupName].items) do + if craftables[itemId] then local currentStock = addon:GetItemCount(itemId, groupName); if currentStock >= 0 then -- Current stock will be -1 when no itemcount addon was found - -- Retrieve group settings - local restockTarget = addon:GetOptionByKey(groupName, "restockTarget"); - local bonusQueue = addon:GetOptionByKey(groupName, "bonusQueue"); - local minCraftingQueue = floor( addon:GetOptionByKey(groupName, "minCraftingQueue") * restockTarget ); -- If the minCraftingQueue is 5% and restockTarget is 60, this will result in 3 - -- Calculate the amount to be queued local amount = ( restockTarget - currentStock ); + local bonus = 0; if currentStock == 0 and bonusQueue > 0 then -- If we have none left and the bonus queue is enabled, modify the amount to be queued - amount = floor( ( amount * ( bonusQueue + 1 ) ) + .5 ); -- round + bonus = floor( ( amount * ( bonusQueue ) ) + .5 ); -- round + + -- Update amount + amount = (amount + bonus); end if amount > 0 and amount >= minCraftingQueue then -- If we are queueing at least one AND more than the minimum amount, then proceed -- Auction value settings - local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold"); local value = (priceThreshold ~= 0 and addon:GetAuctionValue(itemLink, groupName)); if priceThreshold == 0 or value == -1 or value >= priceThreshold then -- If no price threshold is set or the auction value is equal to or larger than the price threshold, then proceed - self:Queue(i, amount, groupName); - - addon:Print(("Queued %d of %s"):format(amount, itemLink)); + self:Queue(itemId, amount, bonus, groupName); + else + self:Skip(itemId, skipReasons.LOW_VALUE); + end + else + if amount <= 0 then + self:Skip(itemId, skipReasons.CAPPED); + else + self:Skip(itemId, skipReasons.MIN_CRAFTING_QUEUE); end end else + self:Skip(itemId, skipReasons.NO_ITEMCOUNT_ADDON); addon:Print("No usable itemcount addon found."); + return; end + else + self:Skip(itemId, skipReasons.NOT_CRAFTABLE); end end end -function mod:Queue(tradeSkillIndex, amount, group) +function mod:Queue(itemId, amount, bonus, groupName) + tinsert(queue, { + ["itemId"] = itemId, + ["amount"] = amount, + ["bonus"] = bonus, + ["groupName"] = groupName, + }); +end + +function mod:Skip(itemId, reason) + tinsert(skipped, { + ["itemId"] = itemId, + ["reason"] = reason, + }); +end + +function mod:QueueWithAddon(tradeSkillIndex, amount, group) + -- Sanity check tradeSkillIndex = tonumber(tradeSkillIndex); amount = tonumber(amount); - if not tradeSkillIndex or not amount then return; end - local selectedExternalAddon = addon:GetOptionByKey(group, "craftingAddon"); if addon.supportedAddons.crafting[selectedExternalAddon] and addon.supportedAddons.crafting[selectedExternalAddon].IsEnabled() then @@ -148,5 +361,52 @@ end end - return -2; + return -1; end + +-- Expand all categories +local function ExpandSubClasses() + for i = GetNumTradeSkills(), 1, -1 do + local _, skillType, _, isExpanded = GetTradeSkillInfo(i); + + if skillType == "header" and not isExpanded then + ExpandTradeSkillSubClass(i); + end + end +end + +function mod:GetTradeskillCraftables() + local craftables = {}; + + if GetTradeSkillLine() ~= "UNKNOWN" then + ExpandSubClasses(); + + -- Cache all craftable items + for i = 1, GetNumTradeSkills() do + local itemLink = GetTradeSkillItemLink(i); + + if itemLink then + local itemId = addon:GetItemId(itemLink); + if not itemId then + -- If this isn't an item, it can only be an enchant instead + itemId = tonumber(smatch(itemLink, "|Henchant:([-0-9]+)|h")); + + itemId = addon.scrollIds[itemId]; -- change enchantIds into scrollIds + end + + -- Remember the average amount of items created per craft (doesn't need to be a round number, since we multiply this by the amount of items to be queued we're better off rounding at that time) + local minMade, maxMade = GetTradeSkillNumMade(i); + local average = ((minMade == maxMade) and minMade) or ((minMade + maxMade) / 2); + + craftables[itemId] = { + ["no"] = i, + ["quantity"] = average, + }; + end + end + else + return; + end + + return craftables; +end