Mercurial > wow > inventory
comparison Modules/Scanner.lua @ 119:dc6f405c1a5d
Now resizing the mover frame based on text size.
addon.Locations table now uses location names as value, rather than random numbers.
Added proper Merchant restocking support. Please note this currently doesn?t take the bonus queue nor the min crafting queue options into account.
author | Zerotorescue |
---|---|
date | Sat, 15 Jan 2011 17:03:05 +0100 |
parents | 239e25a058c7 |
children | 6724bc8eface |
comparison
equal
deleted
inserted
replaced
118:de18ef96983b | 119:dc6f405c1a5d |
---|---|
16 currentLocation = nil; | 16 currentLocation = nil; |
17 | 17 |
18 InventoriumItemMover:Hide(); | 18 InventoriumItemMover:Hide(); |
19 end | 19 end |
20 | 20 |
21 local function GetSmallCoinTextureString(coins) | |
22 if coins >= 10000000 then | |
23 -- When we have1000g, hide silver and copper | |
24 coins = (math.ceil(coins / 10000) * 10000); | |
25 elseif coins >= 10000 then | |
26 -- When we have 1g, hide copper | |
27 coins = (math.ceil(coins / 100) * 100); | |
28 end | |
29 | |
30 return GetCoinTextureString(coins); | |
31 end | |
32 | |
33 -- Refill moves window: refill form storage such as the bank, guild bank and mailbox | |
21 local function UseStorageRefillST() | 34 local function UseStorageRefillST() |
22 local frame = InventoriumItemMover; -- both for speed as code-consistency | 35 local frame = InventoriumItemMover; -- both for speed as code-consistency |
23 | 36 |
24 -- Scrolling table with a list of items to be moved | 37 -- Scrolling table with a list of items to be moved |
25 local scrollTableWidth = ( frame.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size | 38 local scrollTableWidth = ( frame.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size |
86 tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Cancel"), | 99 tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Cancel"), |
87 tooltip = (not addon.db.profile.defaults.hideHelp and "Do not move anything and close the window."), | 100 tooltip = (not addon.db.profile.defaults.hideHelp and "Do not move anything and close the window."), |
88 onClick = OnMoveCancel, | 101 onClick = OnMoveCancel, |
89 }; | 102 }; |
90 | 103 |
91 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); | 104 addon:SetFrameSettings("Inventorium Storage Refill", "The items listed below can be refilled from this location, do you wish to move them to your bags?", proceedButton, cancelButton, headers); |
105 end | |
106 | |
107 -- Merchant restock window: restock from a merchant by buying items needed | |
108 local function UseMerchantRestockST(totalCost) | |
109 local frame = InventoriumItemMover; -- both for speed as code-consistency | |
110 | |
111 -- Scrolling table with a list of items to be moved | |
112 local scrollTableWidth = ( frame.frmMeasureDummy:GetWidth() - 30 ); -- adjust width by the scrollbar size | |
113 local headers = { | |
114 { | |
115 ["name"] = "Item", | |
116 ["width"] = (scrollTableWidth * .60), | |
117 ["defaultsort"] = "asc", | |
118 ["comparesort"] = function(this, aRow, bRow, column) | |
119 local aName, _, aRarity = GetItemInfo(this:GetRow(aRow).rowData.itemId); | |
120 local bName, _, bRarity = GetItemInfo(this:GetRow(bRow).rowData.itemId); | |
121 local template = "%d%s"; | |
122 aName = template:format((10 - (aRarity or 10)), (aName or ""):lower()); | |
123 bName = template:format((10 - (bRarity or 10)), (bName or ""):lower()); | |
124 | |
125 if this.cols[column].sort == "dsc" then | |
126 return aName > bName; | |
127 else | |
128 return aName < bName; | |
129 end | |
130 end, | |
131 ["sort"] = "asc", -- when the data is set, use this column so sort the default data | |
132 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Item"), | |
133 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by item quality then item name."), | |
134 }, | |
135 { | |
136 ["name"] = "Buying", | |
137 ["width"] = (scrollTableWidth * .20), | |
138 ["align"] = "RIGHT", | |
139 ["defaultsort"] = "dsc", | |
140 ["sortnext"] = 1, | |
141 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Buying"), | |
142 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the amount of purchasable items."), | |
143 }, | |
144 { | |
145 ["name"] = "Cost", | |
146 ["width"] = (scrollTableWidth * .20), | |
147 ["align"] = "RIGHT", | |
148 ["defaultsort"] = "dsc", | |
149 ["sortnext"] = 1, | |
150 ["tooltipTitle"] = (not addon.db.profile.defaults.hideHelp and "Cost"), | |
151 ["tooltip"] = (not addon.db.profile.defaults.hideHelp and "Click to sort the list by the total cost of buying all these items."), | |
152 }, | |
153 }; | |
154 | |
155 local proceedButton = { | |
156 text = "Purchase Items", | |
157 tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Purchase Items"), | |
158 tooltip = (not addon.db.profile.defaults.hideHelp and "Start purchasing these items from this merchant."), | |
159 onClick = OnMoveAccept, | |
160 }; | |
161 local cancelButton = { | |
162 text = "Cancel", | |
163 tooltipTitle = (not addon.db.profile.defaults.hideHelp and "Cancel"), | |
164 tooltip = (not addon.db.profile.defaults.hideHelp and "Do not purchase anything and close the window."), | |
165 onClick = OnMoveCancel, | |
166 }; | |
167 | |
168 addon:SetFrameSettings("Inventorium Merchant Restock", ("The following items can be restocked from this merchant for a total of %s. Do you wish to proceed?"):format(GetSmallCoinTextureString(totalCost)), proceedButton, cancelButton, headers); | |
92 end | 169 end |
93 | 170 |
94 function mod:ClearCache() | 171 function mod:ClearCache() |
95 table.wipe(itemCache); | 172 table.wipe(itemCache); |
96 end | 173 end |
121 | 198 |
122 local itemId = GetContainerItemID(bagId, slotId); | 199 local itemId = GetContainerItemID(bagId, slotId); |
123 local itemCount = itemId and select(2, GetContainerItemInfo(bagId, slotId)); | 200 local itemCount = itemId and select(2, GetContainerItemInfo(bagId, slotId)); |
124 | 201 |
125 if itemId and itemCount and itemCount > 0 then | 202 if itemId and itemCount and itemCount > 0 then |
126 local itemMove; | 203 local containerItem; |
127 if not itemCache[itemId] then | 204 if not itemCache[itemId] then |
128 -- If this is the first time we see this item, make a new object | 205 -- If this is the first time we see this item, make a new object |
129 itemMove = addon.ContainerItem:New(); | 206 containerItem = addon.ContainerItem:New(); |
130 itemCache[itemId] = itemMove; | 207 itemCache[itemId] = containerItem; |
131 else | 208 else |
132 -- If we had this item in another slot too | 209 -- If we had this item in another slot too |
133 itemMove = itemCache[itemId]; | 210 containerItem = itemCache[itemId]; |
134 end | 211 end |
135 | 212 |
136 itemMove:AddLocation(bagId, slotId, itemCount); | 213 containerItem:AddLocation(bagId, slotId, itemCount); |
137 end | 214 end |
138 | 215 |
139 -- Continue scanning a different slot | 216 -- Continue scanning a different slot |
140 slotId = (slotId - 1); | 217 slotId = (slotId - 1); |
141 end | 218 end |
154 local itemId = itemLink and addon:GetItemId(itemLink); | 231 local itemId = itemLink and addon:GetItemId(itemLink); |
155 local itemCount = itemLink and select(2, GetGuildBankItemInfo(tabId, slotId)); | 232 local itemCount = itemLink and select(2, GetGuildBankItemInfo(tabId, slotId)); |
156 | 233 |
157 if itemLink and itemId and itemCount and itemCount > 0 then | 234 if itemLink and itemId and itemCount and itemCount > 0 then |
158 -- If there is actually an item in this slot | 235 -- If there is actually an item in this slot |
159 local itemMove; | 236 local containerItem; |
160 if not itemCache[itemId] then | 237 if not itemCache[itemId] then |
161 -- If this is the first time we see this item, make a new object | 238 -- If this is the first time we see this item, make a new object |
162 itemMove = addon.ContainerItem:New(); | 239 containerItem = addon.ContainerItem:New(); |
163 itemCache[itemId] = itemMove; | 240 itemCache[itemId] = containerItem; |
164 else | 241 else |
165 -- If we had this item in another slot too | 242 -- If we had this item in another slot too |
166 itemMove = itemCache[itemId]; | 243 containerItem = itemCache[itemId]; |
167 end | 244 end |
168 | 245 |
169 itemMove:AddLocation(tabId, slotId, itemCount); | 246 containerItem:AddLocation(tabId, slotId, itemCount); |
170 end | 247 end |
171 | 248 |
172 -- Continue scanning a different slot | 249 -- Continue scanning a different slot |
173 slotId = (slotId - 1); | 250 slotId = (slotId - 1); |
174 end | 251 end |
184 local itemLink = GetInboxItemLink(mailIndex, attachIndex); | 261 local itemLink = GetInboxItemLink(mailIndex, attachIndex); |
185 local itemId = itemLink and addon:GetItemId(itemLink); | 262 local itemId = itemLink and addon:GetItemId(itemLink); |
186 local itemCount = itemLink and select(3, GetInboxItem(mailIndex, attachIndex)); | 263 local itemCount = itemLink and select(3, GetInboxItem(mailIndex, attachIndex)); |
187 | 264 |
188 if itemLink and itemId and itemCount and itemCount > 0 then | 265 if itemLink and itemId and itemCount and itemCount > 0 then |
189 local itemMove; | 266 local containerItem; |
190 if not itemCache[itemId] then | 267 if not itemCache[itemId] then |
191 -- If this is the first time we see this item, make a new object | 268 -- If this is the first time we see this item, make a new object |
192 itemMove = addon.ContainerItem:New(); | 269 containerItem = addon.ContainerItem:New(); |
193 itemCache[itemId] = itemMove; | 270 itemCache[itemId] = containerItem; |
194 else | 271 else |
195 -- If we had this item in another slot too | 272 -- If we had this item in another slot too |
196 itemMove = itemCache[itemId]; | 273 containerItem = itemCache[itemId]; |
197 end | 274 end |
198 | 275 |
199 itemMove:AddLocation(mailIndex, attachIndex, itemCount); | 276 containerItem:AddLocation(mailIndex, attachIndex, itemCount); |
200 end | 277 end |
201 end | 278 end |
202 end | 279 end |
280 elseif location == addon.Locations.Merchant then | |
281 for itemIndex = 1, GetMerchantNumItems() do | |
282 -- All merchant items | |
283 | |
284 local itemLink = GetMerchantItemLink(itemIndex); | |
285 local itemId = itemLink and addon:GetItemId(itemLink); | |
286 local _, _, vendorValue, quantity, numAvailable, _, extendedCost = GetMerchantItemInfo(itemIndex); | |
287 | |
288 if itemLink and itemId and numAvailable ~= 0 and not extendedCost then | |
289 local containerItem; | |
290 if not itemCache[itemId] then | |
291 -- If this is the first time we see this item, make a new object | |
292 containerItem = addon.ContainerItem:New(); | |
293 containerItem.price = (vendorValue / quantity); -- remember the price for this item. We assume it's the same for this entire item id | |
294 | |
295 itemCache[itemId] = containerItem; | |
296 else | |
297 -- If we had this item in another slot too | |
298 containerItem = itemCache[itemId]; | |
299 end | |
300 | |
301 containerItem:AddLocation(1, itemIndex, numAvailable); | |
302 end | |
303 end | |
203 else | 304 else |
204 error("Invalid location provided for CacheLocation. Must be Bank or Guild."); | 305 error("Invalid location provided for CacheLocation."); |
205 end | 306 end |
206 | 307 |
207 if not remember then | 308 if not remember then |
208 -- Copy the table as clearing the cache wipes it empty (and tables are passed by reference) | 309 -- Copy the table as clearing the cache wipes it empty (and tables are passed by reference) |
209 local cacheCopy = CopyTable(itemCache); | 310 local cacheCopy = CopyTable(itemCache); |
227 self:CacheLocation(location, true); | 328 self:CacheLocation(location, true); |
228 | 329 |
229 -- Ensure previous queue isn't remaining | 330 -- Ensure previous queue isn't remaining |
230 Mover:ResetQueue(); | 331 Mover:ResetQueue(); |
231 | 332 |
333 -- Restock = obtaining more, refill = merely moving local. IsRestock = are we buying/making more? | |
334 local isRestock = (location == addon.Locations.Merchant); | |
335 | |
232 -- Go through all groups | 336 -- Go through all groups |
233 for groupName, values in pairs(addon.db.profile.groups) do | 337 for groupName, values in pairs(addon.db.profile.groups) do |
338 -- Settings | |
234 local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters"); | 339 local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters"); |
235 local localItemData = addon:GetOptionByKey(groupName, "localItemData"); | 340 local localItemData = addon:GetOptionByKey(groupName, "localItemData"); |
236 | 341 local isRefillEnabled = addon:GetOptionByKey(groupName, "autoRefill"); |
237 if values.items and trackAt[playerName] and addon:GetOptionByKey(groupName, "autoRefill") and (location ~= addon.Locations.Bank or not localItemData or not localItemData["Bank"]) then | 342 local requiredItems = ((isRestock and addon:GetOptionByKey(groupName, "restockTarget")) or addon:GetOptionByKey(groupName, "minLocalStock")); |
238 -- Is this character interested in this data? | 343 |
239 | 344 local isTracked = (trackAt and trackAt[playerName]); -- Is this character interested in this data? |
240 local minLocalStock = addon:GetOptionByKey(groupName, "minLocalStock"); | 345 local isConsideredLocal = (localItemData and localItemData[location]); -- if this location was checked as local storage, don't refill from it |
241 | 346 |
242 -- Go through all items | 347 if values.items and isTracked and (isRefillEnabled or isRestock) and not isConsideredLocal then |
348 addon:Debug("Scanning |cff00ff00%s|r", groupName); | |
349 | |
243 for itemId, _ in pairs(values.items) do | 350 for itemId, _ in pairs(values.items) do |
244 | 351 -- Find this item in the source |
245 -- Check if we have enough items local (but only do so if this location also has enough available) | 352 local containerItem = itemCache[itemId]; |
246 local missingItems = itemCache[itemId] and (minLocalStock - addon:GetLocalItemCount(itemId, groupName)); | 353 |
247 | 354 if containerItem then |
248 if itemCache[itemId] and missingItems > 0 then | 355 -- Only do all the CPU intensive checks if this item is available |
249 -- Check how many are available | 356 |
250 local availableItems = ((itemCache[itemId] and itemCache[itemId].totalCount) or 0); | 357 -- When restocking use the global item count, when refilling use the local |
251 -- Calculate how many we'll be moving (less missing than available? use missing, otherwise use available) | 358 local currentItemCount = ((isRestock and addon:GetItemCount(itemId, groupName)) or addon:GetLocalItemCount(itemId, groupName)); |
252 local moving = ((missingItems <= availableItems and missingItems) or availableItems); | 359 |
253 | 360 -- Check if we have enough items local (but only do so if this location also has enough available) |
254 if availableItems > 0 then | 361 local missingItems = (requiredItems - currentItemCount); |
255 addon:Debug("Insufficient %s but this location has %d (moving %d)", IdToItemLink(itemId), availableItems, moving); | 362 |
363 if missingItems > 0 then | |
364 -- Check how many are available | |
365 local availableItems = ((containerItem.totalCount) or 0); | |
366 -- Calculate how many we'll be moving (less missing than available? use missing, otherwise use available) | |
367 -- -1 available items indicates unlimited amount, in that case we must cap at missing items | |
368 local moving = (((availableItems == -1 or missingItems <= availableItems) and missingItems) or availableItems); | |
256 | 369 |
257 Mover:AddMove(itemId, moving, missingItems, availableItems); | 370 if availableItems == -1 or availableItems > 0 then |
371 addon:Debug("Insufficient %s but this location has %d (moving %d)", IdToItemLink(itemId), availableItems, moving); | |
372 | |
373 Mover:AddMove(itemId, moving, missingItems, availableItems, containerItem.price); | |
374 end | |
258 end | 375 end |
259 end | 376 end |
260 end | 377 end |
261 end | 378 end |
262 end | 379 end |
265 | 382 |
266 if Mover:HasMoves() then | 383 if Mover:HasMoves() then |
267 if addon.db.profile.defaults.autoRefillSkipConfirm then | 384 if addon.db.profile.defaults.autoRefillSkipConfirm then |
268 OnMoveAccept(); | 385 OnMoveAccept(); |
269 else | 386 else |
270 UseStorageRefillST(); | 387 local moves = Mover:GetMoves(); |
271 | 388 |
272 -- This table is never copied, just referenced. It is the same for every row. | 389 -- This table is never copied, just referenced. It is the same for every row. |
273 local columns = { | 390 local columns; |
274 { | 391 |
275 ["value"] = function(data, cols, realrow, column, table) | 392 if isRestock then |
276 return IdToItemLink(data[realrow].rowData.itemId); | 393 local totalCost = 0; |
277 end, | 394 for _, move in pairs(moves) do |
278 }, -- item | 395 totalCost = (totalCost + (move.cost * move.num)); |
279 { | 396 end |
280 ["value"] = function(data, cols, realrow, column, table) | 397 UseMerchantRestockST(totalCost); |
281 return data[realrow].rowData.num; | 398 |
282 end, | 399 columns = { |
283 }, -- moving | 400 { |
284 { | 401 ["value"] = function(data, cols, realrow, column, table) |
285 ["value"] = function(data, cols, realrow, column, table) | 402 return IdToItemLink(data[realrow].rowData.itemId); |
286 return addon:DisplayItemCount(data[realrow].rowData.available, data[realrow].rowData.missing); -- available / missing | 403 end, |
287 end, | 404 }, -- item |
288 ["color"] = function(data, cols, realrow, column, table) | 405 { |
289 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 }; | 406 ["value"] = function(data, cols, realrow, column, table) |
290 end, | 407 return data[realrow].rowData.num; |
291 }, -- missing / available | 408 end, |
292 }; | 409 }, -- buying |
410 { | |
411 ["value"] = function(data, cols, realrow, column, table) | |
412 return GetSmallCoinTextureString((data[realrow].rowData.cost * data[realrow].rowData.num)); | |
413 end, | |
414 }, -- cost | |
415 }; | |
416 else | |
417 UseStorageRefillST(); | |
418 | |
419 columns = { | |
420 { | |
421 ["value"] = function(data, cols, realrow, column, table) | |
422 return IdToItemLink(data[realrow].rowData.itemId); | |
423 end, | |
424 }, -- item | |
425 { | |
426 ["value"] = function(data, cols, realrow, column, table) | |
427 return data[realrow].rowData.num; | |
428 end, | |
429 }, -- moving | |
430 { | |
431 ["value"] = function(data, cols, realrow, column, table) | |
432 return addon:DisplayItemCount(data[realrow].rowData.available, data[realrow].rowData.missing); -- available / missing | |
433 end, | |
434 ["color"] = function(data, cols, realrow, column, table) | |
435 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 }; | |
436 end, | |
437 }, -- missing / available | |
438 }; | |
439 end | |
293 | 440 |
294 -- Store the list with rows in this | 441 -- Store the list with rows in this |
295 local data = {}; | 442 local data = {}; |
296 | 443 |
297 for i, move in pairs(Mover:GetMoves()) do | 444 for i, move in pairs(moves) do |
298 table.insert(data, { | 445 table.insert(data, { |
299 ["rowData"] = move, -- this is not a key usually found in a row item and ignored by the library | 446 ["rowData"] = move, -- this is not a key usually found in a row item and ignored by the library |
300 ["cols"] = columns, | 447 ["cols"] = columns, |
301 }); | 448 }); |
302 end | 449 end |
384 | 531 |
385 self:RegisterEvent("GUILDBANKFRAME_CLOSED"); | 532 self:RegisterEvent("GUILDBANKFRAME_CLOSED"); |
386 self:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED"); | 533 self:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED"); |
387 end | 534 end |
388 | 535 |
536 function mod:MERCHANT_SHOW() | |
537 addon:Debug("Scanner:MERCHANT_SHOW"); | |
538 | |
539 self:RegisterEvent("MERCHANT_CLOSED"); | |
540 | |
541 self:Scan(addon.Locations.Merchant); | |
542 end | |
543 | |
544 function mod:MERCHANT_CLOSED() | |
545 addon:Debug("Scanner:MERCHANT_CLOSED"); | |
546 | |
547 self:ClearCache(); | |
548 | |
549 self:UnregisterEvent("MERCHANT_CLOSED"); | |
550 | |
551 InventoriumItemMover:Hide(); | |
552 Mover:ResetQueue(); | |
553 end | |
554 | |
389 local previousMailCount; | 555 local previousMailCount; |
390 function mod:MAIL_SHOW() | 556 function mod:MAIL_SHOW() |
391 addon:Debug("Scanner:MAIL_SHOW"); | 557 addon:Debug("Scanner:MAIL_SHOW"); |
392 | 558 |
393 self:RegisterEvent("MAIL_INBOX_UPDATE"); | 559 self:RegisterEvent("MAIL_INBOX_UPDATE"); |
437 function mod:OnEnable() | 603 function mod:OnEnable() |
438 -- Scan once when the bankframe is opened | 604 -- Scan once when the bankframe is opened |
439 self:RegisterEvent("BANKFRAME_OPENED"); | 605 self:RegisterEvent("BANKFRAME_OPENED"); |
440 self:RegisterEvent("GUILDBANKFRAME_OPENED"); | 606 self:RegisterEvent("GUILDBANKFRAME_OPENED"); |
441 self:RegisterEvent("MAIL_SHOW"); | 607 self:RegisterEvent("MAIL_SHOW"); |
608 self:RegisterEvent("MERCHANT_SHOW"); | |
442 | 609 |
443 Mover = addon:GetModule("Mover"); | 610 Mover = addon:GetModule("Mover"); |
444 | 611 |
445 if not InventoriumItemMover then | 612 if not InventoriumItemMover then |
446 addon:CreateMoverFrame(OnMoveAccept, OnMoveCancel); | 613 addon:CreateMoverFrame(OnMoveAccept, OnMoveCancel); |
461 self:UnregisterEvent("GUILDBANKFRAME_OPENED"); | 628 self:UnregisterEvent("GUILDBANKFRAME_OPENED"); |
462 | 629 |
463 -- Mailbox | 630 -- Mailbox |
464 self:MAIL_CLOSED(); | 631 self:MAIL_CLOSED(); |
465 self:UnregisterEvent("MAIL_SHOW"); | 632 self:UnregisterEvent("MAIL_SHOW"); |
633 | |
634 -- Merchant | |
635 self:MERCHANT_CLOSED(); | |
636 self:UnregisterEvent("MERCHANT_SHOW"); | |
466 end | 637 end |
467 | 638 |
468 function mod:Pause() | 639 function mod:Pause() |
469 paused = true; | 640 paused = true; |
470 end | 641 end |