Zerotorescue@17: local addon = select(2, ...); Zerotorescue@13: local mod = addon:NewModule("Queue", "AceEvent-3.0", "AceTimer-3.0"); Zerotorescue@13: Zerotorescue@132: local _G = _G; Zerotorescue@144: local tonumber, tostring, pairs, sformat, smatch, slower, floor, ceil, tinsert, twipe = _G.tonumber, _G.tostring, _G.pairs, _G.string.format, _G.string.match, _G.string.lower, _G.floor, _G.ceil, _G.table.insert, _G.table.wipe; Zerotorescue@132: Zerotorescue@132: local queue, skipped = {}, {}; Zerotorescue@132: Zerotorescue@132: -- 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 Zerotorescue@132: local skipReasons = { Zerotorescue@143: ["NOT_CRAFTABLE"] = { Zerotorescue@143: "|cff3d3d3dNot in profession|r", -- gray Zerotorescue@143: "This item is not part of this profession.", Zerotorescue@143: 0, Zerotorescue@143: }, Zerotorescue@143: ["CAPPED"] = { Zerotorescue@143: "|cff66ff33Fully stocked|r", -- lime/green Zerotorescue@143: "The recorded item count is above or equal to your minimum restock target setting.", Zerotorescue@143: 5, Zerotorescue@143: }, Zerotorescue@143: ["MIN_CRAFTING_QUEUE"] = { Zerotorescue@143: "|cffffff00Min crafting queue|r", -- yellow Zerotorescue@143: "The amount of missing items is below or equal to your \"don't queue if I only miss\"-setting.", Zerotorescue@143: 10, Zerotorescue@143: }, Zerotorescue@143: ["LOW_VALUE"] = { Zerotorescue@143: "|cffff6633Underpriced|r", -- orange Zerotorescue@143: "The recorded auction value of this item is below your price threshold.", Zerotorescue@143: 15, Zerotorescue@143: }, Zerotorescue@143: ["NO_ITEMCOUNT_ADDON"] = { Zerotorescue@143: "|cffff0000No itemcount addon|r", -- red Zerotorescue@143: "No compatible item count could be found.", Zerotorescue@143: 20, Zerotorescue@143: }, Zerotorescue@144: ["REMOVED"] = { -- because this is updated realtime, it is most useful around the top of the list Zerotorescue@144: "|cffff0000Removed|r", -- red Zerotorescue@144: "You manually removed this item from the queue.", Zerotorescue@144: 45, Zerotorescue@144: }, Zerotorescue@144: ["FINISHED"] = { -- because this is updated realtime, it is most useful on the top of the list Zerotorescue@144: "|cff00ff00Just finished|r", -- green Zerotorescue@144: "Just finished restocking this item.", Zerotorescue@144: 50, Zerotorescue@144: }, Zerotorescue@132: }; Zerotorescue@132: Zerotorescue@145: local function Compare(a, b, this, aRow, bRow, columnNo) Zerotorescue@145: if a == b then Zerotorescue@145: local column = this.cols[columnNo]; Zerotorescue@145: if column.sortnext then Zerotorescue@145: local nextcol = this.cols[column.sortnext]; Zerotorescue@145: if not(nextcol.sort) then Zerotorescue@145: if nextcol.comparesort then Zerotorescue@145: return nextcol.comparesort(this, aRow, bRow, column.sortnext); Zerotorescue@145: else Zerotorescue@145: return this:CompareSort(this, bRow, column.sortnext); Zerotorescue@145: end Zerotorescue@145: else Zerotorescue@145: return false; Zerotorescue@145: end Zerotorescue@145: else Zerotorescue@145: return false; Zerotorescue@145: end Zerotorescue@145: elseif (this.cols[columnNo].sort or this.cols[columnNo].defaultsort or "asc") == "dsc" then Zerotorescue@145: return a > b; Zerotorescue@145: else Zerotorescue@145: return a < b; Zerotorescue@145: end Zerotorescue@145: end Zerotorescue@145: Zerotorescue@132: local function MakeQueueWindow() Zerotorescue@143: if not InventoriumQueuer then Zerotorescue@143: addon:CreateQueueFrame(); Zerotorescue@143: Zerotorescue@132: local frame = InventoriumQueuer; -- both for speed as code-consistency Zerotorescue@132: Zerotorescue@132: -- Scrolling table with a list of items to be moved Zerotorescue@132: local scrollTableWidth = ( frame.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size Zerotorescue@132: local headers = { Zerotorescue@132: { Zerotorescue@132: ["name"] = "Item", Zerotorescue@144: ["width"] = (scrollTableWidth * .65), Zerotorescue@132: ["defaultsort"] = "asc", Zerotorescue@145: ["comparesort"] = function(this, aRow, bRow, columnNo) Zerotorescue@132: local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId); Zerotorescue@132: local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId); Zerotorescue@145: aName = sformat("%d%s", (10 - (aRarity or 10)), slower(aName or "")); Zerotorescue@145: bName = sformat("%d%s", (10 - (bRarity or 10)), slower(bName or "")); Zerotorescue@132: Zerotorescue@145: return Compare(aName, bName, this, aRow, bRow, columnNo); Zerotorescue@132: end, Zerotorescue@132: ["sort"] = "asc", -- when the data is set, use this column so sort the default data Zerotorescue@144: ["tooltipTitle"] = "Item", Zerotorescue@144: ["tooltip"] = "Click to sort the list by item quality then item name.", Zerotorescue@132: }, Zerotorescue@132: { Zerotorescue@132: ["name"] = "Amount", Zerotorescue@144: ["width"] = (scrollTableWidth * .15), Zerotorescue@132: ["align"] = "RIGHT", Zerotorescue@132: ["defaultsort"] = "dsc", Zerotorescue@145: ["comparesort"] = function(this, aRow, bRow, columnNo) Zerotorescue@145: local a = this:GetRow(aRow).rowData.amount; Zerotorescue@145: local b = this:GetRow(bRow).rowData.amount; Zerotorescue@145: Zerotorescue@145: return Compare(a, b, this, aRow, bRow, columnNo); Zerotorescue@143: end, Zerotorescue@132: ["sortnext"] = 1, Zerotorescue@144: ["tooltipTitle"] = "Amount needed", Zerotorescue@144: ["tooltip"] = "Click to sort the list by the amount of items needed to reach the restock target.", Zerotorescue@132: }, Zerotorescue@132: { Zerotorescue@132: ["name"] = "Extra", Zerotorescue@144: ["width"] = (scrollTableWidth * .15), Zerotorescue@132: ["align"] = "RIGHT", Zerotorescue@132: ["defaultsort"] = "dsc", Zerotorescue@145: ["comparesort"] = function(this, aRow, bRow, columnNo) Zerotorescue@145: local a = this:GetRow(aRow).rowData.bonus; Zerotorescue@145: local b = this:GetRow(bRow).rowData.bonus; Zerotorescue@145: Zerotorescue@145: return Compare(a, b, this, aRow, bRow, columnNo); Zerotorescue@143: end, Zerotorescue@132: ["sortnext"] = 1, Zerotorescue@144: ["tooltipTitle"] = "Extra items", Zerotorescue@144: ["tooltip"] = "Click to sort the list by the amount of bonus items.", Zerotorescue@144: }, Zerotorescue@144: { Zerotorescue@144: ["name"] = "X", Zerotorescue@144: ["width"] = (scrollTableWidth * .05), Zerotorescue@144: ["align"] = "CENTER", Zerotorescue@144: ["sortnext"] = 1, Zerotorescue@144: ["tooltipTitle"] = "Remove", Zerotorescue@144: ["tooltip"] = "Click any of the fields in this column to remove this item from the queue.", Zerotorescue@144: ["onClick"] = function(rowData) Zerotorescue@144: -- Remove this element from the queue Zerotorescue@144: for index, q in pairs(queue) do Zerotorescue@144: if q == rowData then Zerotorescue@144: table.remove(queue, index); Zerotorescue@144: mod:Skip(q.itemId, skipReasons.REMOVED); Zerotorescue@144: break; Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: -- Rebuild our scrolltable (records were removed and added) Zerotorescue@144: mod:BuildQueue(); Zerotorescue@144: end, Zerotorescue@144: ["color"] = { ["r"] = 1.0, ["g"] = 0.0, ["b"] = 0.0, ["a"] = 1, }, Zerotorescue@132: }, Zerotorescue@132: }; Zerotorescue@132: Zerotorescue@132: local scrollTableWidth = ( InventoriumQueuerUnqueueables.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size Zerotorescue@132: local unqueueablesHeaders = { Zerotorescue@132: { Zerotorescue@132: ["name"] = "Item", Zerotorescue@132: ["width"] = (scrollTableWidth * .6), Zerotorescue@132: ["defaultsort"] = "asc", Zerotorescue@145: ["comparesort"] = function(this, aRow, bRow, columnNo) Zerotorescue@132: local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId); Zerotorescue@132: local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId); Zerotorescue@145: aName = sformat("%d%s", (10 - (aRarity or 10)), slower(aName or "")); Zerotorescue@145: bName = sformat("%d%s", (10 - (bRarity or 10)), slower(bName or "")); Zerotorescue@132: Zerotorescue@145: return Compare(aName, bName, this, aRow, bRow, columnNo); Zerotorescue@132: end, Zerotorescue@144: ["tooltipTitle"] = "Item", Zerotorescue@144: ["tooltip"] = "Click to sort the list by item quality then item name.", Zerotorescue@132: }, Zerotorescue@132: { Zerotorescue@132: ["name"] = "Reason", Zerotorescue@132: ["width"] = (scrollTableWidth * .4), Zerotorescue@132: ["defaultsort"] = "dsc", Zerotorescue@145: ["comparesort"] = function(this, aRow, bRow, columnNo) Zerotorescue@145: local a = this:GetRow(aRow).rowData.reason[3]; Zerotorescue@145: local b = this:GetRow(bRow).rowData.reason[3]; Zerotorescue@145: Zerotorescue@145: return Compare(a, b, this, aRow, bRow, columnNo); Zerotorescue@143: end, Zerotorescue@143: ["sort"] = "dsc", -- when the data is set, use this column to sort the default data Zerotorescue@132: ["sortnext"] = 1, Zerotorescue@144: ["tooltipTitle"] = "Reason", Zerotorescue@144: ["tooltip"] = "Click to sort the list by the reason the items couldn't be queued.", Zerotorescue@132: }, Zerotorescue@132: }; Zerotorescue@132: Zerotorescue@132: local proceedButton = { Zerotorescue@132: text = "Queue", Zerotorescue@144: tooltipTitle = "Queue", Zerotorescue@144: tooltip = "Add these items to the queue of your crafting addon.", Zerotorescue@144: onClick = function() mod:QueueProcess(); end, Zerotorescue@132: }; Zerotorescue@132: local cancelButton = { Zerotorescue@132: text = "Cancel", Zerotorescue@144: tooltipTitle = "Cancel", Zerotorescue@144: tooltip = "Do not queue anything and close the window.", Zerotorescue@144: onClick = function() mod:QueueAbort(); end, Zerotorescue@132: }; Zerotorescue@145: local craftButton = { Zerotorescue@145: text = "Craft", Zerotorescue@145: tooltipTitle = "Craft", Zerotorescue@145: tooltip = "Start crafting the first item.", Zerotorescue@145: onClick = function() mod:StartCrafting(); end, Zerotorescue@145: }; Zerotorescue@132: Zerotorescue@145: addon:SetQueueFrameSettings("Inventorium Queue", "The following items can be added to the queue of your crafting addon. Do you wish to proceed?", proceedButton, cancelButton, craftButton, headers, unqueueablesHeaders); Zerotorescue@132: end Zerotorescue@132: end Zerotorescue@132: Zerotorescue@144: function mod:BuildQueue() Zerotorescue@132: MakeQueueWindow(); Zerotorescue@132: Zerotorescue@132: -- This table is never copied, just referenced. It is the same for every row. Zerotorescue@132: local queueablesColumns = { Zerotorescue@132: { Zerotorescue@132: ["value"] = function(data, cols, realrow, column, table) Zerotorescue@132: return IdToItemLink(data[realrow].rowData.itemId); Zerotorescue@132: end, Zerotorescue@132: }, -- item Zerotorescue@132: { Zerotorescue@132: ["value"] = function(data, cols, realrow, column, table) Zerotorescue@132: return data[realrow].rowData.amount; Zerotorescue@132: end, Zerotorescue@132: }, -- amount Zerotorescue@132: { Zerotorescue@132: ["value"] = function(data, cols, realrow, column, table) Zerotorescue@143: return ((data[realrow].rowData.bonus == 0) and 0) or "+" .. data[realrow].rowData.bonus; Zerotorescue@132: end, Zerotorescue@132: ["color"] = function(data, cols, realrow, column, table) Zerotorescue@132: 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 }; Zerotorescue@132: end, Zerotorescue@132: }, -- extra Zerotorescue@144: { Zerotorescue@144: ["value"] = "X", Zerotorescue@144: }, Zerotorescue@132: }; Zerotorescue@132: Zerotorescue@132: -- Store the list with rows in this Zerotorescue@132: local queueables = {}; Zerotorescue@132: Zerotorescue@132: for _, q in pairs(queue) do Zerotorescue@132: tinsert(queueables, { Zerotorescue@132: ["rowData"] = q, -- this is not a key usually found in a row item and ignored by the library Zerotorescue@132: ["cols"] = queueablesColumns, Zerotorescue@132: }); Zerotorescue@132: end Zerotorescue@132: Zerotorescue@132: -- This table is never copied, just referenced. It is the same for every row. Zerotorescue@132: local unqueueablesColumns = { Zerotorescue@132: { Zerotorescue@132: ["value"] = function(data, cols, realrow, column, table) Zerotorescue@132: return IdToItemLink(data[realrow].rowData.itemId); Zerotorescue@132: end, Zerotorescue@132: }, -- item Zerotorescue@132: { Zerotorescue@132: ["value"] = function(data, cols, realrow, column, table) Zerotorescue@132: return data[realrow].rowData.reason[1]; Zerotorescue@132: end, Zerotorescue@132: }, -- reason Zerotorescue@132: }; Zerotorescue@132: Zerotorescue@132: -- Store the list with rows in this Zerotorescue@132: local unqueueables = {}; Zerotorescue@132: Zerotorescue@132: for _, s in pairs(skipped) do Zerotorescue@132: tinsert(unqueueables, { Zerotorescue@132: ["rowData"] = s, -- this is not a key usually found in a row item and ignored by the library Zerotorescue@132: ["cols"] = unqueueablesColumns, Zerotorescue@132: }); Zerotorescue@132: end Zerotorescue@132: Zerotorescue@132: addon:SetQueueFrameData(queueables, unqueueables); Zerotorescue@132: end Zerotorescue@62: Zerotorescue@144: local function RefreshQueue() Zerotorescue@144: InventoriumQueuer.scrollTable:Refresh(); Zerotorescue@14: end Zerotorescue@14: Zerotorescue@144: do -- Crafting region Zerotorescue@144: -- We are keeping these events within the module object to allow for easier testing and overriding Zerotorescue@144: -- To test: LibStub("AceAddon-3.0"):GetAddon("Inventorium"):GetModule("Queue"):FUNCTION_NAME(param1, param2, ...); Zerotorescue@144: Zerotorescue@144: -- Start crafting the selected skill (or the first in line) Zerotorescue@144: local currentQueueItem; Zerotorescue@144: function mod:StartCrafting(test) Zerotorescue@144: local frame = InventoriumQueuer; -- both for speed as code-consistency Zerotorescue@144: Zerotorescue@144: local selectedIndex = frame.scrollTable:GetSelection(); -- gets realrow index Zerotorescue@144: Zerotorescue@145: addon:Debug("%s was selected.", tostring(selectedIndex)); Zerotorescue@144: Zerotorescue@144: if not selectedIndex then Zerotorescue@144: -- Select the top most element (scrolltable with index of 1 will contain a index of the related realrow of the data table) Zerotorescue@144: selectedIndex = ((frame.scrollTable.sorttable and frame.scrollTable.sorttable[1]) or 1); Zerotorescue@144: Zerotorescue@145: addon:Debug("%s should be the top record.", tostring(selectedIndex)); Zerotorescue@144: end Zerotorescue@144: Zerotorescue@145: local nextQueue = frame.scrollTable.data[selectedIndex].rowData or frame.scrollTable.data[1].rowData; -- if the selected index still fails, try to get the first record Zerotorescue@144: Zerotorescue@144: if nextQueue then Zerotorescue@144: if not test then Zerotorescue@145: self:ResetTradeSkillFilters(); Zerotorescue@145: Zerotorescue@144: -- Initiate spell (test will be used while debugging to fake crafts) Zerotorescue@144: DoTradeSkill(nextQueue.craft.no, ceil(nextQueue.amount / nextQueue.craft.quantity)); Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: -- Remember what we're crafting (saves many loops and/or table storing) Zerotorescue@144: currentQueueItem = nextQueue; Zerotorescue@144: Zerotorescue@144: return; Zerotorescue@144: else Zerotorescue@144: addon:Print("Nothing is available in the craft queue.", addon.Colors.Red); Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: function mod:SpellCastComplete(_, unit, _, _, _, spellId) Zerotorescue@144: -- Sadly the item isn't put in our inventory yet so we don't know how many were made. Zerotorescue@144: -- Because of that we assume the average amount was made, this isn't really the best solution, but it's pretty-est - for now. Zerotorescue@144: Zerotorescue@144: if unit == "player" and currentQueueItem and spellId == currentQueueItem.craft.spellId then Zerotorescue@144: -- Decrease amount remaining by one quantity Zerotorescue@144: currentQueueItem.amount = ( currentQueueItem.amount - currentQueueItem.craft.quantity ); Zerotorescue@144: Zerotorescue@144: if currentQueueItem.amount < 1 then Zerotorescue@144: -- We finished crafting this item Zerotorescue@144: Zerotorescue@144: -- Remove this element from the queue Zerotorescue@144: for index, q in pairs(queue) do Zerotorescue@144: if q == currentQueueItem then Zerotorescue@144: table.remove(queue, index); Zerotorescue@144: break; Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: -- Add this queue item to the "Unqueueables" frame - we finished it so it is no longer queueable and the user may become interested Zerotorescue@144: self:Skip(currentQueueItem.itemId, skipReasons.FINISHED); Zerotorescue@144: Zerotorescue@144: -- We are no longer crafting anything Zerotorescue@144: currentQueueItem = nil; Zerotorescue@144: Zerotorescue@144: -- Rebuild our scrolltable (records were removed and added) Zerotorescue@144: mod:BuildQueue(); Zerotorescue@144: else Zerotorescue@144: -- Refresh the scrolltable (update item counts) Zerotorescue@144: RefreshQueue(); Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: function mod:SpellCastStart(_, unit, _, _, _, spellId) Zerotorescue@144: if unit == "player" and currentQueueItem and spellId == currentQueueItem.craft.spellId then Zerotorescue@144: self.isProcessing = true; Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: function mod:SpellCastStop(_, unit, _, _, _, spellId) Zerotorescue@144: if unit == "player" and currentQueueItem and spellId == currentQueueItem.craft.spellId then Zerotorescue@144: self.isProcessing = nil; Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: function mod:SpellCastFailed(_, unit, _, _, _, spellId) Zerotorescue@144: if unit == "player" and currentQueueItem and spellId == currentQueueItem.craft.spellId then Zerotorescue@144: currentQueueItem = nil; Zerotorescue@144: self.isProcessing = nil; Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: --@debug@ Zerotorescue@144: function TestCraft() Zerotorescue@144: mod:StartCrafting(true); Zerotorescue@144: mod:SpellCastComplete("UNIT_SPELLCAST_SUCCEEDED", "player", "Relentless Earthsiege Diamond", nil, nil, 55400); Zerotorescue@144: end Zerotorescue@144: --@end-debug@ Zerotorescue@14: end Zerotorescue@14: Zerotorescue@144: function mod:QueueProcess() Zerotorescue@144: -- Prepare a table with all possible tradeskill craftables Zerotorescue@144: local craftables = self:GetTradeskillCraftables(); Zerotorescue@144: Zerotorescue@144: for _, q in pairs(queue) do Zerotorescue@144: if craftables[q.itemId] then Zerotorescue@144: if self:QueueWithAddon(craftables[q.itemId].no, ceil(q.amount / craftables[q.itemId].quantity), q.groupName) == -1 then Zerotorescue@144: addon:Print("Couldn't queue, no supported crafting addon found.", addon.Colors.Red); Zerotorescue@144: Zerotorescue@144: self:QueueAbort(); Zerotorescue@144: return; Zerotorescue@144: else Zerotorescue@144: -- Update the crafted-item count Zerotorescue@144: for groupName, values in pairs(addon.db.profile.groups) do Zerotorescue@144: if values.items and values.items[q.itemId] then Zerotorescue@144: values.items[q.itemId] = (tonumber(values.items[q.itemId]) or 0) + 1; Zerotorescue@144: break; Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: else Zerotorescue@144: addon:Debug("Lost %s", IdToItemLink(q.itemId)); Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: self:QueueHide(); Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: function mod:QueueAbort() Zerotorescue@144: self:QueueHide(); Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: function mod:QueueHide() Zerotorescue@144: twipe(queue); Zerotorescue@144: twipe(skipped); Zerotorescue@144: Zerotorescue@144: if InventoriumQueuer then Zerotorescue@144: InventoriumQueuer:Hide(); Zerotorescue@144: end Zerotorescue@13: end Zerotorescue@13: Zerotorescue@13: function mod:QueueAll() Zerotorescue@132: -- Prepare a table with all possible tradeskill craftables Zerotorescue@132: local craftables = self:GetTradeskillCraftables(); Zerotorescue@132: Zerotorescue@132: -- Forget old queue Zerotorescue@132: twipe(queue); Zerotorescue@132: twipe(skipped); Zerotorescue@132: Zerotorescue@14: local playerName = UnitName("player"); Zerotorescue@14: Zerotorescue@14: -- Go through all groups Zerotorescue@61: for groupName, values in pairs(addon.db.profile.groups) do Zerotorescue@62: local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters"); Zerotorescue@14: Zerotorescue@14: if trackAt[playerName] then Zerotorescue@132: self:QueueGroup(groupName, craftables); Zerotorescue@13: end Zerotorescue@13: end Zerotorescue@132: Zerotorescue@144: mod:BuildQueue(); Zerotorescue@13: end Zerotorescue@13: Zerotorescue@149: function mod:QueueGroup(groupName, craftables, displayQueue) Zerotorescue@132: -- Prepare a table with all possible tradeskill craftables Zerotorescue@132: if not craftables then Zerotorescue@132: craftables = self:GetTradeskillCraftables(); -- nil when no tradeskill window is open Zerotorescue@132: end Zerotorescue@132: Zerotorescue@132: if not craftables then Zerotorescue@132: addon:Print("No tradeskill window detected.", addon.Colors.Red); Zerotorescue@132: return; Zerotorescue@132: elseif not addon.db.profile.groups[groupName] then Zerotorescue@132: addon:Print(sformat("Tried to queue items from a group named \"%s\", but no such group exists.", groupName), addon.Colors.Red); Zerotorescue@132: return; Zerotorescue@132: elseif not addon.db.profile.groups[groupName].items then Zerotorescue@132: addon:Debug("This group (%s) has no items.", groupName); Zerotorescue@14: return; Zerotorescue@14: end Zerotorescue@14: Zerotorescue@132: -- Retrieve group settings Zerotorescue@146: local restockTarget = addon:GetOptionByKey(groupName, "restockTarget"); Zerotorescue@146: local bonusQueue = addon:GetOptionByKey(groupName, "bonusQueue"); Zerotorescue@143: local minCraftingQueue = floor( addon:GetOptionByKey(groupName, "minCraftingQueue") * addon:GetOptionByKey(groupName, "restockTarget") ); -- If the minCraftingQueue is 5% and restockTarget is 60, this will result in 3 Zerotorescue@132: local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold"); Zerotorescue@13: Zerotorescue@140: for itemId, count in pairs(addon.db.profile.groups[groupName].items) do Zerotorescue@132: if craftables[itemId] then Zerotorescue@146: local currentStock = addon:GetItemCount(itemId, groupName); Zerotorescue@31: Zerotorescue@146: if currentStock >= 0 then Zerotorescue@146: -- Current stock will be -1 when no itemcount addon was found Zerotorescue@31: Zerotorescue@146: -- Calculate the amount to be queued Zerotorescue@146: local amount = ( restockTarget - currentStock ); Zerotorescue@146: local bonus = 0; Zerotorescue@17: Zerotorescue@146: if currentStock == 0 and bonusQueue > 0 then Zerotorescue@146: -- If we have none left and the bonus queue is enabled, modify the amount to be queued Zerotorescue@31: Zerotorescue@146: bonus = floor( ( amount * ( bonusQueue ) ) + .5 ); -- round Zerotorescue@146: Zerotorescue@146: -- Update amount Zerotorescue@146: amount = (amount + bonus); Zerotorescue@146: end Zerotorescue@146: Zerotorescue@146: if amount >= minCraftingQueue then Zerotorescue@146: -- If we are queuing at least one AND more than the minimum amount, then proceed Zerotorescue@146: Zerotorescue@146: -- Get auction value when it is relevant Zerotorescue@146: local value = (priceThreshold ~= 0 and addon:GetAuctionValue(IdToItemLink(itemId), groupName)); Zerotorescue@146: Zerotorescue@146: if priceThreshold == 0 or value == -1 or value >= priceThreshold then Zerotorescue@146: -- If no price threshold is set or the auction value is equal to or larger than the price threshold, then proceed Zerotorescue@146: Zerotorescue@146: self:Queue(itemId, amount, bonus, craftables[itemId], groupName); Zerotorescue@146: else Zerotorescue@146: self:Skip(itemId, skipReasons.LOW_VALUE); Zerotorescue@146: --addon:Debug("%s is valued at %s while %s is needed", IdToItemLink(itemId), tostring(value), tostring(priceThreshold)); Zerotorescue@146: end Zerotorescue@132: else Zerotorescue@146: if amount <= 0 then Zerotorescue@146: -- less than 0 = (over)capped Zerotorescue@146: self:Skip(itemId, skipReasons.CAPPED); Zerotorescue@146: else Zerotorescue@146: -- more than 0 = below min crafting queue Zerotorescue@146: self:Skip(itemId, skipReasons.MIN_CRAFTING_QUEUE); Zerotorescue@146: end Zerotorescue@14: end Zerotorescue@14: else Zerotorescue@146: -- No item count addon Zerotorescue@146: self:Skip(itemId, skipReasons.NO_ITEMCOUNT_ADDON); Zerotorescue@146: addon:Print("No usable itemcount addon found."); Zerotorescue@146: return; Zerotorescue@13: end Zerotorescue@132: else Zerotorescue@132: self:Skip(itemId, skipReasons.NOT_CRAFTABLE); Zerotorescue@13: end Zerotorescue@13: end Zerotorescue@149: Zerotorescue@149: if displayQueue then Zerotorescue@149: mod:BuildQueue(); Zerotorescue@149: end Zerotorescue@13: end Zerotorescue@13: Zerotorescue@143: function mod:Queue(itemId, amount, bonus, craft, groupName) Zerotorescue@132: tinsert(queue, { Zerotorescue@143: ["itemId"] = itemId, -- needed to display the queued item in the queue window Zerotorescue@143: ["amount"] = amount, -- the amount missing Zerotorescue@143: ["bonus"] = bonus, -- the amount queued by the bonus queue Zerotorescue@143: ["craft"] = craft, -- (craftable) - needed to find the proper element of this parent array when crafting has finished (spellId), and to update the numCrafts (quantity) Zerotorescue@143: ["groupName"] = groupName, -- related group, needed to find the selected crafting addon Zerotorescue@132: }); Zerotorescue@132: end Zerotorescue@132: Zerotorescue@132: function mod:Skip(itemId, reason) Zerotorescue@132: tinsert(skipped, { Zerotorescue@132: ["itemId"] = itemId, Zerotorescue@132: ["reason"] = reason, Zerotorescue@132: }); Zerotorescue@132: end Zerotorescue@132: Zerotorescue@132: function mod:QueueWithAddon(tradeSkillIndex, amount, group) Zerotorescue@132: -- Sanity check Zerotorescue@13: tradeSkillIndex = tonumber(tradeSkillIndex); Zerotorescue@13: amount = tonumber(amount); Zerotorescue@13: Zerotorescue@23: local selectedExternalAddon = addon:GetOptionByKey(group, "craftingAddon"); Zerotorescue@23: Zerotorescue@23: if addon.supportedAddons.crafting[selectedExternalAddon] and addon.supportedAddons.crafting[selectedExternalAddon].IsEnabled() then Zerotorescue@13: -- Try to use the default auction pricing addon Zerotorescue@13: Zerotorescue@23: return addon.supportedAddons.crafting[selectedExternalAddon].Queue(tradeSkillIndex, amount); Zerotorescue@13: else Zerotorescue@13: -- Default not available, get the first one then Zerotorescue@13: Zerotorescue@13: for name, value in pairs(addon.supportedAddons.crafting) do Zerotorescue@13: if value.IsEnabled() then Zerotorescue@13: return value.Queue(tradeSkillIndex, amount); Zerotorescue@13: end Zerotorescue@13: end Zerotorescue@13: end Zerotorescue@13: Zerotorescue@132: return -1; Zerotorescue@13: end Zerotorescue@132: Zerotorescue@144: function mod:OnEnable() Zerotorescue@144: -- Register our own slash commands Zerotorescue@144: -- /im queue Zerotorescue@144: addon:RegisterSlash(function() Zerotorescue@144: mod:QueueAll(); Zerotorescue@144: end, { "q", "que", "queue" }, "|Hfunction:InventoriumCommandHandler:queue|h|cff00fff7/im queue|r|h (or /im q) - Queue all items found in the currently opened profession that are within the groups tracked at this current character."); Zerotorescue@144: Zerotorescue@144: self:RegisterMessage("IM_QUEUE_ALL"); Zerotorescue@144: self:RegisterMessage("IM_QUEUE_GROUP"); Zerotorescue@144: Zerotorescue@144: -- When closing the tradeskill window also hide the queue screen. Zerotorescue@144: -- We scan the recipes right before queueing not when the tradeskill is opened because we really don't need it at any other time. Zerotorescue@144: self:RegisterEvent("TRADE_SKILL_CLOSE", "QueueAbort"); Zerotorescue@144: Zerotorescue@144: -- Crafting events Zerotorescue@144: self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED", "SpellCastComplete"); Zerotorescue@144: Zerotorescue@144: -- Button en-/disabling Zerotorescue@144: self:RegisterEvent("UNIT_SPELLCAST_START", "SpellCastStart"); Zerotorescue@144: self:RegisterEvent("UNIT_SPELLCAST_STOP", "SpellCastStop"); Zerotorescue@144: Zerotorescue@144: self:RegisterEvent("UNIT_SPELLCAST_FAILED", "SpellCastFailed"); Zerotorescue@144: self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED", "SpellCastFailed"); Zerotorescue@144: end Zerotorescue@132: Zerotorescue@144: do -- Addon messages (Ace3) region Zerotorescue@144: function mod:IM_QUEUE_ALL() Zerotorescue@144: self:QueueAll(); Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: function mod:IM_QUEUE_GROUP(event, groupName) Zerotorescue@149: self:QueueGroup(groupName, nil, true); Zerotorescue@132: end Zerotorescue@132: end Zerotorescue@132: Zerotorescue@144: do -- Trade skill recipes region Zerotorescue@145: -- Reset all filters so no crafts are hidden Zerotorescue@145: function mod:ResetTradeSkillFilters() Zerotorescue@145: SetTradeSkillSubClassFilter(0, 1, 1); Zerotorescue@145: SetTradeSkillItemNameFilter(""); Zerotorescue@145: SetTradeSkillItemLevelFilter(0, 0); Zerotorescue@145: TradeSkillOnlyShowSkillUps(false); Zerotorescue@145: TradeSkillOnlyShowMakeable(false); Zerotorescue@145: Zerotorescue@145: -- Expand all categories so no crafts are hidden Zerotorescue@144: for i = GetNumTradeSkills(), 1, -1 do Zerotorescue@144: local _, skillType, _, isExpanded = GetTradeSkillInfo(i); Zerotorescue@144: Zerotorescue@144: if skillType == "header" and not isExpanded then Zerotorescue@144: ExpandTradeSkillSubClass(i); Zerotorescue@132: end Zerotorescue@132: end Zerotorescue@132: end Zerotorescue@144: Zerotorescue@144: -- Get all craftable items into a table. Each record contains "no", "spellId" and "quantity". The last is the average amount made per craft. Zerotorescue@144: function mod:GetTradeskillCraftables() Zerotorescue@144: local craftables = {}; Zerotorescue@144: Zerotorescue@144: if GetTradeSkillLine() ~= "UNKNOWN" then Zerotorescue@145: self:ResetTradeSkillFilters(); Zerotorescue@144: Zerotorescue@144: -- Cache all craftable items Zerotorescue@144: for i = 1, GetNumTradeSkills() do Zerotorescue@144: local itemLink = GetTradeSkillItemLink(i); Zerotorescue@144: Zerotorescue@144: if itemLink then Zerotorescue@144: local itemId = addon:GetItemId(itemLink); Zerotorescue@144: if not itemId then Zerotorescue@144: -- If this isn't an item, it can only be an enchant instead Zerotorescue@144: itemId = tonumber(smatch(itemLink, "|Henchant:([-0-9]+)|h")); Zerotorescue@144: Zerotorescue@144: if itemId and addon.scrollIds[itemId] then Zerotorescue@144: -- Only if this scroll id actually exists Zerotorescue@144: itemId = addon.scrollIds[itemId]; -- change enchantIds into scrollIds Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: -- 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) Zerotorescue@144: local minMade, maxMade = GetTradeSkillNumMade(i); Zerotorescue@144: local average = ((minMade == maxMade) and minMade) or ((minMade + maxMade) / 2); Zerotorescue@144: Zerotorescue@144: local recipeLink = GetTradeSkillRecipeLink(i); Zerotorescue@144: local spellId = tonumber(smatch(recipeLink, "|Henchant:([-0-9]+)|h")); Zerotorescue@144: Zerotorescue@144: craftables[itemId] = { Zerotorescue@144: ["no"] = i, -- needed to start crafting at the end of the entire cycle Zerotorescue@144: ["spellId"] = spellId, -- needed to detect creation of this item was finished Zerotorescue@144: ["quantity"] = average, -- needed to calculate the amount of crafts Zerotorescue@144: }; Zerotorescue@144: end Zerotorescue@144: end Zerotorescue@144: else Zerotorescue@144: return; Zerotorescue@144: end Zerotorescue@144: Zerotorescue@144: return craftables; Zerotorescue@144: end Zerotorescue@132: end