Mercurial > wow > inventory
comparison Modules/Scanner.lua @ 110:67bd5057ecb7
Implemented vendor restocking with the mover. Comitting so I can always review this working version, but I?ll be disabling all part of it as it is not going to work properly without seriously compromising the code structure.
Debug messages are now appended with ?Inventorium? (my MailOpener addon was making stuff difficult).
Now properly removing the refill window from the displayed static popup windows list so new popups won?t be aligned at odd locations.
Changed ?CreateMoverFrame? to not contain any scenario-specific info. All settings can be set with SetFrameSettings.
Items that belong to speciality bags are now put there. Other items now ignore spaciality bags.
Implemented test code for mailbox refill support. It has been disabled due to some issues but may be introduced later.
The guild withdrawal limit is now taken into consideration.
Queue is now reset before scanning again.
author | Zerotorescue |
---|---|
date | Fri, 14 Jan 2011 23:25:05 +0100 |
parents | 3bbad0429d87 |
children | 41f0689dfda1 |
comparison
equal
deleted
inserted
replaced
109:3bbad0429d87 | 110:67bd5057ecb7 |
---|---|
1 local addon = select(2, ...); | 1 local addon = select(2, ...); |
2 local mod = addon:NewModule("Scanner", "AceEvent-3.0", "AceTimer-3.0"); | 2 local mod = addon:NewModule("Scanner", "AceEvent-3.0", "AceTimer-3.0"); |
3 | 3 |
4 addon.Locations = { | |
5 Bag = 0, | |
6 Bank = 1, | |
7 Guild = 2, | |
8 Mailbox = 3, | |
9 }; | |
10 | |
11 local Mover, paused, currentLocation; | 4 local Mover, paused, currentLocation; |
12 local itemCache = {}; | 5 local itemCache = {}; |
13 | 6 |
14 local function OnMoveAccept(this) | 7 local function OnMoveAccept() |
15 mod:Pause(); | 8 mod:Pause(); |
16 Mover:BeginMove(currentLocation, mod.Unpause); | 9 Mover:BeginMove(currentLocation, mod.Unpause); |
17 | 10 |
18 InventoriumItemMover:Hide(); | 11 InventoriumItemMover:Hide(); |
19 end | 12 end |
20 | 13 |
21 local function OnMoveCancel(this) | 14 local function OnMoveCancel() |
22 Mover:ResetQueue(); | 15 Mover:ResetQueue(); |
23 currentLocation = nil; | 16 currentLocation = nil; |
24 | 17 |
25 InventoriumItemMover:Hide(); | 18 InventoriumItemMover:Hide(); |
19 end | |
20 | |
21 local function UseStorageRefillST(withPrices) | |
22 local frame = InventoriumItemMover; -- both for speed as code-consistency | |
23 | |
24 -- Scrolling table with a list of items to be moved | |
25 local scrollTableWidth = ( frame.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size | |
26 local headers = { | |
27 { | |
28 ["name"] = "Item", | |
29 ["width"] = (scrollTableWidth * ((withPrices and .5) or .60)), | |
30 ["defaultsort"] = "asc", | |
31 ["comparesort"] = function(this, aRow, bRow, column) | |
32 local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId); | |
33 local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId); | |
34 local template = "%d%s"; | |
35 aName = template:format((10 - (aRarity or 10)), (aName or ""):lower()); | |
36 bName = template:format((10 - (bRarity or 10)), (bName or ""):lower()); | |
37 | |
38 if this.cols[column].sort == "dsc" then | |
39 return aName > bName; | |
40 else | |
41 return aName < bName; | |
42 end | |
43 end, | |
44 ["sort"] = "asc", -- when the data is set, use this column so sort the default data | |
45 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Item"), | |
46 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by item quality then item name."), | |
47 }, | |
48 { | |
49 ["name"] = "Moving", | |
50 ["width"] = (scrollTableWidth * .15), | |
51 ["align"] = "RIGHT", | |
52 ["defaultsort"] = "dsc", | |
53 ["sortnext"] = 1, | |
54 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Moving"), | |
55 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of movable items."), | |
56 }, | |
57 { | |
58 ["name"] = "Available", | |
59 ["width"] = (scrollTableWidth * ((withPrices and .2) or .25)), | |
60 ["align"] = "RIGHT", | |
61 ["defaultsort"] = "dsc", | |
62 ["sortnext"] = 1, | |
63 ["comparesort"] = function(this, aRow, bRow, column) | |
64 local aAvailablePercent = (this:GetRow(aRow).rowData.available / this:GetRow(aRow).rowData.missing); | |
65 local bAvailablePercent = (this:GetRow(bRow).rowData.available / this:GetRow(bRow).rowData.missing); | |
66 | |
67 if this.cols[column].sort == "dsc" then | |
68 return aAvailablePercent > bAvailablePercent; | |
69 else | |
70 return aAvailablePercent < bAvailablePercent; | |
71 end | |
72 end, | |
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 the availibility percentage."), | |
75 }, | |
76 }; | |
77 if withPrices then | |
78 table.insert(headers, { | |
79 ["name"] = "Price", | |
80 ["width"] = (scrollTableWidth * .15), | |
81 ["align"] = "RIGHT", | |
82 ["defaultsort"] = "dsc", | |
83 ["sortnext"] = 1, | |
84 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Price"), | |
85 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the price of this item at this vendor."), | |
86 }); | |
87 end | |
88 | |
89 local proceedButton = { | |
90 text = "Move Items", | |
91 tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Move Items"), | |
92 tooltip = (not addon.db.profile.defaults.hideHelp and "Start moving these items from the bank."), | |
93 onClick = OnMoveAccept, | |
94 }; | |
95 local cancelButton = { | |
96 text = "Cancel", | |
97 tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Cancel"), | |
98 tooltip = (not addon.db.profile.defaults.hideHelp and "Do not move anything and close the window."), | |
99 onClick = OnMoveCancel, | |
100 }; | |
101 | |
102 addon:SetFrameSettings("Inventorium Bank Refill", "The items listed below can be refilled from this location, do you wish to move them to your bags?", proceedButton, cancelButton, headers); | |
26 end | 103 end |
27 | 104 |
28 function mod:ClearCache() | 105 function mod:ClearCache() |
29 table.wipe(itemCache); | 106 table.wipe(itemCache); |
30 end | 107 end |
74 slotId = (slotId - 1); | 151 slotId = (slotId - 1); |
75 end | 152 end |
76 end | 153 end |
77 elseif location == addon.Locations.Guild then | 154 elseif location == addon.Locations.Guild then |
78 for tabId = 1, GetNumGuildBankTabs() do | 155 for tabId = 1, GetNumGuildBankTabs() do |
79 local isViewable = select(3, GetGuildBankTabInfo(tabId)); | 156 local _, _, isViewable, _, _, remainingWithdrawals = GetGuildBankTabInfo(tabId); |
80 | 157 |
81 if isViewable == 1 then | 158 if isViewable and (remainingWithdrawals > 0 or remainingWithdrawals == -1) then |
82 local slotId = (MAX_GUILDBANK_SLOTS_PER_TAB or 98); -- start by scanning the last slot | 159 local slotId = (MAX_GUILDBANK_SLOTS_PER_TAB or 98); -- start by scanning the last slot |
83 | 160 |
84 while slotId ~= 0 do | 161 while slotId ~= 0 do |
85 -- A not equal-comparison should be quicker than a larger than-comparison | 162 -- A not equal-comparison should be quicker than a larger than-comparison |
86 | 163 |
106 -- Continue scanning a different slot | 183 -- Continue scanning a different slot |
107 slotId = (slotId - 1); | 184 slotId = (slotId - 1); |
108 end | 185 end |
109 end | 186 end |
110 end | 187 end |
188 elseif location == addon.Locations.Mailbox then | |
189 for mailIndex = 1, GetInboxNumItems() do | |
190 -- All mail items | |
191 | |
192 for attachIndex = 1, ATTACHMENTS_MAX_RECEIVE do | |
193 -- All attachments | |
194 | |
195 local itemLink = GetInboxItemLink(mailIndex, attachIndex); | |
196 local itemId = itemLink and addon:GetItemId(itemLink); | |
197 local itemCount = itemLink and select(3, GetInboxItem(mailIndex, attachIndex)); | |
198 | |
199 if itemLink and itemId and itemCount and itemCount > 0 then | |
200 local itemMove; | |
201 if not itemCache[itemId] then | |
202 -- If this is the first time we see this item, make a new object | |
203 itemMove = addon.ContainerItem:New(); | |
204 itemCache[itemId] = itemMove; | |
205 else | |
206 -- If we had this item in another slot too | |
207 itemMove = itemCache[itemId]; | |
208 end | |
209 | |
210 itemMove:AddLocation(mailIndex, attachIndex, itemCount); | |
211 end | |
212 end | |
213 end | |
214 elseif location == addon.Locations.Merchant then | |
215 for itemIndex = 1, GetMerchantNumItems() do | |
216 -- All merchant items | |
217 | |
218 local itemLink = GetMerchantItemLink(itemIndex); | |
219 local itemId = itemLink and addon:GetItemId(itemLink); | |
220 local _, _, vendorValue, _, numAvailable, _, extendedCost = GetMerchantItemInfo(index); | |
221 | |
222 if itemLink and itemId and numAvailable ~= 0 and not extendedCost then | |
223 local itemMove; | |
224 if not itemCache[itemId] then | |
225 -- If this is the first time we see this item, make a new object | |
226 itemMove = addon.ContainerItem:New(); | |
227 itemCache[itemId] = itemMove; | |
228 else | |
229 -- If we had this item in another slot too | |
230 itemMove = itemCache[itemId]; | |
231 end | |
232 | |
233 itemMove:AddLocation(1, itemIndex, numAvailable, vendorValue); | |
234 end | |
235 end | |
111 else | 236 else |
112 error("Invalid location provided for CacheLocation. Must be Bank or Guild."); | 237 error("Invalid location provided for CacheLocation. Must be Bank or Guild."); |
113 end | 238 end |
114 | 239 |
115 if not remember then | 240 if not remember then |
123 end | 248 end |
124 | 249 |
125 function mod:Scan(location) | 250 function mod:Scan(location) |
126 -- We might pause the scanning when we invoke moves ourself | 251 -- We might pause the scanning when we invoke moves ourself |
127 if paused then | 252 if paused then |
253 addon:Debug("Not scanning; paused..."); | |
128 return; | 254 return; |
129 end | 255 end |
130 | 256 |
131 local playerName = UnitName("player"); | 257 local playerName = UnitName("player"); |
132 | 258 |
133 currentLocation = location; | 259 currentLocation = location; |
134 self:CacheLocation(location, true); | 260 self:CacheLocation(location, true); |
261 | |
262 -- Ensure previous queue isn't remaining | |
263 Mover:ResetQueue(); | |
135 | 264 |
136 -- Go through all groups | 265 -- Go through all groups |
137 for groupName, values in pairs(addon.db.profile.groups) do | 266 for groupName, values in pairs(addon.db.profile.groups) do |
138 local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters"); | 267 local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters"); |
139 local localItemData = addon:GetOptionByKey(groupName, "localItemData"); | 268 local localItemData = addon:GetOptionByKey(groupName, "localItemData"); |
151 | 280 |
152 if itemCache[itemId] and missingItems > 0 then | 281 if itemCache[itemId] and missingItems > 0 then |
153 -- Check how many are available | 282 -- Check how many are available |
154 local availableItems = ((itemCache[itemId] and itemCache[itemId].totalCount) or 0); | 283 local availableItems = ((itemCache[itemId] and itemCache[itemId].totalCount) or 0); |
155 -- Calculate how many we'll be moving (less missing than available? use missing, otherwise use available) | 284 -- Calculate how many we'll be moving (less missing than available? use missing, otherwise use available) |
156 local moving = (((missingItems <= availableItems) and missingItems) or availableItems); | 285 local moving = (((availableItems == -1 or missingItems <= availableItems) and missingItems) or availableItems); |
157 | 286 |
158 if availableItems > 0 then | 287 if availableItems ~= 0 then |
159 --addon:Print("Insufficient " .. IdToItemLink(itemId) .. " but this location has " .. availableItems .. " (moving " .. moving .. ")"); | 288 addon:Debug("Insufficient %s but this location has %s (moving %d)", IdToItemLink(itemId), ((availableItems == -1 and "unlimited") or availableItems), moving); |
160 | 289 |
161 Mover:AddMove(itemId, moving, missingItems, availableItems); | 290 Mover:AddMove(itemId, moving, missingItems, availableItems, itemCache[itemId]:GetVendorPrice()); |
162 else | |
163 --addon:Print("Insufficient " .. IdToItemLink(itemId)); | |
164 end | 291 end |
165 end | 292 end |
166 end | 293 end |
167 end | 294 end |
168 end | 295 end |
169 | 296 |
170 self:ClearCache(); | 297 self:ClearCache(); |
171 | 298 |
172 if Mover:HasMoves() then | 299 if Mover:HasMoves() then |
173 if addon.db.profile.defaults.autoRefillSkipConfirm then | 300 if addon.db.profile.defaults.autoRefillSkipConfirm then |
174 OnMoveAccept(true); | 301 OnMoveAccept(); |
175 else | 302 else |
303 UseStorageRefillST((location == addon.Locations.Merchant)); | |
304 | |
176 -- This table is never copied, just referenced. It is the same for every row. | 305 -- This table is never copied, just referenced. It is the same for every row. |
177 local columns = { | 306 local columns = { |
178 { | 307 { |
179 value = function(data, cols, realrow, column, table) | 308 ["value"] = function(data, cols, realrow, column, table) |
180 return IdToItemLink(data[realrow].rowData.id); | 309 return IdToItemLink(data[realrow].rowData.itemId); |
181 end, | 310 end, |
182 }, -- item | 311 }, -- item |
183 { | 312 { |
184 value = function(data, cols, realrow, column, table) | 313 ["value"] = function(data, cols, realrow, column, table) |
185 return data[realrow].rowData.num; | 314 return data[realrow].rowData.num; |
186 end, | 315 end, |
187 }, -- moving | 316 }, -- moving |
188 { | 317 { |
189 value = function(data, cols, realrow, column, table) | 318 ["value"] = function(data, cols, realrow, column, table) |
190 return addon:DisplayItemCount(data[realrow].rowData.available, data[realrow].rowData.missing); -- available / missing | 319 return addon:DisplayItemCount(data[realrow].rowData.available, data[realrow].rowData.missing); -- available / missing |
191 end, | 320 end, |
192 color = function(data, cols, realrow, column, table) | 321 ["color"] = function(data, cols, realrow, column, table) |
193 return ((data[realrow].rowData.available < data[realrow].rowData.missing) and { r = 1, g = 0, b = 0, a = 1 }) or { r = 1, g = 1, b = 1, a = 1 }; | 322 return ((data[realrow].rowData.available < data[realrow].rowData.missing) and { r = 1, g = 0, b = 0, a = 1 }) or { r = 1, g = 1, b = 1, a = 1 }; |
194 end, | 323 end, |
195 }, -- missing / available | 324 }, -- missing / available |
196 }; | 325 }; |
326 if location == addon.Locations.Merchant then | |
327 table.insert(columns, { | |
328 ["value"] = function(data, cols, realrow, column, table) | |
329 return GetCoinTextureString(data[realrow].rowData.price * data[realrow].rowData.num); | |
330 end, | |
331 }); | |
332 end | |
197 | 333 |
198 -- Store the list with rows in this | 334 -- Store the list with rows in this |
199 local data = {}; | 335 local data = {}; |
200 | 336 |
201 for i, move in pairs(Mover:GetMoves()) do | 337 for i, move in pairs(Mover:GetMoves()) do |
277 | 413 |
278 scanned = nil; | 414 scanned = nil; |
279 | 415 |
280 -- Get the contents for every tab into our cache | 416 -- Get the contents for every tab into our cache |
281 for tabId = 1, GetNumGuildBankTabs() do | 417 for tabId = 1, GetNumGuildBankTabs() do |
282 local isViewable = select(3, GetGuildBankTabInfo(tabId)); | 418 local _, _, isViewable, _, _, remainingWithdrawals = GetGuildBankTabInfo(tabId); |
283 if isViewable == 1 then | 419 |
420 if isViewable and (remainingWithdrawals > 0 or remainingWithdrawals == -1) then | |
284 QueryGuildBankTab(tabId); | 421 QueryGuildBankTab(tabId); |
285 end | 422 end |
286 end | 423 end |
287 | 424 |
288 self:RegisterEvent("GUILDBANKFRAME_CLOSED"); | 425 self:RegisterEvent("GUILDBANKFRAME_CLOSED"); |
289 self:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED"); | 426 self:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED"); |
290 end | 427 end |
428 | |
429 function mod:MERCHANT_SHOW() | |
430 addon:Debug("Scanner:MERCHANT_SHOW"); | |
431 | |
432 self:RegisterEvent("MERCHANT_CLOSED"); | |
433 | |
434 self:Scan(addon.Locations.Merchant); | |
435 end | |
436 | |
437 function mod:MERCHANT_CLOSED() | |
438 addon:Debug("Scanner:MERCHANT_CLOSED"); | |
439 | |
440 self:ClearCache(); | |
441 | |
442 self:UnregisterEvent("MERCHANT_CLOSED"); | |
443 | |
444 InventoriumItemMover:Hide(); | |
445 Mover:ResetQueue(); | |
446 end | |
447 | |
448 --local previousMailCount; | |
449 --function mod:MAIL_SHOW() | |
450 -- addon:Debug("Scanner:MAIL_SHOW"); | |
451 -- | |
452 -- self:RegisterEvent("MAIL_INBOX_UPDATE"); | |
453 -- self:RegisterEvent("MAIL_CLOSED"); | |
454 -- | |
455 -- scanned = nil; | |
456 -- previousMailCount = nil; | |
457 -- | |
458 -- self:Scan(addon.Locations.Mailbox); | |
459 --end | |
460 | |
461 --function mod:MAIL_INBOX_UPDATE() | |
462 -- if not scanned then | |
463 -- addon:Debug("Scanner:MAIL_INBOX_UPDATE"); | |
464 -- | |
465 -- local current, total = GetInboxNumItems(); | |
466 -- | |
467 -- if not previousMailCount or current > previousMailCount then | |
468 -- -- New mail received | |
469 -- | |
470 -- scanned = true; | |
471 -- | |
472 -- self:Scan(addon.Locations.Mailbox); | |
473 -- end | |
474 -- | |
475 -- -- Also remember the new mailcount when losing items, otherwise deleting item 50 and getting to 50 again wouldn't trigger a re-scan | |
476 -- previousMailCount = current; | |
477 -- else | |
478 -- addon:Debug("Scanner:MAIL_INBOX_UPDATE skipped, already scanned"); | |
479 -- end | |
480 --end | |
481 | |
482 --function mod:MAIL_CLOSED() | |
483 -- addon:Debug("Scanner:MAIL_CLOSED"); | |
484 -- | |
485 -- previousMailCount = nil; | |
486 -- scanned = nil; | |
487 -- self:ClearCache(); | |
488 -- | |
489 -- self:UnregisterEvent("MAIL_INBOX_UPDATE"); | |
490 -- self:UnregisterEvent("MAIL_CLOSED"); | |
491 -- | |
492 -- InventoriumItemMover:Hide(); | |
493 -- Mover:ResetQueue(); | |
494 --end | |
291 | 495 |
292 function mod:OnEnable() | 496 function mod:OnEnable() |
293 -- Scan once when the bankframe is opened | 497 -- Scan once when the bankframe is opened |
294 self:RegisterEvent("BANKFRAME_OPENED"); | 498 self:RegisterEvent("BANKFRAME_OPENED"); |
295 self:RegisterEvent("GUILDBANKFRAME_OPENED"); | 499 self:RegisterEvent("GUILDBANKFRAME_OPENED"); |
500 -- self:RegisterEvent("MAIL_SHOW"); | |
501 self:RegisterEvent("MERCHANT_SHOW"); | |
296 | 502 |
297 Mover = addon:GetModule("Mover"); | 503 Mover = addon:GetModule("Mover"); |
298 | 504 |
299 if not InventoriumItemMover then | 505 if not InventoriumItemMover then |
300 addon:CreateMoverFrame(OnMoveAccept, OnMoveCancel); | 506 addon:CreateMoverFrame(OnMoveAccept, OnMoveCancel); |
305 Mover = nil; | 511 Mover = nil; |
306 currentLocation = nil; | 512 currentLocation = nil; |
307 paused = nil; | 513 paused = nil; |
308 | 514 |
309 -- Bank | 515 -- Bank |
516 self:BANKFRAME_CLOSED(); | |
310 self:UnregisterEvent("BANKFRAME_OPENED"); | 517 self:UnregisterEvent("BANKFRAME_OPENED"); |
311 | 518 |
312 -- Guild | 519 -- Guild |
313 self:GUILDBANKFRAME_CLOSED(); | 520 self:GUILDBANKFRAME_CLOSED(); |
314 self:UnregisterEvent("GUILDBANKFRAME_OPENED"); | 521 self:UnregisterEvent("GUILDBANKFRAME_OPENED"); |
522 | |
523 -- -- Mailbox | |
524 -- self:MAIL_CLOSED(); | |
525 -- self:UnregisterEvent("MAIL_SHOW"); | |
315 end | 526 end |
316 | 527 |
317 function mod:Pause() | 528 function mod:Pause() |
318 paused = true; | 529 paused = true; |
319 end | 530 end |