Mercurial > wow > inventory
comparison 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 |
comparison
equal
deleted
inserted
replaced
131:a27948591159 | 132:8460855e3d90 |
---|---|
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 pairs = pairs; | 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; | |
6 | |
7 local queue, skipped = {}, {}; | |
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 | |
10 local skipReasons = { | |
11 ["LOW_VALUE"] = { "|cffff6633Underpriced|r", "The recorded auction value of this item is below your price threshold." }, | |
12 ["CAPPED"] = { "|cff66ff33Fully stocked|r", "The recorded item count is above or equal to your minimum global stock setting." }, | |
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." }, | |
14 ["NO_ITEMCOUNT_ADDON"] = { "|cffff0000No itemcount addon|r", "No compatible item count could be found." }, | |
15 ["NOT_CRAFTABLE"] = { "|cff3d3d3dNot in profession|r", "This item is not part of this profession." }, | |
16 }; | |
17 | |
18 local function OnQueueCancel() | |
19 twipe(queue); | |
20 twipe(skipped); | |
21 | |
22 InventoriumQueuer:Hide(); | |
23 end | |
24 | |
25 local function OnQueueAccept() | |
26 -- Prepare a table with all possible tradeskill craftables | |
27 local craftables = mod:GetTradeskillCraftables(); | |
28 | |
29 for _, q in pairs(queue) do | |
30 if craftables[q.itemId] then | |
31 if mod:QueueWithAddon(craftables[q.itemId].no, ceil(q.amount / craftables[q.itemId].quantity), q.groupName) == -1 then | |
32 addon:Print("Couldn't queue, no supported crafting addon found.", addon.Colors.Red); | |
33 | |
34 OnQueueCancel(); | |
35 return; | |
36 end | |
37 else | |
38 addon:Debug("Lost %s", IdToItemLink(q.itemId)); | |
39 end | |
40 end | |
41 | |
42 twipe(queue); | |
43 twipe(skipped); | |
44 | |
45 InventoriumQueuer:Hide(); | |
46 end | |
47 | |
48 local function MakeQueueWindow() | |
49 do | |
50 local frame = InventoriumQueuer; -- both for speed as code-consistency | |
51 | |
52 -- Scrolling table with a list of items to be moved | |
53 local scrollTableWidth = ( frame.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size | |
54 local headers = { | |
55 { | |
56 ["name"] = "Item", | |
57 ["width"] = (scrollTableWidth * .60), | |
58 ["defaultsort"] = "asc", | |
59 ["comparesort"] = function(this, aRow, bRow, column) | |
60 local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId); | |
61 local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId); | |
62 local template = "%d%s"; | |
63 aName = template:format((10 - (aRarity or 10)), (aName or ""):lower()); | |
64 bName = template:format((10 - (bRarity or 10)), (bName or ""):lower()); | |
65 | |
66 if this.cols[column].sort == "dsc" then | |
67 return aName > bName; | |
68 else | |
69 return aName < bName; | |
70 end | |
71 end, | |
72 ["sort"] = "asc", -- when the data is set, use this column so sort the default data | |
73 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Item"), | |
74 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by item quality then item name."), | |
75 }, | |
76 { | |
77 ["name"] = "Amount", | |
78 ["width"] = (scrollTableWidth * .20), | |
79 ["align"] = "RIGHT", | |
80 ["defaultsort"] = "dsc", | |
81 ["sortnext"] = 1, | |
82 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Amount"), | |
83 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of items to be queued."), | |
84 }, | |
85 { | |
86 ["name"] = "Extra", | |
87 ["width"] = (scrollTableWidth * .20), | |
88 ["align"] = "RIGHT", | |
89 ["defaultsort"] = "dsc", | |
90 ["sortnext"] = 1, | |
91 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Extra"), | |
92 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of bonus items."), | |
93 }, | |
94 }; | |
95 | |
96 local scrollTableWidth = ( InventoriumQueuerUnqueueables.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size | |
97 local unqueueablesHeaders = { | |
98 { | |
99 ["name"] = "Item", | |
100 ["width"] = (scrollTableWidth * .6), | |
101 ["defaultsort"] = "asc", | |
102 ["comparesort"] = function(this, aRow, bRow, column) | |
103 local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId); | |
104 local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId); | |
105 local template = "%d%s"; | |
106 aName = template:format((10 - (aRarity or 10)), (aName or ""):lower()); | |
107 bName = template:format((10 - (bRarity or 10)), (bName or ""):lower()); | |
108 | |
109 if this.cols[column].sort == "dsc" then | |
110 return aName > bName; | |
111 else | |
112 return aName < bName; | |
113 end | |
114 end, | |
115 ["sort"] = "asc", -- when the data is set, use this column so sort the default data | |
116 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Item"), | |
117 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by item quality then item name."), | |
118 }, | |
119 { | |
120 ["name"] = "Reason", | |
121 ["width"] = (scrollTableWidth * .4), | |
122 ["defaultsort"] = "dsc", | |
123 ["sortnext"] = 1, | |
124 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Reason"), | |
125 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the reason the items couldn't be queued."), | |
126 }, | |
127 }; | |
128 | |
129 local proceedButton = { | |
130 text = "Queue", | |
131 tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Queue"), | |
132 tooltip = (not addon.db.profile.defaults.hideHelp and "Add these items to the queue of your crafting addon."), | |
133 onClick = OnQueueAccept, | |
134 }; | |
135 local cancelButton = { | |
136 text = "Cancel", | |
137 tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Cancel"), | |
138 tooltip = (not addon.db.profile.defaults.hideHelp and "Do not queue anything and close the window."), | |
139 onClick = OnQueueCancel, | |
140 }; | |
141 | |
142 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); | |
143 end | |
144 end | |
145 | |
146 local function DisplayQueue() | |
147 MakeQueueWindow(); | |
148 | |
149 -- This table is never copied, just referenced. It is the same for every row. | |
150 local queueablesColumns = { | |
151 { | |
152 ["value"] = function(data, cols, realrow, column, table) | |
153 return IdToItemLink(data[realrow].rowData.itemId); | |
154 end, | |
155 }, -- item | |
156 { | |
157 ["value"] = function(data, cols, realrow, column, table) | |
158 return data[realrow].rowData.amount; | |
159 end, | |
160 }, -- amount | |
161 { | |
162 ["value"] = function(data, cols, realrow, column, table) | |
163 return (data[realrow].rowData.bonus == 0 and 0) or "+" .. data[realrow].rowData.bonus; | |
164 end, | |
165 ["color"] = function(data, cols, realrow, column, table) | |
166 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 }; | |
167 end, | |
168 }, -- extra | |
169 }; | |
170 | |
171 -- Store the list with rows in this | |
172 local queueables = {}; | |
173 | |
174 for _, q in pairs(queue) do | |
175 tinsert(queueables, { | |
176 ["rowData"] = q, -- this is not a key usually found in a row item and ignored by the library | |
177 ["cols"] = queueablesColumns, | |
178 }); | |
179 end | |
180 | |
181 -- This table is never copied, just referenced. It is the same for every row. | |
182 local unqueueablesColumns = { | |
183 { | |
184 ["value"] = function(data, cols, realrow, column, table) | |
185 return IdToItemLink(data[realrow].rowData.itemId); | |
186 end, | |
187 }, -- item | |
188 { | |
189 ["value"] = function(data, cols, realrow, column, table) | |
190 return data[realrow].rowData.reason[1]; | |
191 end, | |
192 }, -- reason | |
193 }; | |
194 | |
195 -- Store the list with rows in this | |
196 local unqueueables = {}; | |
197 | |
198 for _, s in pairs(skipped) do | |
199 tinsert(unqueueables, { | |
200 ["rowData"] = s, -- this is not a key usually found in a row item and ignored by the library | |
201 ["cols"] = unqueueablesColumns, | |
202 }); | |
203 end | |
204 | |
205 addon:SetQueueFrameData(queueables, unqueueables); | |
206 end | |
5 | 207 |
6 function mod:OnEnable() | 208 function mod:OnEnable() |
7 -- Register our own slash commands | 209 -- Register our own slash commands |
8 -- /im queue | 210 -- /im queue |
9 addon:RegisterSlash(function() | 211 addon:RegisterSlash(function() |
10 mod:QueueAll(); | 212 mod:QueueAll(); |
11 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."); | 213 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."); |
12 | 214 |
13 self:RegisterMessage("IM_QUEUE_ALL"); | 215 self:RegisterMessage("IM_QUEUE_ALL"); |
14 self:RegisterMessage("IM_QUEUE_GROUP"); | 216 self:RegisterMessage("IM_QUEUE_GROUP"); |
217 | |
218 if not InventoriumQueuer then | |
219 addon:CreateQueueFrame(OnMoveAccept, OnMoveCancel); | |
220 end | |
15 end | 221 end |
16 | 222 |
17 function mod:IM_QUEUE_ALL() | 223 function mod:IM_QUEUE_ALL() |
18 self:QueueAll(); | 224 self:QueueAll(); |
19 end | 225 end |
21 function mod:IM_QUEUE_GROUP(event, groupName) | 227 function mod:IM_QUEUE_GROUP(event, groupName) |
22 self:QueueGroup(groupName); | 228 self:QueueGroup(groupName); |
23 end | 229 end |
24 | 230 |
25 function mod:QueueAll() | 231 function mod:QueueAll() |
232 -- Prepare a table with all possible tradeskill craftables | |
233 local craftables = self:GetTradeskillCraftables(); | |
234 | |
235 -- Forget old queue | |
236 twipe(queue); | |
237 twipe(skipped); | |
238 | |
26 local playerName = UnitName("player"); | 239 local playerName = UnitName("player"); |
27 | 240 |
28 -- Go through all groups | 241 -- Go through all groups |
29 for groupName, values in pairs(addon.db.profile.groups) do | 242 for groupName, values in pairs(addon.db.profile.groups) do |
30 local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters"); | 243 local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters"); |
31 | 244 |
32 if trackAt[playerName] then | 245 if trackAt[playerName] then |
33 self:QueueGroup(groupName); | 246 self:QueueGroup(groupName, craftables); |
34 end | 247 end |
35 end | 248 end |
36 end | 249 |
37 | 250 DisplayQueue(); |
38 function mod:QueueGroup(groupName) | 251 end |
39 if not addon.db.profile.groups[groupName] then | 252 |
40 addon:Print(("Tried to queue items from a group named \"%s\", but no such group exists."):format(groupName), addon.Colors.Red); | 253 function mod:QueueGroup(groupName, craftables) |
254 -- Prepare a table with all possible tradeskill craftables | |
255 if not craftables then | |
256 craftables = self:GetTradeskillCraftables(); -- nil when no tradeskill window is open | |
257 end | |
258 | |
259 if not craftables then | |
260 addon:Print("No tradeskill window detected.", addon.Colors.Red); | |
41 return; | 261 return; |
42 end | 262 elseif not addon.db.profile.groups[groupName] then |
43 | 263 addon:Print(sformat("Tried to queue items from a group named \"%s\", but no such group exists.", groupName), addon.Colors.Red); |
44 local temp = {}; | 264 return; |
45 | 265 elseif not addon.db.profile.groups[groupName].items then |
46 local tradeskillName, currentLevel, maxLevel = GetTradeSkillLine(); | 266 addon:Debug("This group (%s) has no items.", groupName); |
47 | 267 return; |
48 if tradeskillName ~= "UNKNOWN" then | 268 end |
49 -- Go through all trade skills for the profession | 269 |
50 for i = 1, GetNumTradeSkills() do | 270 -- Retrieve group settings |
51 -- Process every single tradeskill | 271 local restockTarget = addon:GetOptionByKey(groupName, "restockTarget"); |
52 self:ProcessTradeSkill(i, groupName, temp); | 272 local bonusQueue = addon:GetOptionByKey(groupName, "bonusQueue"); |
53 end | 273 local minCraftingQueue = floor( addon:GetOptionByKey(groupName, "minCraftingQueue") * restockTarget ); -- If the minCraftingQueue is 5% and restockTarget is 60, this will result in 3 |
54 end | 274 local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold"); |
55 | 275 |
56 if addon.db.profile.groups[groupName].items then | 276 for itemId in pairs(addon.db.profile.groups[groupName].items) do |
57 for itemId, _ in pairs(addon.db.profile.groups[groupName].items) do | 277 if craftables[itemId] then |
58 if not temp[itemId] then | |
59 local itemLink = select(2, GetItemInfo(itemId)); | |
60 | |
61 addon:Print(("Couldn't queue %s (not part of this profession)"):format((itemLink or itemId or "???")), addon.Colors.Orange); | |
62 end | |
63 end | |
64 end | |
65 end | |
66 | |
67 function mod:ProcessTradeSkill(i, groupName, temp) | |
68 -- Try to retrieve the itemlink, this will be nil if current item is a group instead | |
69 local itemLink = GetTradeSkillItemLink(i); | |
70 | |
71 if itemLink then | |
72 local itemId = addon:GetItemId(itemLink); | |
73 if not itemId then | |
74 -- If this isn't an item, it can only be an enchant instead | |
75 itemId = tonumber(itemLink:match("|Henchant:([-0-9]+)|h")); | |
76 | |
77 itemId = addon.scrollIds[itemId]; -- change enchantIds into scrollIds | |
78 end | |
79 | |
80 if addon.db.profile.groups[groupName].items and addon.db.profile.groups[groupName].items[itemId] then | |
81 -- This item is in this group, queue it! | |
82 | |
83 if temp then | |
84 -- Remember which items have been processed | |
85 temp[itemId] = true; | |
86 end | |
87 | |
88 local currentStock = addon:GetItemCount(itemId, groupName); | 278 local currentStock = addon:GetItemCount(itemId, groupName); |
89 | 279 |
90 if currentStock >= 0 then | 280 if currentStock >= 0 then |
91 -- Current stock will be -1 when no itemcount addon was found | 281 -- Current stock will be -1 when no itemcount addon was found |
92 | 282 |
93 -- Retrieve group settings | |
94 local restockTarget = addon:GetOptionByKey(groupName, "restockTarget"); | |
95 local bonusQueue = addon:GetOptionByKey(groupName, "bonusQueue"); | |
96 local minCraftingQueue = floor( addon:GetOptionByKey(groupName, "minCraftingQueue") * restockTarget ); -- If the minCraftingQueue is 5% and restockTarget is 60, this will result in 3 | |
97 | |
98 -- Calculate the amount to be queued | 283 -- Calculate the amount to be queued |
99 local amount = ( restockTarget - currentStock ); | 284 local amount = ( restockTarget - currentStock ); |
285 local bonus = 0; | |
100 | 286 |
101 if currentStock == 0 and bonusQueue > 0 then | 287 if currentStock == 0 and bonusQueue > 0 then |
102 -- If we have none left and the bonus queue is enabled, modify the amount to be queued | 288 -- If we have none left and the bonus queue is enabled, modify the amount to be queued |
103 | 289 |
104 amount = floor( ( amount * ( bonusQueue + 1 ) ) + .5 ); -- round | 290 bonus = floor( ( amount * ( bonusQueue ) ) + .5 ); -- round |
291 | |
292 -- Update amount | |
293 amount = (amount + bonus); | |
105 end | 294 end |
106 | 295 |
107 if amount > 0 and amount >= minCraftingQueue then | 296 if amount > 0 and amount >= minCraftingQueue then |
108 -- If we are queueing at least one AND more than the minimum amount, then proceed | 297 -- If we are queueing at least one AND more than the minimum amount, then proceed |
109 | 298 |
110 -- Auction value settings | 299 -- Auction value settings |
111 local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold"); | |
112 local value = (priceThreshold ~= 0 and addon:GetAuctionValue(itemLink, groupName)); | 300 local value = (priceThreshold ~= 0 and addon:GetAuctionValue(itemLink, groupName)); |
113 | 301 |
114 if priceThreshold == 0 or value == -1 or value >= priceThreshold then | 302 if priceThreshold == 0 or value == -1 or value >= priceThreshold then |
115 -- If no price threshold is set or the auction value is equal to or larger than the price threshold, then proceed | 303 -- If no price threshold is set or the auction value is equal to or larger than the price threshold, then proceed |
116 | 304 |
117 self:Queue(i, amount, groupName); | 305 self:Queue(itemId, amount, bonus, groupName); |
118 | 306 else |
119 addon:Print(("Queued %d of %s"):format(amount, itemLink)); | 307 self:Skip(itemId, skipReasons.LOW_VALUE); |
308 end | |
309 else | |
310 if amount <= 0 then | |
311 self:Skip(itemId, skipReasons.CAPPED); | |
312 else | |
313 self:Skip(itemId, skipReasons.MIN_CRAFTING_QUEUE); | |
120 end | 314 end |
121 end | 315 end |
122 else | 316 else |
317 self:Skip(itemId, skipReasons.NO_ITEMCOUNT_ADDON); | |
123 addon:Print("No usable itemcount addon found."); | 318 addon:Print("No usable itemcount addon found."); |
319 return; | |
124 end | 320 end |
125 end | 321 else |
126 end | 322 self:Skip(itemId, skipReasons.NOT_CRAFTABLE); |
127 end | 323 end |
128 | 324 end |
129 function mod:Queue(tradeSkillIndex, amount, group) | 325 end |
326 | |
327 function mod:Queue(itemId, amount, bonus, groupName) | |
328 tinsert(queue, { | |
329 ["itemId"] = itemId, | |
330 ["amount"] = amount, | |
331 ["bonus"] = bonus, | |
332 ["groupName"] = groupName, | |
333 }); | |
334 end | |
335 | |
336 function mod:Skip(itemId, reason) | |
337 tinsert(skipped, { | |
338 ["itemId"] = itemId, | |
339 ["reason"] = reason, | |
340 }); | |
341 end | |
342 | |
343 function mod:QueueWithAddon(tradeSkillIndex, amount, group) | |
344 -- Sanity check | |
130 tradeSkillIndex = tonumber(tradeSkillIndex); | 345 tradeSkillIndex = tonumber(tradeSkillIndex); |
131 amount = tonumber(amount); | 346 amount = tonumber(amount); |
132 | |
133 if not tradeSkillIndex or not amount then return; end | |
134 | 347 |
135 local selectedExternalAddon = addon:GetOptionByKey(group, "craftingAddon"); | 348 local selectedExternalAddon = addon:GetOptionByKey(group, "craftingAddon"); |
136 | 349 |
137 if addon.supportedAddons.crafting[selectedExternalAddon] and addon.supportedAddons.crafting[selectedExternalAddon].IsEnabled() then | 350 if addon.supportedAddons.crafting[selectedExternalAddon] and addon.supportedAddons.crafting[selectedExternalAddon].IsEnabled() then |
138 -- Try to use the default auction pricing addon | 351 -- Try to use the default auction pricing addon |
146 return value.Queue(tradeSkillIndex, amount); | 359 return value.Queue(tradeSkillIndex, amount); |
147 end | 360 end |
148 end | 361 end |
149 end | 362 end |
150 | 363 |
151 return -2; | 364 return -1; |
152 end | 365 end |
366 | |
367 -- Expand all categories | |
368 local function ExpandSubClasses() | |
369 for i = GetNumTradeSkills(), 1, -1 do | |
370 local _, skillType, _, isExpanded = GetTradeSkillInfo(i); | |
371 | |
372 if skillType == "header" and not isExpanded then | |
373 ExpandTradeSkillSubClass(i); | |
374 end | |
375 end | |
376 end | |
377 | |
378 function mod:GetTradeskillCraftables() | |
379 local craftables = {}; | |
380 | |
381 if GetTradeSkillLine() ~= "UNKNOWN" then | |
382 ExpandSubClasses(); | |
383 | |
384 -- Cache all craftable items | |
385 for i = 1, GetNumTradeSkills() do | |
386 local itemLink = GetTradeSkillItemLink(i); | |
387 | |
388 if itemLink then | |
389 local itemId = addon:GetItemId(itemLink); | |
390 if not itemId then | |
391 -- If this isn't an item, it can only be an enchant instead | |
392 itemId = tonumber(smatch(itemLink, "|Henchant:([-0-9]+)|h")); | |
393 | |
394 itemId = addon.scrollIds[itemId]; -- change enchantIds into scrollIds | |
395 end | |
396 | |
397 -- 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) | |
398 local minMade, maxMade = GetTradeSkillNumMade(i); | |
399 local average = ((minMade == maxMade) and minMade) or ((minMade + maxMade) / 2); | |
400 | |
401 craftables[itemId] = { | |
402 ["no"] = i, | |
403 ["quantity"] = average, | |
404 }; | |
405 end | |
406 end | |
407 else | |
408 return; | |
409 end | |
410 | |
411 return craftables; | |
412 end |