annotate Modules/Queue.lua @ 176:26c750a10b14

Renamed Inventorium debug channel to IMDebug (so it?s easier to recognize only IM changes, not from other addons), write /im d to register this new channel. Implemented stock alerts. Added ?don?t alert at characters? option which allows you to track groups at characters without being bothered about low stock. You can change the speed of the stock alert at the extra config tab.
author Zerotorescue
date Sun, 30 Jan 2011 15:39:18 +0100
parents da28be6ccd31
children ba5ddc4448dd
rev   line source
Zerotorescue@17 1 local addon = select(2, ...);
Zerotorescue@13 2 local mod = addon:NewModule("Queue", "AceEvent-3.0", "AceTimer-3.0");
Zerotorescue@13 3
Zerotorescue@132 4 local _G = _G;
Zerotorescue@144 5 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 6
Zerotorescue@132 7 local queue, skipped = {}, {};
Zerotorescue@132 8
Zerotorescue@132 9 -- 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 10 local skipReasons = {
Zerotorescue@143 11 ["NOT_CRAFTABLE"] = {
Zerotorescue@143 12 "|cff3d3d3dNot in profession|r", -- gray
Zerotorescue@143 13 "This item is not part of this profession.",
Zerotorescue@143 14 0,
Zerotorescue@143 15 },
Zerotorescue@143 16 ["CAPPED"] = {
Zerotorescue@143 17 "|cff66ff33Fully stocked|r", -- lime/green
Zerotorescue@143 18 "The recorded item count is above or equal to your minimum restock target setting.",
Zerotorescue@143 19 5,
Zerotorescue@143 20 },
Zerotorescue@143 21 ["MIN_CRAFTING_QUEUE"] = {
Zerotorescue@143 22 "|cffffff00Min crafting queue|r", -- yellow
Zerotorescue@143 23 "The amount of missing items is below or equal to your \"don't queue if I only miss\"-setting.",
Zerotorescue@143 24 10,
Zerotorescue@143 25 },
Zerotorescue@143 26 ["LOW_VALUE"] = {
Zerotorescue@143 27 "|cffff6633Underpriced|r", -- orange
Zerotorescue@143 28 "The recorded auction value of this item is below your price threshold.",
Zerotorescue@143 29 15,
Zerotorescue@143 30 },
Zerotorescue@143 31 ["NO_ITEMCOUNT_ADDON"] = {
Zerotorescue@143 32 "|cffff0000No itemcount addon|r", -- red
Zerotorescue@143 33 "No compatible item count could be found.",
Zerotorescue@143 34 20,
Zerotorescue@143 35 },
Zerotorescue@144 36 ["REMOVED"] = { -- because this is updated realtime, it is most useful around the top of the list
Zerotorescue@144 37 "|cffff0000Removed|r", -- red
Zerotorescue@144 38 "You manually removed this item from the queue.",
Zerotorescue@144 39 45,
Zerotorescue@144 40 },
Zerotorescue@144 41 ["FINISHED"] = { -- because this is updated realtime, it is most useful on the top of the list
Zerotorescue@144 42 "|cff00ff00Just finished|r", -- green
Zerotorescue@144 43 "Just finished restocking this item.",
Zerotorescue@144 44 50,
Zerotorescue@144 45 },
Zerotorescue@132 46 };
Zerotorescue@132 47
Zerotorescue@145 48 local function Compare(a, b, this, aRow, bRow, columnNo)
Zerotorescue@145 49 if a == b then
Zerotorescue@145 50 local column = this.cols[columnNo];
Zerotorescue@145 51 if column.sortnext then
Zerotorescue@145 52 local nextcol = this.cols[column.sortnext];
Zerotorescue@145 53 if not(nextcol.sort) then
Zerotorescue@145 54 if nextcol.comparesort then
Zerotorescue@145 55 return nextcol.comparesort(this, aRow, bRow, column.sortnext);
Zerotorescue@145 56 else
Zerotorescue@145 57 return this:CompareSort(this, bRow, column.sortnext);
Zerotorescue@145 58 end
Zerotorescue@145 59 else
Zerotorescue@145 60 return false;
Zerotorescue@145 61 end
Zerotorescue@145 62 else
Zerotorescue@145 63 return false;
Zerotorescue@145 64 end
Zerotorescue@145 65 elseif (this.cols[columnNo].sort or this.cols[columnNo].defaultsort or "asc") == "dsc" then
Zerotorescue@145 66 return a > b;
Zerotorescue@145 67 else
Zerotorescue@145 68 return a < b;
Zerotorescue@145 69 end
Zerotorescue@145 70 end
Zerotorescue@145 71
Zerotorescue@132 72 local function MakeQueueWindow()
Zerotorescue@143 73 if not InventoriumQueuer then
Zerotorescue@143 74 addon:CreateQueueFrame();
Zerotorescue@143 75
Zerotorescue@132 76 local frame = InventoriumQueuer; -- both for speed as code-consistency
Zerotorescue@132 77
Zerotorescue@132 78 -- Scrolling table with a list of items to be moved
Zerotorescue@132 79 local scrollTableWidth = ( frame.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size
Zerotorescue@132 80 local headers = {
Zerotorescue@132 81 {
Zerotorescue@132 82 ["name"] = "Item",
Zerotorescue@144 83 ["width"] = (scrollTableWidth * .65),
Zerotorescue@132 84 ["defaultsort"] = "asc",
Zerotorescue@145 85 ["comparesort"] = function(this, aRow, bRow, columnNo)
Zerotorescue@132 86 local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId);
Zerotorescue@132 87 local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId);
Zerotorescue@145 88 aName = sformat("%d%s", (10 - (aRarity or 10)), slower(aName or ""));
Zerotorescue@145 89 bName = sformat("%d%s", (10 - (bRarity or 10)), slower(bName or ""));
Zerotorescue@132 90
Zerotorescue@145 91 return Compare(aName, bName, this, aRow, bRow, columnNo);
Zerotorescue@132 92 end,
Zerotorescue@132 93 ["sort"] = "asc", -- when the data is set, use this column so sort the default data
Zerotorescue@144 94 ["tooltipTitle"] = "Item",
Zerotorescue@144 95 ["tooltip"] = "Click to sort the list by item quality then item name.",
Zerotorescue@132 96 },
Zerotorescue@132 97 {
Zerotorescue@132 98 ["name"] = "Amount",
Zerotorescue@144 99 ["width"] = (scrollTableWidth * .15),
Zerotorescue@132 100 ["align"] = "RIGHT",
Zerotorescue@132 101 ["defaultsort"] = "dsc",
Zerotorescue@145 102 ["comparesort"] = function(this, aRow, bRow, columnNo)
Zerotorescue@145 103 local a = this:GetRow(aRow).rowData.amount;
Zerotorescue@145 104 local b = this:GetRow(bRow).rowData.amount;
Zerotorescue@145 105
Zerotorescue@145 106 return Compare(a, b, this, aRow, bRow, columnNo);
Zerotorescue@143 107 end,
Zerotorescue@132 108 ["sortnext"] = 1,
Zerotorescue@144 109 ["tooltipTitle"] = "Amount needed",
Zerotorescue@144 110 ["tooltip"] = "Click to sort the list by the amount of items needed to reach the restock target.",
Zerotorescue@132 111 },
Zerotorescue@132 112 {
Zerotorescue@132 113 ["name"] = "Extra",
Zerotorescue@144 114 ["width"] = (scrollTableWidth * .15),
Zerotorescue@132 115 ["align"] = "RIGHT",
Zerotorescue@132 116 ["defaultsort"] = "dsc",
Zerotorescue@145 117 ["comparesort"] = function(this, aRow, bRow, columnNo)
Zerotorescue@145 118 local a = this:GetRow(aRow).rowData.bonus;
Zerotorescue@145 119 local b = this:GetRow(bRow).rowData.bonus;
Zerotorescue@145 120
Zerotorescue@145 121 return Compare(a, b, this, aRow, bRow, columnNo);
Zerotorescue@143 122 end,
Zerotorescue@132 123 ["sortnext"] = 1,
Zerotorescue@144 124 ["tooltipTitle"] = "Extra items",
Zerotorescue@144 125 ["tooltip"] = "Click to sort the list by the amount of bonus items.",
Zerotorescue@144 126 },
Zerotorescue@144 127 {
Zerotorescue@144 128 ["name"] = "X",
Zerotorescue@144 129 ["width"] = (scrollTableWidth * .05),
Zerotorescue@144 130 ["align"] = "CENTER",
Zerotorescue@144 131 ["sortnext"] = 1,
Zerotorescue@144 132 ["tooltipTitle"] = "Remove",
Zerotorescue@144 133 ["tooltip"] = "Click any of the fields in this column to remove this item from the queue.",
Zerotorescue@144 134 ["onClick"] = function(rowData)
Zerotorescue@144 135 -- Remove this element from the queue
Zerotorescue@144 136 for index, q in pairs(queue) do
Zerotorescue@144 137 if q == rowData then
Zerotorescue@144 138 table.remove(queue, index);
Zerotorescue@144 139 mod:Skip(q.itemId, skipReasons.REMOVED);
Zerotorescue@144 140 break;
Zerotorescue@144 141 end
Zerotorescue@144 142 end
Zerotorescue@144 143
Zerotorescue@144 144 -- Rebuild our scrolltable (records were removed and added)
Zerotorescue@144 145 mod:BuildQueue();
Zerotorescue@144 146 end,
Zerotorescue@144 147 ["color"] = { ["r"] = 1.0, ["g"] = 0.0, ["b"] = 0.0, ["a"] = 1, },
Zerotorescue@132 148 },
Zerotorescue@132 149 };
Zerotorescue@132 150
Zerotorescue@132 151 local scrollTableWidth = ( InventoriumQueuerUnqueueables.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size
Zerotorescue@132 152 local unqueueablesHeaders = {
Zerotorescue@132 153 {
Zerotorescue@132 154 ["name"] = "Item",
Zerotorescue@132 155 ["width"] = (scrollTableWidth * .6),
Zerotorescue@132 156 ["defaultsort"] = "asc",
Zerotorescue@145 157 ["comparesort"] = function(this, aRow, bRow, columnNo)
Zerotorescue@132 158 local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId);
Zerotorescue@132 159 local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId);
Zerotorescue@145 160 aName = sformat("%d%s", (10 - (aRarity or 10)), slower(aName or ""));
Zerotorescue@145 161 bName = sformat("%d%s", (10 - (bRarity or 10)), slower(bName or ""));
Zerotorescue@132 162
Zerotorescue@145 163 return Compare(aName, bName, this, aRow, bRow, columnNo);
Zerotorescue@132 164 end,
Zerotorescue@144 165 ["tooltipTitle"] = "Item",
Zerotorescue@144 166 ["tooltip"] = "Click to sort the list by item quality then item name.",
Zerotorescue@132 167 },
Zerotorescue@132 168 {
Zerotorescue@132 169 ["name"] = "Reason",
Zerotorescue@132 170 ["width"] = (scrollTableWidth * .4),
Zerotorescue@132 171 ["defaultsort"] = "dsc",
Zerotorescue@145 172 ["comparesort"] = function(this, aRow, bRow, columnNo)
Zerotorescue@145 173 local a = this:GetRow(aRow).rowData.reason[3];
Zerotorescue@145 174 local b = this:GetRow(bRow).rowData.reason[3];
Zerotorescue@145 175
Zerotorescue@145 176 return Compare(a, b, this, aRow, bRow, columnNo);
Zerotorescue@143 177 end,
Zerotorescue@143 178 ["sort"] = "dsc", -- when the data is set, use this column to sort the default data
Zerotorescue@132 179 ["sortnext"] = 1,
Zerotorescue@144 180 ["tooltipTitle"] = "Reason",
Zerotorescue@144 181 ["tooltip"] = "Click to sort the list by the reason the items couldn't be queued.",
Zerotorescue@132 182 },
Zerotorescue@132 183 };
Zerotorescue@132 184
Zerotorescue@132 185 local proceedButton = {
Zerotorescue@132 186 text = "Queue",
Zerotorescue@144 187 tooltipTitle = "Queue",
Zerotorescue@144 188 tooltip = "Add these items to the queue of your crafting addon.",
Zerotorescue@144 189 onClick = function() mod:QueueProcess(); end,
Zerotorescue@132 190 };
Zerotorescue@132 191 local cancelButton = {
Zerotorescue@132 192 text = "Cancel",
Zerotorescue@144 193 tooltipTitle = "Cancel",
Zerotorescue@144 194 tooltip = "Do not queue anything and close the window.",
Zerotorescue@144 195 onClick = function() mod:QueueAbort(); end,
Zerotorescue@132 196 };
Zerotorescue@145 197 local craftButton = {
Zerotorescue@145 198 text = "Craft",
Zerotorescue@145 199 tooltipTitle = "Craft",
Zerotorescue@145 200 tooltip = "Start crafting the first item.",
Zerotorescue@145 201 onClick = function() mod:StartCrafting(); end,
Zerotorescue@145 202 };
Zerotorescue@132 203
Zerotorescue@145 204 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 205 end
Zerotorescue@132 206 end
Zerotorescue@132 207
Zerotorescue@144 208 function mod:BuildQueue()
Zerotorescue@132 209 MakeQueueWindow();
Zerotorescue@132 210
Zerotorescue@132 211 -- This table is never copied, just referenced. It is the same for every row.
Zerotorescue@132 212 local queueablesColumns = {
Zerotorescue@132 213 {
Zerotorescue@132 214 ["value"] = function(data, cols, realrow, column, table)
Zerotorescue@132 215 return IdToItemLink(data[realrow].rowData.itemId);
Zerotorescue@132 216 end,
Zerotorescue@132 217 }, -- item
Zerotorescue@132 218 {
Zerotorescue@132 219 ["value"] = function(data, cols, realrow, column, table)
Zerotorescue@132 220 return data[realrow].rowData.amount;
Zerotorescue@132 221 end,
Zerotorescue@132 222 }, -- amount
Zerotorescue@132 223 {
Zerotorescue@132 224 ["value"] = function(data, cols, realrow, column, table)
Zerotorescue@143 225 return ((data[realrow].rowData.bonus == 0) and 0) or "+" .. data[realrow].rowData.bonus;
Zerotorescue@132 226 end,
Zerotorescue@132 227 ["color"] = function(data, cols, realrow, column, table)
Zerotorescue@132 228 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 229 end,
Zerotorescue@132 230 }, -- extra
Zerotorescue@144 231 {
Zerotorescue@144 232 ["value"] = "X",
Zerotorescue@144 233 },
Zerotorescue@132 234 };
Zerotorescue@132 235
Zerotorescue@132 236 -- Store the list with rows in this
Zerotorescue@132 237 local queueables = {};
Zerotorescue@132 238
Zerotorescue@132 239 for _, q in pairs(queue) do
Zerotorescue@132 240 tinsert(queueables, {
Zerotorescue@132 241 ["rowData"] = q, -- this is not a key usually found in a row item and ignored by the library
Zerotorescue@132 242 ["cols"] = queueablesColumns,
Zerotorescue@132 243 });
Zerotorescue@132 244 end
Zerotorescue@132 245
Zerotorescue@132 246 -- This table is never copied, just referenced. It is the same for every row.
Zerotorescue@132 247 local unqueueablesColumns = {
Zerotorescue@132 248 {
Zerotorescue@132 249 ["value"] = function(data, cols, realrow, column, table)
Zerotorescue@132 250 return IdToItemLink(data[realrow].rowData.itemId);
Zerotorescue@132 251 end,
Zerotorescue@132 252 }, -- item
Zerotorescue@132 253 {
Zerotorescue@132 254 ["value"] = function(data, cols, realrow, column, table)
Zerotorescue@132 255 return data[realrow].rowData.reason[1];
Zerotorescue@132 256 end,
Zerotorescue@132 257 }, -- reason
Zerotorescue@132 258 };
Zerotorescue@132 259
Zerotorescue@132 260 -- Store the list with rows in this
Zerotorescue@132 261 local unqueueables = {};
Zerotorescue@132 262
Zerotorescue@132 263 for _, s in pairs(skipped) do
Zerotorescue@132 264 tinsert(unqueueables, {
Zerotorescue@132 265 ["rowData"] = s, -- this is not a key usually found in a row item and ignored by the library
Zerotorescue@132 266 ["cols"] = unqueueablesColumns,
Zerotorescue@132 267 });
Zerotorescue@132 268 end
Zerotorescue@132 269
Zerotorescue@132 270 addon:SetQueueFrameData(queueables, unqueueables);
Zerotorescue@132 271 end
Zerotorescue@62 272
Zerotorescue@144 273 local function RefreshQueue()
Zerotorescue@144 274 InventoriumQueuer.scrollTable:Refresh();
Zerotorescue@14 275 end
Zerotorescue@14 276
Zerotorescue@144 277 do -- Crafting region
Zerotorescue@144 278 -- We are keeping these events within the module object to allow for easier testing and overriding
Zerotorescue@144 279 -- To test: LibStub("AceAddon-3.0"):GetAddon("Inventorium"):GetModule("Queue"):FUNCTION_NAME(param1, param2, ...);
Zerotorescue@144 280
Zerotorescue@144 281 -- Start crafting the selected skill (or the first in line)
Zerotorescue@144 282 local currentQueueItem;
Zerotorescue@144 283 function mod:StartCrafting(test)
Zerotorescue@144 284 local frame = InventoriumQueuer; -- both for speed as code-consistency
Zerotorescue@144 285
Zerotorescue@144 286 local selectedIndex = frame.scrollTable:GetSelection(); -- gets realrow index
Zerotorescue@144 287
Zerotorescue@145 288 addon:Debug("%s was selected.", tostring(selectedIndex));
Zerotorescue@144 289
Zerotorescue@144 290 if not selectedIndex then
Zerotorescue@144 291 -- Select the top most element (scrolltable with index of 1 will contain a index of the related realrow of the data table)
Zerotorescue@144 292 selectedIndex = ((frame.scrollTable.sorttable and frame.scrollTable.sorttable[1]) or 1);
Zerotorescue@144 293
Zerotorescue@145 294 addon:Debug("%s should be the top record.", tostring(selectedIndex));
Zerotorescue@144 295 end
Zerotorescue@144 296
Zerotorescue@145 297 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 298
Zerotorescue@144 299 if nextQueue then
Zerotorescue@144 300 if not test then
Zerotorescue@145 301 self:ResetTradeSkillFilters();
Zerotorescue@145 302
Zerotorescue@144 303 -- Initiate spell (test will be used while debugging to fake crafts)
Zerotorescue@144 304 DoTradeSkill(nextQueue.craft.no, ceil(nextQueue.amount / nextQueue.craft.quantity));
Zerotorescue@144 305 end
Zerotorescue@144 306
Zerotorescue@144 307 -- Remember what we're crafting (saves many loops and/or table storing)
Zerotorescue@144 308 currentQueueItem = nextQueue;
Zerotorescue@144 309
Zerotorescue@144 310 return;
Zerotorescue@144 311 else
Zerotorescue@144 312 addon:Print("Nothing is available in the craft queue.", addon.Colors.Red);
Zerotorescue@144 313 end
Zerotorescue@144 314 end
Zerotorescue@144 315
Zerotorescue@144 316 function mod:SpellCastComplete(_, unit, _, _, _, spellId)
Zerotorescue@144 317 -- Sadly the item isn't put in our inventory yet so we don't know how many were made.
Zerotorescue@144 318 -- 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 319
Zerotorescue@144 320 if unit == "player" and currentQueueItem and spellId == currentQueueItem.craft.spellId then
Zerotorescue@144 321 -- Decrease amount remaining by one quantity
Zerotorescue@144 322 currentQueueItem.amount = ( currentQueueItem.amount - currentQueueItem.craft.quantity );
Zerotorescue@144 323
Zerotorescue@144 324 if currentQueueItem.amount < 1 then
Zerotorescue@144 325 -- We finished crafting this item
Zerotorescue@144 326
Zerotorescue@144 327 -- Remove this element from the queue
Zerotorescue@144 328 for index, q in pairs(queue) do
Zerotorescue@144 329 if q == currentQueueItem then
Zerotorescue@144 330 table.remove(queue, index);
Zerotorescue@144 331 break;
Zerotorescue@144 332 end
Zerotorescue@144 333 end
Zerotorescue@144 334
Zerotorescue@144 335 -- 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 336 self:Skip(currentQueueItem.itemId, skipReasons.FINISHED);
Zerotorescue@144 337
Zerotorescue@144 338 -- We are no longer crafting anything
Zerotorescue@144 339 currentQueueItem = nil;
Zerotorescue@144 340
Zerotorescue@144 341 -- Rebuild our scrolltable (records were removed and added)
Zerotorescue@144 342 mod:BuildQueue();
Zerotorescue@144 343 else
Zerotorescue@144 344 -- Refresh the scrolltable (update item counts)
Zerotorescue@144 345 RefreshQueue();
Zerotorescue@144 346 end
Zerotorescue@144 347 end
Zerotorescue@144 348 end
Zerotorescue@144 349
Zerotorescue@144 350 function mod:SpellCastStart(_, unit, _, _, _, spellId)
Zerotorescue@144 351 if unit == "player" and currentQueueItem and spellId == currentQueueItem.craft.spellId then
Zerotorescue@144 352 self.isProcessing = true;
Zerotorescue@144 353 end
Zerotorescue@144 354 end
Zerotorescue@144 355
Zerotorescue@144 356 function mod:SpellCastStop(_, unit, _, _, _, spellId)
Zerotorescue@144 357 if unit == "player" and currentQueueItem and spellId == currentQueueItem.craft.spellId then
Zerotorescue@144 358 self.isProcessing = nil;
Zerotorescue@144 359 end
Zerotorescue@144 360 end
Zerotorescue@144 361
Zerotorescue@144 362 function mod:SpellCastFailed(_, unit, _, _, _, spellId)
Zerotorescue@144 363 if unit == "player" and currentQueueItem and spellId == currentQueueItem.craft.spellId then
Zerotorescue@144 364 currentQueueItem = nil;
Zerotorescue@144 365 self.isProcessing = nil;
Zerotorescue@144 366 end
Zerotorescue@144 367 end
Zerotorescue@144 368
Zerotorescue@144 369 --@debug@
Zerotorescue@144 370 function TestCraft()
Zerotorescue@144 371 mod:StartCrafting(true);
Zerotorescue@144 372 mod:SpellCastComplete("UNIT_SPELLCAST_SUCCEEDED", "player", "Relentless Earthsiege Diamond", nil, nil, 55400);
Zerotorescue@144 373 end
Zerotorescue@144 374 --@end-debug@
Zerotorescue@14 375 end
Zerotorescue@14 376
Zerotorescue@144 377 function mod:QueueProcess()
Zerotorescue@144 378 -- Prepare a table with all possible tradeskill craftables
Zerotorescue@144 379 local craftables = self:GetTradeskillCraftables();
Zerotorescue@144 380
Zerotorescue@144 381 for _, q in pairs(queue) do
Zerotorescue@144 382 if craftables[q.itemId] then
Zerotorescue@144 383 if self:QueueWithAddon(craftables[q.itemId].no, ceil(q.amount / craftables[q.itemId].quantity), q.groupName) == -1 then
Zerotorescue@144 384 addon:Print("Couldn't queue, no supported crafting addon found.", addon.Colors.Red);
Zerotorescue@144 385
Zerotorescue@144 386 self:QueueAbort();
Zerotorescue@144 387 return;
Zerotorescue@144 388 else
Zerotorescue@144 389 -- Update the crafted-item count
Zerotorescue@144 390 for groupName, values in pairs(addon.db.profile.groups) do
Zerotorescue@144 391 if values.items and values.items[q.itemId] then
Zerotorescue@144 392 values.items[q.itemId] = (tonumber(values.items[q.itemId]) or 0) + 1;
Zerotorescue@144 393 break;
Zerotorescue@144 394 end
Zerotorescue@144 395 end
Zerotorescue@144 396 end
Zerotorescue@144 397 else
Zerotorescue@144 398 addon:Debug("Lost %s", IdToItemLink(q.itemId));
Zerotorescue@144 399 end
Zerotorescue@144 400 end
Zerotorescue@144 401
Zerotorescue@144 402 self:QueueHide();
Zerotorescue@144 403 end
Zerotorescue@144 404
Zerotorescue@144 405 function mod:QueueAbort()
Zerotorescue@144 406 self:QueueHide();
Zerotorescue@144 407 end
Zerotorescue@144 408
Zerotorescue@144 409 function mod:QueueHide()
Zerotorescue@144 410 twipe(queue);
Zerotorescue@144 411 twipe(skipped);
Zerotorescue@144 412
Zerotorescue@144 413 if InventoriumQueuer then
Zerotorescue@144 414 InventoriumQueuer:Hide();
Zerotorescue@144 415 end
Zerotorescue@13 416 end
Zerotorescue@13 417
Zerotorescue@13 418 function mod:QueueAll()
Zerotorescue@132 419 -- Prepare a table with all possible tradeskill craftables
Zerotorescue@132 420 local craftables = self:GetTradeskillCraftables();
Zerotorescue@132 421
Zerotorescue@132 422 -- Forget old queue
Zerotorescue@132 423 twipe(queue);
Zerotorescue@132 424 twipe(skipped);
Zerotorescue@132 425
Zerotorescue@14 426 local playerName = UnitName("player");
Zerotorescue@14 427
Zerotorescue@14 428 -- Go through all groups
Zerotorescue@61 429 for groupName, values in pairs(addon.db.profile.groups) do
Zerotorescue@62 430 local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters");
Zerotorescue@14 431
Zerotorescue@14 432 if trackAt[playerName] then
Zerotorescue@132 433 self:QueueGroup(groupName, craftables);
Zerotorescue@13 434 end
Zerotorescue@13 435 end
Zerotorescue@132 436
Zerotorescue@144 437 mod:BuildQueue();
Zerotorescue@13 438 end
Zerotorescue@13 439
Zerotorescue@149 440 function mod:QueueGroup(groupName, craftables, displayQueue)
Zerotorescue@132 441 -- Prepare a table with all possible tradeskill craftables
Zerotorescue@132 442 if not craftables then
Zerotorescue@132 443 craftables = self:GetTradeskillCraftables(); -- nil when no tradeskill window is open
Zerotorescue@132 444 end
Zerotorescue@132 445
Zerotorescue@132 446 if not craftables then
Zerotorescue@132 447 addon:Print("No tradeskill window detected.", addon.Colors.Red);
Zerotorescue@132 448 return;
Zerotorescue@132 449 elseif not addon.db.profile.groups[groupName] then
Zerotorescue@132 450 addon:Print(sformat("Tried to queue items from a group named \"%s\", but no such group exists.", groupName), addon.Colors.Red);
Zerotorescue@132 451 return;
Zerotorescue@132 452 elseif not addon.db.profile.groups[groupName].items then
Zerotorescue@132 453 addon:Debug("This group (%s) has no items.", groupName);
Zerotorescue@14 454 return;
Zerotorescue@14 455 end
Zerotorescue@14 456
Zerotorescue@132 457 -- Retrieve group settings
Zerotorescue@146 458 local restockTarget = addon:GetOptionByKey(groupName, "restockTarget");
Zerotorescue@146 459 local bonusQueue = addon:GetOptionByKey(groupName, "bonusQueue");
Zerotorescue@143 460 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 461 local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold");
Zerotorescue@13 462
Zerotorescue@140 463 for itemId, count in pairs(addon.db.profile.groups[groupName].items) do
Zerotorescue@132 464 if craftables[itemId] then
Zerotorescue@146 465 local currentStock = addon:GetItemCount(itemId, groupName);
Zerotorescue@31 466
Zerotorescue@146 467 if currentStock >= 0 then
Zerotorescue@146 468 -- Current stock will be -1 when no itemcount addon was found
Zerotorescue@31 469
Zerotorescue@146 470 -- Calculate the amount to be queued
Zerotorescue@146 471 local amount = ( restockTarget - currentStock );
Zerotorescue@146 472 local bonus = 0;
Zerotorescue@17 473
Zerotorescue@146 474 if currentStock == 0 and bonusQueue > 0 then
Zerotorescue@146 475 -- If we have none left and the bonus queue is enabled, modify the amount to be queued
Zerotorescue@31 476
Zerotorescue@146 477 bonus = floor( ( amount * ( bonusQueue ) ) + .5 ); -- round
Zerotorescue@146 478
Zerotorescue@146 479 -- Update amount
Zerotorescue@146 480 amount = (amount + bonus);
Zerotorescue@146 481 end
Zerotorescue@146 482
Zerotorescue@153 483 if amount > 0 and amount > minCraftingQueue then
Zerotorescue@146 484 -- If we are queuing at least one AND more than the minimum amount, then proceed
Zerotorescue@146 485
Zerotorescue@146 486 -- Get auction value when it is relevant
Zerotorescue@146 487 local value = (priceThreshold ~= 0 and addon:GetAuctionValue(IdToItemLink(itemId), groupName));
Zerotorescue@146 488
Zerotorescue@146 489 if priceThreshold == 0 or value == -1 or value >= priceThreshold then
Zerotorescue@146 490 -- If no price threshold is set or the auction value is equal to or larger than the price threshold, then proceed
Zerotorescue@146 491
Zerotorescue@146 492 self:Queue(itemId, amount, bonus, craftables[itemId], groupName);
Zerotorescue@146 493 else
Zerotorescue@146 494 self:Skip(itemId, skipReasons.LOW_VALUE);
Zerotorescue@146 495 --addon:Debug("%s is valued at %s while %s is needed", IdToItemLink(itemId), tostring(value), tostring(priceThreshold));
Zerotorescue@146 496 end
Zerotorescue@132 497 else
Zerotorescue@146 498 if amount <= 0 then
Zerotorescue@146 499 -- less than 0 = (over)capped
Zerotorescue@146 500 self:Skip(itemId, skipReasons.CAPPED);
Zerotorescue@146 501 else
Zerotorescue@146 502 -- more than 0 = below min crafting queue
Zerotorescue@146 503 self:Skip(itemId, skipReasons.MIN_CRAFTING_QUEUE);
Zerotorescue@146 504 end
Zerotorescue@14 505 end
Zerotorescue@14 506 else
Zerotorescue@146 507 -- No item count addon
Zerotorescue@146 508 self:Skip(itemId, skipReasons.NO_ITEMCOUNT_ADDON);
Zerotorescue@146 509 addon:Print("No usable itemcount addon found.");
Zerotorescue@146 510 return;
Zerotorescue@13 511 end
Zerotorescue@132 512 else
Zerotorescue@132 513 self:Skip(itemId, skipReasons.NOT_CRAFTABLE);
Zerotorescue@13 514 end
Zerotorescue@13 515 end
Zerotorescue@149 516
Zerotorescue@149 517 if displayQueue then
Zerotorescue@149 518 mod:BuildQueue();
Zerotorescue@149 519 end
Zerotorescue@13 520 end
Zerotorescue@13 521
Zerotorescue@143 522 function mod:Queue(itemId, amount, bonus, craft, groupName)
Zerotorescue@132 523 tinsert(queue, {
Zerotorescue@143 524 ["itemId"] = itemId, -- needed to display the queued item in the queue window
Zerotorescue@143 525 ["amount"] = amount, -- the amount missing
Zerotorescue@143 526 ["bonus"] = bonus, -- the amount queued by the bonus queue
Zerotorescue@143 527 ["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 528 ["groupName"] = groupName, -- related group, needed to find the selected crafting addon
Zerotorescue@132 529 });
Zerotorescue@132 530 end
Zerotorescue@132 531
Zerotorescue@132 532 function mod:Skip(itemId, reason)
Zerotorescue@132 533 tinsert(skipped, {
Zerotorescue@132 534 ["itemId"] = itemId,
Zerotorescue@132 535 ["reason"] = reason,
Zerotorescue@132 536 });
Zerotorescue@132 537 end
Zerotorescue@132 538
Zerotorescue@132 539 function mod:QueueWithAddon(tradeSkillIndex, amount, group)
Zerotorescue@132 540 -- Sanity check
Zerotorescue@13 541 tradeSkillIndex = tonumber(tradeSkillIndex);
Zerotorescue@13 542 amount = tonumber(amount);
Zerotorescue@13 543
Zerotorescue@23 544 local selectedExternalAddon = addon:GetOptionByKey(group, "craftingAddon");
Zerotorescue@23 545
Zerotorescue@23 546 if addon.supportedAddons.crafting[selectedExternalAddon] and addon.supportedAddons.crafting[selectedExternalAddon].IsEnabled() then
Zerotorescue@13 547 -- Try to use the default auction pricing addon
Zerotorescue@13 548
Zerotorescue@23 549 return addon.supportedAddons.crafting[selectedExternalAddon].Queue(tradeSkillIndex, amount);
Zerotorescue@13 550 else
Zerotorescue@13 551 -- Default not available, get the first one then
Zerotorescue@13 552
Zerotorescue@13 553 for name, value in pairs(addon.supportedAddons.crafting) do
Zerotorescue@13 554 if value.IsEnabled() then
Zerotorescue@13 555 return value.Queue(tradeSkillIndex, amount);
Zerotorescue@13 556 end
Zerotorescue@13 557 end
Zerotorescue@13 558 end
Zerotorescue@13 559
Zerotorescue@132 560 return -1;
Zerotorescue@13 561 end
Zerotorescue@132 562
Zerotorescue@144 563 function mod:OnEnable()
Zerotorescue@144 564 -- Register our own slash commands
Zerotorescue@144 565 -- /im queue
Zerotorescue@144 566 addon:RegisterSlash(function()
Zerotorescue@144 567 mod:QueueAll();
Zerotorescue@144 568 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 569
Zerotorescue@144 570 self:RegisterMessage("IM_QUEUE_ALL");
Zerotorescue@144 571 self:RegisterMessage("IM_QUEUE_GROUP");
Zerotorescue@144 572
Zerotorescue@144 573 -- When closing the tradeskill window also hide the queue screen.
Zerotorescue@144 574 -- 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 575 self:RegisterEvent("TRADE_SKILL_CLOSE", "QueueAbort");
Zerotorescue@144 576
Zerotorescue@144 577 -- Crafting events
Zerotorescue@144 578 self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED", "SpellCastComplete");
Zerotorescue@144 579
Zerotorescue@144 580 -- Button en-/disabling
Zerotorescue@144 581 self:RegisterEvent("UNIT_SPELLCAST_START", "SpellCastStart");
Zerotorescue@144 582 self:RegisterEvent("UNIT_SPELLCAST_STOP", "SpellCastStop");
Zerotorescue@144 583
Zerotorescue@144 584 self:RegisterEvent("UNIT_SPELLCAST_FAILED", "SpellCastFailed");
Zerotorescue@144 585 self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED", "SpellCastFailed");
Zerotorescue@144 586 end
Zerotorescue@132 587
Zerotorescue@144 588 do -- Addon messages (Ace3) region
Zerotorescue@144 589 function mod:IM_QUEUE_ALL()
Zerotorescue@144 590 self:QueueAll();
Zerotorescue@144 591 end
Zerotorescue@144 592
Zerotorescue@144 593 function mod:IM_QUEUE_GROUP(event, groupName)
Zerotorescue@149 594 self:QueueGroup(groupName, nil, true);
Zerotorescue@132 595 end
Zerotorescue@132 596 end
Zerotorescue@132 597
Zerotorescue@144 598 do -- Trade skill recipes region
Zerotorescue@145 599 -- Reset all filters so no crafts are hidden
Zerotorescue@145 600 function mod:ResetTradeSkillFilters()
Zerotorescue@145 601 SetTradeSkillSubClassFilter(0, 1, 1);
Zerotorescue@145 602 SetTradeSkillItemNameFilter("");
Zerotorescue@145 603 SetTradeSkillItemLevelFilter(0, 0);
Zerotorescue@145 604 TradeSkillOnlyShowSkillUps(false);
Zerotorescue@145 605 TradeSkillOnlyShowMakeable(false);
Zerotorescue@145 606
Zerotorescue@145 607 -- Expand all categories so no crafts are hidden
Zerotorescue@144 608 for i = GetNumTradeSkills(), 1, -1 do
Zerotorescue@144 609 local _, skillType, _, isExpanded = GetTradeSkillInfo(i);
Zerotorescue@144 610
Zerotorescue@144 611 if skillType == "header" and not isExpanded then
Zerotorescue@144 612 ExpandTradeSkillSubClass(i);
Zerotorescue@132 613 end
Zerotorescue@132 614 end
Zerotorescue@132 615 end
Zerotorescue@144 616
Zerotorescue@144 617 -- 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 618 function mod:GetTradeskillCraftables()
Zerotorescue@144 619 local craftables = {};
Zerotorescue@144 620
Zerotorescue@144 621 if GetTradeSkillLine() ~= "UNKNOWN" then
Zerotorescue@145 622 self:ResetTradeSkillFilters();
Zerotorescue@144 623
Zerotorescue@144 624 -- Cache all craftable items
Zerotorescue@144 625 for i = 1, GetNumTradeSkills() do
Zerotorescue@144 626 local itemLink = GetTradeSkillItemLink(i);
Zerotorescue@144 627
Zerotorescue@144 628 if itemLink then
Zerotorescue@144 629 local itemId = addon:GetItemId(itemLink);
Zerotorescue@144 630 if not itemId then
Zerotorescue@144 631 -- If this isn't an item, it can only be an enchant instead
Zerotorescue@144 632 itemId = tonumber(smatch(itemLink, "|Henchant:([-0-9]+)|h"));
Zerotorescue@144 633
Zerotorescue@144 634 if itemId and addon.scrollIds[itemId] then
Zerotorescue@144 635 -- Only if this scroll id actually exists
Zerotorescue@144 636 itemId = addon.scrollIds[itemId]; -- change enchantIds into scrollIds
Zerotorescue@144 637 end
Zerotorescue@144 638 end
Zerotorescue@144 639
Zerotorescue@144 640 -- 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 641 local minMade, maxMade = GetTradeSkillNumMade(i);
Zerotorescue@144 642 local average = ((minMade == maxMade) and minMade) or ((minMade + maxMade) / 2);
Zerotorescue@144 643
Zerotorescue@144 644 local recipeLink = GetTradeSkillRecipeLink(i);
Zerotorescue@144 645 local spellId = tonumber(smatch(recipeLink, "|Henchant:([-0-9]+)|h"));
Zerotorescue@144 646
Zerotorescue@144 647 craftables[itemId] = {
Zerotorescue@144 648 ["no"] = i, -- needed to start crafting at the end of the entire cycle
Zerotorescue@144 649 ["spellId"] = spellId, -- needed to detect creation of this item was finished
Zerotorescue@144 650 ["quantity"] = average, -- needed to calculate the amount of crafts
Zerotorescue@144 651 };
Zerotorescue@144 652 end
Zerotorescue@144 653 end
Zerotorescue@144 654 else
Zerotorescue@144 655 return;
Zerotorescue@144 656 end
Zerotorescue@144 657
Zerotorescue@144 658 return craftables;
Zerotorescue@144 659 end
Zerotorescue@132 660 end