comparison Modules/Queue.lua @ 143:8eb0f5b5a885

Fixed ?fully stocked? tooltip to say it uses the restock target setting rather than the global stock setting. Making sure the inventorium queuer frame is available before hiding it. Fixed an error with queueing items. Skip reasons are now sorted by importance (also by default). Now closing the queue window when you close your profession window.
author Zerotorescue
date Tue, 18 Jan 2011 23:48:16 +0100
parents cd461a41723c
children 12a8ea5af671
comparison
equal deleted inserted replaced
142:56f33abee1e3 143:8eb0f5b5a885
1 local addon = select(2, ...); 1 local addon = select(2, ...);
2 local mod = addon:NewModule("Queue", "AceEvent-3.0", "AceTimer-3.0"); 2 local mod = addon:NewModule("Queue", "AceEvent-3.0", "AceTimer-3.0");
3 3
4 local _G = _G; 4 local _G = _G;
5 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; 5 local tonumber, pairs, sformat, smatch, slower, floor, ceil, tinsert, twipe = _G.tonumber, _G.pairs, _G.string.format, _G.string.match, _G.string.lower, _G.floor, _G.ceil, _G.table.insert, _G.table.wipe;
6 6
7 local queue, skipped = {}, {}; 7 local queue, skipped = {}, {};
8 8
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 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
10 local skipReasons = { 10 local skipReasons = {
11 ["LOW_VALUE"] = { "|cffff6633Underpriced|r", "The recorded auction value of this item is below your price threshold." }, 11 ["NOT_CRAFTABLE"] = {
12 ["CAPPED"] = { "|cff66ff33Fully stocked|r", "The recorded item count is above or equal to your minimum global stock setting." }, 12 "|cff3d3d3dNot in profession|r", -- gray
13 ["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." }, 13 "This item is not part of this profession.",
14 ["NO_ITEMCOUNT_ADDON"] = { "|cffff0000No itemcount addon|r", "No compatible item count could be found." }, 14 0,
15 ["NOT_CRAFTABLE"] = { "|cff3d3d3dNot in profession|r", "This item is not part of this profession." }, 15 },
16 ["CAPPED"] = {
17 "|cff66ff33Fully stocked|r", -- lime/green
18 "The recorded item count is above or equal to your minimum restock target setting.",
19 5,
20 },
21 ["MIN_CRAFTING_QUEUE"] = {
22 "|cffffff00Min crafting queue|r", -- yellow
23 "The amount of missing items is below or equal to your \"don't queue if I only miss\"-setting.",
24 10,
25 },
26 ["LOW_VALUE"] = {
27 "|cffff6633Underpriced|r", -- orange
28 "The recorded auction value of this item is below your price threshold.",
29 15,
30 },
31 ["NO_ITEMCOUNT_ADDON"] = {
32 "|cffff0000No itemcount addon|r", -- red
33 "No compatible item count could be found.",
34 20,
35 },
16 }; 36 };
17 37
18 local function OnQueueCancel() 38 local function OnQueueCancel()
19 twipe(queue); 39 twipe(queue);
20 twipe(skipped); 40 twipe(skipped);
21 41
22 InventoriumQueuer:Hide(); 42 if InventoriumQueuer then
43 InventoriumQueuer:Hide();
44 end
23 end 45 end
24 46
25 local function OnQueueAccept() 47 local function OnQueueAccept()
26 -- Prepare a table with all possible tradeskill craftables 48 -- Prepare a table with all possible tradeskill craftables
27 local craftables = mod:GetTradeskillCraftables(); 49 local craftables = mod:GetTradeskillCraftables();
35 return; 57 return;
36 else 58 else
37 -- Update the crafted-item count 59 -- Update the crafted-item count
38 for groupName, values in pairs(addon.db.profile.groups) do 60 for groupName, values in pairs(addon.db.profile.groups) do
39 if values.items and values.items[q.itemId] then 61 if values.items and values.items[q.itemId] then
40 values.items[q.itemId] = tonumber(values.items[q.itemId]) + 1; 62 values.items[q.itemId] = (tonumber(values.items[q.itemId]) or 0) + 1;
41 break; 63 break;
42 end 64 end
43 end 65 end
44 end 66 end
45 else 67 else
48 end 70 end
49 71
50 twipe(queue); 72 twipe(queue);
51 twipe(skipped); 73 twipe(skipped);
52 74
53 InventoriumQueuer:Hide(); 75 if InventoriumQueuer then
54 end 76 InventoriumQueuer:Hide();
77 end
78 end
79
80
81 --[[Allowing the queue window to actually initiate crafts is going to be a likely feature.
82 do
83 -- Start crafting the selected skill (or the first in line)
84 local function StartSelectedCraft()
85 local craftables = mod:GetTradeskillCraftables();
86
87 for _, q in pairs(queue) do
88 if craftables[q.itemId] then
89 DoTradeSkill(craftables[q.itemId].no, ceil(q.amount / craftables[q.itemId].quantity));
90 return;
91 end
92 end
93 end
94
95 -- Remove from queue and if it was selected, auto-select the next
96 local function CraftFinished()
97
98 end
99
100 -- Refresh the item count for this item
101 local function RefreshItem()
102 q.amount = mod:GetRestockAmount(q.itemId, q.groupName);
103
104 if q.amount < 1 then
105 table.remove(crafts, i);
106 end
107
108 DisplayQueue();
109 end
110
111 local function OnSpellFinished(event, unit, spellName, _, _, spellId)
112 if unit == "player" then
113 for i, q in pairs(queue) do
114 if q.craft.spellId == spellId then
115 -- We just finished this spell
116
117 print("pass");
118
119
120 return;
121 end
122 end
123 end
124 end
125 function Test() OnSpellFinished("SomeSpell", "player", "Delicate Inferno Ruby", nil, nil, 55400); end
126
127 tinsert(queue, {
128 ["itemId"] = itemId, -- needed to display the queued item in the queue window
129 ["amount"] = amount, -- the amount missing
130 ["bonus"] = bonus, -- the amount queued by the bonus queue
131 ["craft"] = craft, -- (craftable) - needed to find the proper element of this parent array when crafting has finished (spellId), and to update the numCrafts (quantity)
132 ["groupName"] = groupName, -- related group, needed to find the selected crafting addon
133 });
134 [1] = “player”;
135 [2] = “Delicate Inferno Ruby”;
136 [3] = “”;
137 [4] = 19;
138 [5] = 73336;
139 arg1
140 Unit casting the spell - "player"
141 arg2
142 Spell name - "“Delicate Inferno Ruby”"
143 arg3
144 Spell rank (deprecated in 4.0) - ""
145 arg4
146 Spell lineID counter - 19
147 arg5
148 Spell ID (added in 4.0) - 73336
149
150 end]]
55 151
56 local function MakeQueueWindow() 152 local function MakeQueueWindow()
57 do 153 if not InventoriumQueuer then
154 addon:CreateQueueFrame();
155
58 local frame = InventoriumQueuer; -- both for speed as code-consistency 156 local frame = InventoriumQueuer; -- both for speed as code-consistency
59 157
60 -- Scrolling table with a list of items to be moved 158 -- Scrolling table with a list of items to be moved
61 local scrollTableWidth = ( frame.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size 159 local scrollTableWidth = ( frame.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size
62 local headers = { 160 local headers = {
66 ["defaultsort"] = "asc", 164 ["defaultsort"] = "asc",
67 ["comparesort"] = function(this, aRow, bRow, column) 165 ["comparesort"] = function(this, aRow, bRow, column)
68 local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId); 166 local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId);
69 local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId); 167 local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId);
70 local template = "%d%s"; 168 local template = "%d%s";
71 aName = template:format((10 - (aRarity or 10)), (aName or ""):lower()); 169 aName = sformat(template, (10 - (aRarity or 10)), slower(aName or ""));
72 bName = template:format((10 - (bRarity or 10)), (bName or ""):lower()); 170 bName = sformat(template, (10 - (bRarity or 10)), slower(bName or ""));
73 171
74 if this.cols[column].sort == "dsc" then 172 if this.cols[column].sort == "dsc" then
75 return aName > bName; 173 return aName > bName;
76 else 174 else
77 return aName < bName; 175 return aName < bName;
84 { 182 {
85 ["name"] = "Amount", 183 ["name"] = "Amount",
86 ["width"] = (scrollTableWidth * .20), 184 ["width"] = (scrollTableWidth * .20),
87 ["align"] = "RIGHT", 185 ["align"] = "RIGHT",
88 ["defaultsort"] = "dsc", 186 ["defaultsort"] = "dsc",
187 ["comparesort"] = function(this, aRow, bRow, column)
188 if this.cols[column].sort == "dsc" then
189 return (this:GetRow(aRow).rowData.amount > this:GetRow(bRow).rowData.amount);
190 else
191 return (this:GetRow(aRow).rowData.amount < this:GetRow(bRow).rowData.amount);
192 end
193 end,
89 ["sortnext"] = 1, 194 ["sortnext"] = 1,
90 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Amount"), 195 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Amount needed"),
91 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of items to be queued."), 196 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of items needed to reach the restock target."),
92 }, 197 },
93 { 198 {
94 ["name"] = "Extra", 199 ["name"] = "Extra",
95 ["width"] = (scrollTableWidth * .20), 200 ["width"] = (scrollTableWidth * .20),
96 ["align"] = "RIGHT", 201 ["align"] = "RIGHT",
97 ["defaultsort"] = "dsc", 202 ["defaultsort"] = "dsc",
203 ["comparesort"] = function(this, aRow, bRow, column)
204 if this.cols[column].sort == "dsc" then
205 return (this:GetRow(aRow).rowData.bonus > this:GetRow(bRow).rowData.bonus);
206 else
207 return (this:GetRow(aRow).rowData.bonus < this:GetRow(bRow).rowData.bonus);
208 end
209 end,
98 ["sortnext"] = 1, 210 ["sortnext"] = 1,
99 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Extra"), 211 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Extra items"),
100 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of bonus items."), 212 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of bonus items."),
101 }, 213 },
102 }; 214 };
103 215
104 local scrollTableWidth = ( InventoriumQueuerUnqueueables.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size 216 local scrollTableWidth = ( InventoriumQueuerUnqueueables.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size
109 ["defaultsort"] = "asc", 221 ["defaultsort"] = "asc",
110 ["comparesort"] = function(this, aRow, bRow, column) 222 ["comparesort"] = function(this, aRow, bRow, column)
111 local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId); 223 local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId);
112 local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId); 224 local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId);
113 local template = "%d%s"; 225 local template = "%d%s";
114 aName = template:format((10 - (aRarity or 10)), (aName or ""):lower()); 226 aName = sformat(template, (10 - (aRarity or 10)), slower(aName or ""));
115 bName = template:format((10 - (bRarity or 10)), (bName or ""):lower()); 227 bName = sformat(template, (10 - (bRarity or 10)), slower(bName or ""));
116 228
117 if this.cols[column].sort == "dsc" then 229 if this.cols[column].sort == "dsc" then
118 return aName > bName; 230 return aName > bName;
119 else 231 else
120 return aName < bName; 232 return aName < bName;
121 end 233 end
122 end, 234 end,
123 ["sort"] = "asc", -- when the data is set, use this column so sort the default data
124 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Item"), 235 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Item"),
125 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by item quality then item name."), 236 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by item quality then item name."),
126 }, 237 },
127 { 238 {
128 ["name"] = "Reason", 239 ["name"] = "Reason",
129 ["width"] = (scrollTableWidth * .4), 240 ["width"] = (scrollTableWidth * .4),
130 ["defaultsort"] = "dsc", 241 ["defaultsort"] = "dsc",
242 ["comparesort"] = function(this, aRow, bRow, column)
243 local result = (this:GetRow(aRow).rowData.reason[3] > this:GetRow(bRow).rowData.reason[3]);
244
245 if this.cols[column].sort == "dsc" then
246 return result;
247 else
248 return (not result);
249 end
250 end,
251 ["sort"] = "dsc", -- when the data is set, use this column to sort the default data
131 ["sortnext"] = 1, 252 ["sortnext"] = 1,
132 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Reason"), 253 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Reason"),
133 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the reason the items couldn't be queued."), 254 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the reason the items couldn't be queued."),
134 }, 255 },
135 }; 256 };
166 return data[realrow].rowData.amount; 287 return data[realrow].rowData.amount;
167 end, 288 end,
168 }, -- amount 289 }, -- amount
169 { 290 {
170 ["value"] = function(data, cols, realrow, column, table) 291 ["value"] = function(data, cols, realrow, column, table)
171 return (data[realrow].rowData.bonus == 0 and 0) or "+" .. data[realrow].rowData.bonus; 292 return ((data[realrow].rowData.bonus == 0) and 0) or "+" .. data[realrow].rowData.bonus;
172 end, 293 end,
173 ["color"] = function(data, cols, realrow, column, table) 294 ["color"] = function(data, cols, realrow, column, table)
174 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 }; 295 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 };
175 end, 296 end,
176 }, -- extra 297 }, -- extra
221 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."); 342 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.");
222 343
223 self:RegisterMessage("IM_QUEUE_ALL"); 344 self:RegisterMessage("IM_QUEUE_ALL");
224 self:RegisterMessage("IM_QUEUE_GROUP"); 345 self:RegisterMessage("IM_QUEUE_GROUP");
225 346
226 if not InventoriumQueuer then 347 self:RegisterEvent("TRADE_SKILL_CLOSE", OnQueueCancel);
227 addon:CreateQueueFrame(OnMoveAccept, OnMoveCancel); 348
228 end 349 --self:RegisterEvent("UNIT_SPELLCAST_STOP", OnSpellFinished);
350 --self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP", OnSpellFinished);
229 end 351 end
230 352
231 function mod:IM_QUEUE_ALL() 353 function mod:IM_QUEUE_ALL()
232 self:QueueAll(); 354 self:QueueAll();
233 end 355 end
274 addon:Debug("This group (%s) has no items.", groupName); 396 addon:Debug("This group (%s) has no items.", groupName);
275 return; 397 return;
276 end 398 end
277 399
278 -- Retrieve group settings 400 -- Retrieve group settings
279 local restockTarget = addon:GetOptionByKey(groupName, "restockTarget"); 401 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
280 local bonusQueue = addon:GetOptionByKey(groupName, "bonusQueue");
281 local minCraftingQueue = floor( addon:GetOptionByKey(groupName, "minCraftingQueue") * restockTarget ); -- If the minCraftingQueue is 5% and restockTarget is 60, this will result in 3
282 local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold"); 402 local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold");
283 403
284 for itemId, count in pairs(addon.db.profile.groups[groupName].items) do 404 for itemId, count in pairs(addon.db.profile.groups[groupName].items) do
285 if craftables[itemId] then 405 if craftables[itemId] then
286 local currentStock = addon:GetItemCount(itemId, groupName); 406 local amount, bonus = self:GetRestockAmount(itemId, groupName);
287 407
288 if currentStock >= 0 then 408 if amount and amount >= minCraftingQueue then
289 -- Current stock will be -1 when no itemcount addon was found 409 -- If we are queuing at least one AND more than the minimum amount, then proceed
290 410
291 -- Calculate the amount to be queued 411 -- Auction value settings
292 local amount = ( restockTarget - currentStock ); 412 local value = (priceThreshold ~= 0 and addon:GetAuctionValue(itemLink, groupName));
293 local bonus = 0;
294 413
295 if currentStock == 0 and bonusQueue > 0 then 414 if priceThreshold == 0 or value == -1 or value >= priceThreshold then
296 -- If we have none left and the bonus queue is enabled, modify the amount to be queued 415 -- If no price threshold is set or the auction value is equal to or larger than the price threshold, then proceed
297 416
298 bonus = floor( ( amount * ( bonusQueue ) ) + .5 ); -- round 417 self:Queue(itemId, amount, bonus, craftables[itemId], groupName);
299
300 -- Update amount
301 amount = (amount + bonus);
302 end
303
304 if amount > 0 and amount >= minCraftingQueue then
305 -- If we are queuing at least one AND more than the minimum amount, then proceed
306
307 -- Auction value settings
308 local value = (priceThreshold ~= 0 and addon:GetAuctionValue(itemLink, groupName));
309
310 if priceThreshold == 0 or value == -1 or value >= priceThreshold then
311 -- If no price threshold is set or the auction value is equal to or larger than the price threshold, then proceed
312
313 self:Queue(itemId, amount, bonus, groupName);
314 else
315 self:Skip(itemId, skipReasons.LOW_VALUE);
316 end
317 else 418 else
318 if amount <= 0 then 419 self:Skip(itemId, skipReasons.LOW_VALUE);
319 self:Skip(itemId, skipReasons.CAPPED);
320 else
321 self:Skip(itemId, skipReasons.MIN_CRAFTING_QUEUE);
322 end
323 end 420 end
324 else 421 else
325 self:Skip(itemId, skipReasons.NO_ITEMCOUNT_ADDON); 422 if not amount then
326 addon:Print("No usable itemcount addon found."); 423 -- nil = no item count addon
327 return; 424 self:Skip(itemId, skipReasons.NO_ITEMCOUNT_ADDON);
425 addon:Print("No usable itemcount addon found.");
426 return;
427 elseif amount <= 0 then
428 -- less than 0 = (over)capped
429 self:Skip(itemId, skipReasons.CAPPED);
430 else
431 -- more than 0 = below min crafting queue
432 self:Skip(itemId, skipReasons.MIN_CRAFTING_QUEUE);
433 end
328 end 434 end
329 else 435 else
330 self:Skip(itemId, skipReasons.NOT_CRAFTABLE); 436 self:Skip(itemId, skipReasons.NOT_CRAFTABLE);
331 end 437 end
332 end 438 end
333 end 439 end
334 440
335 function mod:Queue(itemId, amount, bonus, groupName) 441 function mod:GetRestockAmount(itemId, groupName)
442 local currentStock = addon:GetItemCount(itemId, groupName);
443
444 if currentStock >= 0 then
445 -- Current stock will be -1 when no itemcount addon was found
446
447 local restockTarget = addon:GetOptionByKey(groupName, "restockTarget");
448 local bonusQueue = addon:GetOptionByKey(groupName, "bonusQueue");
449
450 -- Calculate the amount to be queued
451 local amount = ( restockTarget - currentStock );
452 local bonus = 0;
453
454 if currentStock == 0 and bonusQueue > 0 then
455 -- If we have none left and the bonus queue is enabled, modify the amount to be queued
456
457 bonus = floor( ( amount * ( bonusQueue ) ) + .5 ); -- round
458
459 -- Update amount
460 amount = (amount + bonus);
461 end
462
463 return amount, bonus;
464 else
465 return;
466 end
467 end
468
469 function mod:Queue(itemId, amount, bonus, craft, groupName)
336 tinsert(queue, { 470 tinsert(queue, {
337 ["itemId"] = itemId, 471 ["itemId"] = itemId, -- needed to display the queued item in the queue window
338 ["amount"] = amount, 472 ["amount"] = amount, -- the amount missing
339 ["bonus"] = bonus, 473 ["bonus"] = bonus, -- the amount queued by the bonus queue
340 ["groupName"] = groupName, 474 ["craft"] = craft, -- (craftable) - needed to find the proper element of this parent array when crafting has finished (spellId), and to update the numCrafts (quantity)
475 ["groupName"] = groupName, -- related group, needed to find the selected crafting addon
341 }); 476 });
342 end 477 end
343 478
344 function mod:Skip(itemId, reason) 479 function mod:Skip(itemId, reason)
345 tinsert(skipped, { 480 tinsert(skipped, {
404 539
405 -- 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) 540 -- 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)
406 local minMade, maxMade = GetTradeSkillNumMade(i); 541 local minMade, maxMade = GetTradeSkillNumMade(i);
407 local average = ((minMade == maxMade) and minMade) or ((minMade + maxMade) / 2); 542 local average = ((minMade == maxMade) and minMade) or ((minMade + maxMade) / 2);
408 543
544 local recipeLink = GetTradeSkillRecipeLink(i);
545 local spellId = tonumber(smatch(recipeLink, "|Henchant:([-0-9]+)|h"));
546
409 craftables[itemId] = { 547 craftables[itemId] = {
410 ["no"] = i, 548 ["no"] = i, -- needed to start crafting at the end of the entire cycle
411 ["quantity"] = average, 549 ["spellId"] = spellId, -- needed to detect creation of this item was finished
550 ["quantity"] = average, -- needed to calculate the amount of crafts
412 }; 551 };
413 end 552 end
414 end 553 end
415 else 554 else
416 return; 555 return;