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