vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --[[
2 DynamicData
3  
4 By sarf
5  
6 This mod allows you to access dynamic data in WoW without being forced to rely on strange Blizzard functions
7  
8 Thanks goes to the Sea people, the UltimateUI team and finally the nice (but strange) people at
9 #ultimateuitesters and Blizzard.
10  
11 UltimateUIUI URL:
12 http://www.ultimateuiui.org/forums/viewtopic.php?t=NOT_YET_ANNOUNCED
13  
14 ]]
15  
16 --[[
17 Information returned by the DynamicData.item.get*Info() methods
18  
19 An array is returned with the following values
20  
21 name -- the name of the item
22 strings -- an array with strings that represent the tooltip of the item
23 count -- the number of items like this the user currently possesses
24 texture
25 cooldown = -- the cooldown of the item
26 {
27 start -- time when the cooldown started
28 duration -- duration of the cooldown
29 enable -- 1 or 0
30 };
31  
32 -- each item may have these values:
33  
34 durability -- current durability
35 maxDurability -- maximum durability
36 itemType -- type of item
37 locked -- ?
38  
39 These values are 0 unless the item info derives from a ContainerInfo call (bag >= 0):
40  
41 quality -- degree of commonness
42 readable -- ?
43  
44 These values are 0 or "" unless the item info derives from a InventoryInfo call (bag == -1):
45  
46 broken -- true if broken, false if not
47 slotTexture -- background texture of the slot that the item resides in.
48  
49  
50 ]]--
51  
52  
53 DYNAMICDATA_ITEM_SCAN_TYPE_TOOLTIP = 1;
54 DYNAMICDATA_ITEM_SCAN_TYPE_ITEMINFO = 2;
55 DYNAMICDATA_ITEM_SCAN_TYPE_COOLDOWN = 4;
56 DYNAMICDATA_ITEM_SCAN_TYPE_EVERYTHING = 7;
57 DYNAMICDATA_ITEM_SCAN_TYPE_QUICK = 6;
58  
59  
60 -- Item information - what the player is wearing and so on.
61 DynamicData.item = {
62  
63 -- public functions
64  
65 --
66 -- addOnInventoryUpdateHandler (func)
67 --
68 -- Adds a function name that will be called on inventory updates.
69 -- Function will have two parameters:
70 -- bag, which may be nil.
71 -- scanType, which may be DYNAMICDATA_ITEM_SCAN_TYPE_*
72 --
73 addOnInventoryUpdateHandler = function (func)
74 return DynamicData.util.addOnWhateverHandler(DynamicData.item.OnInventoryUpdateHandlers, func);
75 end;
76  
77 --
78 -- removeOnInventoryUpdateHandler (func)
79 --
80 -- Removes the specified function, so that it will not be called on inventory updates.
81 --
82 removeOnInventoryUpdateHandler = function (func)
83 return DynamicData.util.removeOnWhateverHandler(DynamicData.item.OnInventoryUpdateHandlers, func);
84 end;
85  
86 -- LEGACY FUNCTION - covered in addOnInventoryUpdateHandler
87 --
88 -- addOnInventoryCooldownUpdateHandler (func)
89 --
90 -- Adds a function name that will be called on InventoryCooldown updates.
91 -- Function will have one paremeter - bag, which may be nil.
92 --
93 addOnInventoryCooldownUpdateHandler = function (func)
94 return DynamicData.util.addOnWhateverHandler(DynamicData.item.OnInventoryCooldownUpdateHandlers, func);
95 end;
96  
97 -- LEGACY FUNCTION - covered in removeOnInventoryUpdateHandler
98 --
99 -- removeOnInventoryCooldownUpdateHandler (func)
100 --
101 -- Removes the specified function, so that it will not be called on InventoryCooldown updates.
102 --
103 removeOnInventoryCooldownUpdateHandler = function (func)
104 return DynamicData.util.removeOnWhateverHandler(DynamicData.item.OnInventoryCooldownUpdateHandlers, func);
105 end;
106  
107 --
108 -- getEquippedSlotInfo (slot)
109 --
110 -- Retrieves information about the slot.
111 --
112 getEquippedSlotInfo = function (slot)
113 if ( ( DynamicData.item.player ) and ( DynamicData.item.player.itemsByBag ) and ( DynamicData.item.player.itemsByBag[-1] ) and ( DynamicData.item.player.itemsByBag[-1][slot] ) ) then
114 return DynamicData.item.player.itemsByBag[-1][slot];
115 else
116 return DynamicData.item.defaultItem;
117 end
118 end;
119  
120 --
121 -- getItemInfoByName (itemName)
122 --
123 -- Retrieves information about an item by name.
124 -- Adds a new variable called position with the position(s) of the item.
125 --
126 getItemInfoByName = function (itemName)
127 if ( ( DynamicData.item.player ) and ( DynamicData.item.player.itemsByBag ) ) then
128 local element = nil;
129 for bagNumber, bag in DynamicData.item.player.itemsByBag do
130 for slotNumber, slot in bag do
131 if ( slot.name == itemName ) then
132 if ( not element ) then
133 element = DynamicData.item.createBaseItem(slot);
134 else
135 if ( slot.count ) then
136 element.count = element.count + slot.count;
137 end
138 end
139 if ( not element.position ) then
140 element.position = {};
141 end
142 local positionArray = {};
143 positionArray.bag = bagNumber;
144 positionArray.slot = slotNumber;
145 table.insert(element.position, positionArray);
146 end
147 end
148 end
149 return element;
150 else
151 return DynamicData.item.defaultItem;
152 end
153 end;
154  
155 --
156 -- getItemInfoByType (itemType)
157 --
158 -- Retrieves information about items with the specific type. Includes a new cute variable called totalCount.
159 --
160 getItemInfoByType = function (itemName)
161 local bagNumber, bag;
162 local slotNumber, itemInfo;
163 local items = {};
164 for bagNumber, bag in DynamicData.item.player.itemsByBag do
165 for slotNumber, itemInfo in bag do
166 if ( itemInfo.itemType == itemType ) then
167 table.insert(items, DynamicData.item.getItemInfoByName(itemInfo.name));
168 end
169 end
170 end
171 return items;
172 end;
173  
174 --
175 -- getEquippedSlotCooldown (slot)
176 --
177 -- Retrieves cooldown information about the slot.
178 --
179 getEquippedSlotCooldown = function (slot)
180 if ( ( DynamicData.item.player ) and ( DynamicData.item.player.itemsByBag ) and ( DynamicData.item.player.itemsByBag[-1] ) and ( DynamicData.item.player.itemsByBag[-1][slot] ) ) then
181 local cooldown = DynamicData.item.player.itemsByBag[-1][slot].cooldown;
182 return cooldown[1], cooldown[2], cooldown[3];
183 else
184 return 0, 0, 0;
185 end
186 end;
187  
188 --
189 -- getInventoryInfo (bag, slot)
190 --
191 -- Retrieves information about the bag and slot.
192 --
193 getInventoryInfo = function (bag, slot)
194 DynamicData.item.scanInventorySlotIfTime(bag, slot);
195 local element = DynamicData.item.player.itemsByBag[bag][slot];
196 if ( not element ) then
197 element = DynamicData.item.defaultItem;
198 end
199 return element;
200 end;
201  
202 --
203 -- getInventoryName (bag, slot)
204 --
205 -- Retrieves the name of the item in the bag and slot.
206 --
207 getInventoryName = function (bag, slot)
208 if ( ( DynamicData.item.player ) and ( DynamicData.item.player.itemsByBag ) and ( DynamicData.item.player.itemsByBag[bag] ) and ( DynamicData.item.player.itemsByBag[bag][slot] ) ) then
209 local itemInfo = DynamicData.item.getInventoryInfo(bag, slot);
210 if ( ( not itemInfo ) or ( ( itemInfo.texture ) and ( strlen(itemInfo.texture) > 0 ) and ( ( not itemInfo.name ) or ( strlen(itemInfo.name) <= 0 ) ) ) ) then
211 DynamicData.item.scanItem(bag, slot);
212 itemInfo = DynamicData.item.player.itemsByBag[bag][slot];
213 end
214 return itemInfo.name;
215 else
216 return DynamicData.item.defaultItem.name;
217 end
218 end;
219  
220 --
221 -- getInventoryCooldownInfo (bag, slot)
222 --
223 -- Retrieves cooldown information about the bag and slot.
224 --
225 getInventoryCooldown = function (bag, slot)
226 if ( ( DynamicData.item.player ) and ( DynamicData.item.player.itemsByBag ) and ( DynamicData.item.player.itemsByBag[bag] ) and ( DynamicData.item.player.itemsByBag[bag][slot] ) ) then
227 local cooldown = DynamicData.item.player.itemsByBag[bag][slot].cooldown;
228 return cooldown[1], cooldown[2], cooldown[3];
229 else
230 return 0, 0, 0;
231 end
232 end;
233  
234 --
235 -- getEquippedSlotInfoBySlotName (slotName)
236 --
237 -- Retrieves information about the slot with the specified name.
238 --
239 getEquippedSlotInfoBySlotName = function (slotName)
240 for key, value in DynamicData.item.inventorySlotNames do
241 if ( value.name == slotName ) then
242 return DynamicData.item.getEquippedSlotInfo(value.id);
243 end
244 end
245 return DynamicData.item.defaultItem;
246 end;
247  
248 --
249 -- updateItems ()
250 --
251 -- Updates the inventory of the player.
252 --
253 updateItems = function (bag)
254 params = {
255 func = DynamicData.item.doUpdateItems,
256 params = { bag },
257 allowInitialUpdate = 1,
258 schedulingName = "DynamicData_item_UpdateItems",
259 };
260 --DynamicData.util.postpone(params);
261 DynamicData.item.doUpdateItems(bag);
262 end;
263  
264 --
265 -- updateItemCooldowns ()
266 --
267 -- Updates the cooldowns of the players items.
268 --
269 updateItemCooldowns = function ()
270 local safe = true; --DynamicData.util.safeToUseTooltips({"MerchantFrame", "TradeSkillFrame", "AuctionFrame"});
271 if ( not safe ) then
272 UltimateUI_ScheduleByName("DynamicData_item_updateItemCooldownsUnspecified", 0.1, DynamicData.item.updateItemCooldowns);
273 return;
274 end
275 DynamicData.item.doQuickScan();
276 --[[
277 local bag;
278 for bag = 0,4 do
279 DynamicData.item.doUpdateBagItemsCooldown(bag);
280 end
281 DynamicData.item.doUpdateBagItemsCooldown(-1);
282 bag = nil;
283 DynamicData.item.notifyUpdateHandlers(nil, DYNAMICDATA_ITEM_SCAN_TYPE_COOLDOWN);
284 DynamicData.item.notifyItemCooldownUpdateHandlers();
285 ]]--
286 end;
287  
288 --
289 -- updateItemLocks ()
290 --
291 -- Updates the locks of the players items.
292 --
293 updateItemLocks = function ()
294 DynamicData.item.updateItems();
295 end;
296  
297 --
298 -- updateItemAlerts ()
299 --
300 -- Updates the alerts of the players items.
301 -- You can never have too many lerts.
302 --
303 updateItemAlerts = function ()
304 DynamicData.item.updateItems();
305 end;
306  
307 -- protected functions
308  
309  
310 --
311 -- doUpdateSeperateBagItems (bag)
312 --
313 -- Updates a bag seperately from the rest of the inventory of the player.
314 -- Saves some time.
315 --
316 doUpdateSeperateBagItems = function (bag)
317 if ( not bag ) then
318 return;
319 end
320 if ( DynamicData.item.player.itemsByBag ) then
321 table.remove(DynamicData.item.player.itemsByBag, bag);
322 end
323 DynamicData.item.doUpdateBagItems(bag);
324 end;
325  
326 --
327 -- doUpdateBagItems (bag)
328 --
329 -- Updates a bag of the inventory of the player.
330 --
331 doUpdateBagItems = function (bag)
332 DynamicData.item.scanItemsInBag(bag);
333 end;
334  
335 --
336 -- doUpdateItems ()
337 --
338 -- Initiates updates of the inventory of the player.
339 --
340 doUpdateItems = function (bag)
341 local safe = true; --DynamicData.util.safeToUseTooltips({"MerchantFrame", "TradeSkillFrame", "AuctionFrame"});
342 if ( not safe ) then
343 if ( bag ) then
344 UltimateUI_ScheduleByName("DynamicData_item_doUpdateItems", 0.1, DynamicData.item.doUpdateItems, bag);
345 else
346 UltimateUI_ScheduleByName("DynamicData_item_doUpdateItemsUnspecified", 0.1, DynamicData.item.doUpdateItems);
347 end
348 return;
349 end
350 DynamicData.item.doQuickScan();
351 if ( ( bag ) and ( DynamicData.item.player ) ) then
352 --DynamicData.item.doQuickScan(bag);
353 --local scanLists = DynamicData.item.generateScanLists(nil, bag);
354 --DynamicData.item.addScans(scanLists);
355 DynamicData.item.makeScanLists(bag);
356 if ( not DynamicData.item.itemScanInProgress ) then
357 --DynamicData.item.doScans(nil, nil, bag);
358 DynamicData.item.doScans(nil, nil, bag);
359 --UltimateUI_ScheduleByName("DynamicData_Item_doScans", 0.1, DynamicData.item.doScans);
360 end
361 --DynamicData.item.doUpdateSeperateBagItems(bag);
362 --DynamicData.item.notifyUpdateHandlers(bag);
363 --DynamicData.item.notifyItemCooldownUpdateHandlers();
364 else
365 --DynamicData.item.player = {};
366 --local scanLists = DynamicData.item.generateScanLists();
367 --DynamicData.item.addScans(scanLists);
368 DynamicData.item.makeScanLists();
369 --DynamicData.item.doQuickScan();
370 if ( not DynamicData.item.itemScanInProgress ) then
371 DynamicData.item.doScans(nil);
372 --UltimateUI_ScheduleByName("DynamicData_Item_doScans", 0.1, DynamicData.item.doScans);
373 end
374 end
375 end;
376  
377 --
378 -- addScans(scanLists)
379 --
380 -- Adds scan lists to the global scanlist thingy.
381 --
382 addScans = function (scanLists)
383 for k, v in scanLists do
384 for bag, slot in v do
385 if ( not DynamicData.item.scanList ) then
386 DynamicData.item.scanList = {};
387 end
388 if ( not DynamicData.item.scanList[bag] ) then
389 DynamicData.item.scanList[bag] = {};
390 end
391 if ( not DynamicData.item.scanList[bag][slot] ) then
392 DynamicData.item.scanList[bag][slot] = 0;
393 end
394 DynamicData.item.scanList[bag][slot] = 1;
395 end
396 --table.insert(DynamicData.item.scanList, v);
397 end
398 end;
399  
400  
401  
402 --
403 -- doScans (scanLists, currentIndex)
404 --
405 -- scans the currently indicated list and schedules next scan list.
406 -- when completed, generates update notification.
407 --
408 doScans = function (scanLists, currentIndex, bag)
409 scanLists = nil;
410 --[[
411 if ( not scanLists ) then
412 scanLists = DynamicData.item.scanList;
413 end
414 ]]--
415 local scheduleName = "DynamicData_Item_doScans";
416 if ( bag ) then
417 --scheduleName = scheduleName.."_"..bag;
418 end
419 DynamicData.item.itemScanInProgress = true;
420 if ( not currentIndex ) then
421 -- if first time, then we schedule a new scan - this is to prevent the stuttering effect when receiving loads of updates in short succession.
422 --[[
423 if ( scanLists == DynamicData.item.scanList ) then
424 scanLists = nil;
425 end
426 ]]--
427 UltimateUI_ScheduleByName(scheduleName, 0.1, DynamicData.item.doScans, scanLists, 1, bag);
428 return;
429 else
430 -- prevents old scans from continuing.
431 UltimateUI_ScheduleByName(scheduleName, 0.1, DynamicData.item.doScans);
432 end
433 local scanType = DYNAMICDATA_ITEM_SCAN_TYPE_TOOLTIP;
434 if ( DynamicData.item.scanItems(scanType) ) then
435 if ( scanLists == DynamicData.item.scanList ) then
436 scanLists = nil;
437 end
438 UltimateUI_ScheduleByName(scheduleName, 0.1, DynamicData.item.doScans, scanLists, currentIndex, bag);
439 return;
440 else
441 if ( scanLists == DynamicData.item.scanList ) then
442 --DynamicData.item.scanList = {};
443 end
444 DynamicData.item.itemScanInProgress = false;
445 DynamicData.item.notifyUpdateHandlers(bag, scanType);
446 --DynamicData.item.notifyItemCooldownUpdateHandlers();
447 end
448 end;
449  
450  
451 --
452 -- doUpdateBagItemsCooldown (bag)
453 --
454 -- Updates the cooldown a bag of the inventory of the player.
455 --
456 doUpdateBagItemsCooldown = function (bag)
457 if ( ( DynamicData.item.player ) and ( DynamicData.item.player.itemsByBag ) and ( DynamicData.item.player.itemsByBag[bag] ) ) then
458 if ( bag > -1 ) then
459 local element = nil;
460 for slot = 1,GetContainerNumSlots(bag) do
461 if ( DynamicData.item.player.itemsByBag[bag][slot] ) then
462 local ic_start, ic_duration, ic_enable = GetContainerItemCooldown(bag, slot);
463 local itemCooldown = DynamicData.item.getOldCooldown(bag, slot);
464 itemCooldown[1] = ic_start;
465 itemCooldown[2] = ic_duration;
466 itemCooldown[3] = ic_enable;
467 itemCooldown.start = ic_start;
468 itemCooldown.duration = ic_duration;
469 itemCooldown.enable = ic_enable;
470 DynamicData.item.player.itemsByBag[bag][slot].cooldown = itemCooldown;
471 end
472 end
473 else
474 for k, v in DynamicData.item.inventorySlotNames do
475 slot = v.id;
476 if ( DynamicData.item.player.itemsByBag[bag][slot] ) then
477 local ic_start, ic_duration, ic_enable = GetInventoryItemCooldown("player", slot);
478 local itemCooldown = DynamicData.item.getOldCooldown(bag, slot);
479 itemCooldown[1] = ic_start;
480 itemCooldown[2] = ic_duration;
481 itemCooldown[3] = ic_enable;
482 itemCooldown.start = ic_start;
483 itemCooldown.duration = ic_duration;
484 itemCooldown.enable = ic_enable;
485 DynamicData.item.player.itemsByBag[bag][slot].cooldown = itemCooldown;
486 end
487 end
488 end
489 end
490 end;
491  
492 -- private functions
493  
494 --
495 -- notifyUpdateHandlers (bag)
496 --
497 -- Args:
498 -- bag - if not nil, the bag that has been updated
499 -- scanType - the type of scan that has completed
500 --
501 -- Notifies all update handlers that an update has occurred.
502 --
503 notifyUpdateHandlers = function (bag, scanType)
504 DynamicData.util.notifyWhateverHandlers(DynamicData.item.OnInventoryUpdateHandlers, bag, scanType);
505 end;
506  
507 -- LEGACY FUNCTION
508 --
509 -- notifyItemCooldownUpdateHandlers ()
510 --
511 -- Notifies all item cooldown update handlers that an item cooldown has occurred.
512 --
513 notifyItemCooldownUpdateHandlers = function ()
514 DynamicData.util.notifyWhateverHandlers(DynamicData.item.OnInventoryCooldownUpdateHandlers);
515 end;
516  
517 --
518 -- OnLoad ()
519 --
520 -- Sets up the DynamicData.item for operation.
521 -- In this case, it retrieves the IDs for the inventory slots.
522 --
523 OnLoad = function ()
524 for key, value in DynamicData.item.inventorySlotNames do
525 DynamicData.item.inventorySlotNames[key].id = GetInventorySlotInfo(value.name);
526 end
527 DynamicData.item.doUpdateItems();
528 UltimateUI_AfterInit(DynamicData.item.doUpdateItems);
529 UltimateUI_AfterInit(UltimateUI_Schedule, 30, DynamicData.item.doUpdateItems);
530 UltimateUI_AfterInit(UltimateUI_Schedule, 60, DynamicData.item.doUpdateItems);
531 UltimateUI_AfterInit(UltimateUI_Schedule, 90, DynamicData.item.doUpdateItems);
532 end;
533  
534 -- variables
535  
536 -- Taken from ItemBuff - thanks, Telo!
537 -- Used for mapping inventory (equipment) ids and slot names
538 inventorySlotNames = {
539 { name = "HeadSlot" },
540 { name = "NeckSlot" },
541 { name = "ShoulderSlot" },
542 { name = "BackSlot" },
543 { name = "ChestSlot" },
544 { name = "ShirtSlot" },
545 { name = "TabardSlot" },
546 { name = "WristSlot" },
547 { name = "HandsSlot" },
548 { name = "WaistSlot" },
549 { name = "LegsSlot" },
550 { name = "FeetSlot" },
551 { name = "Finger0Slot" },
552 { name = "Finger1Slot" },
553 { name = "Trinket0Slot" },
554 { name = "Trinket1Slot" },
555 { name = "MainHandSlot" },
556 { name = "SecondaryHandSlot" },
557 { name = "RangedSlot" },
558 };
559  
560 -- Contains lists of items that should be scanned.
561 scanList = {};
562  
563 -- Contains lists of when item slots were scanned.
564 scanListScanned = {};
565  
566 -- Whether a scan is in progress or not.
567 itemScanInProgress = false;
568  
569 -- Contains item data about the player's items.
570 player = {};
571  
572 -- Contains the function pointers to functions that want to be called whenever the inventory updates.
573 -- Will be called AFTER the DynamicData has parsed the inventory.
574 OnInventoryUpdateHandlers = {};
575  
576 -- Contains the function pointers to functions that want to be called whenever the inventory cooldown updates.
577 -- Will be called AFTER the DynamicData has parsed the inventory.
578 OnInventoryCooldownUpdateHandlers = {};
579  
580 defaultItem = {
581 name = "",
582 strings = {
583 [1] = {},
584 [2] = {},
585 [3] = {},
586 [4] = {},
587 [5] = {},
588 [6] = {},
589 [7] = {},
590 [8] = {},
591 [9] = {},
592 [10] = {},
593 [11] = {},
594 [12] = {},
595 [13] = {},
596 [14] = {},
597 [15] = {}
598 },
599 count = 0,
600 slotCount = 0,
601 texture = "",
602 cooldown = {
603 [1] = 0,
604 [2] = 0,
605 [3] = 0,
606 start = 0,
607 duration = 0,
608 enable = 0
609 },
610 itemType = "",
611 locked = 0,
612 durability = nil,
613 maxDurability = nil,
614 quality = 0,
615 readable = 0,
616 broken = 0,
617 slotTexture = ""
618 };
619  
620 --
621 -- createBaseItem ()
622 --
623 -- creates a basic item with all attributes set to defaults.
624 --
625 createBaseItem = function (baseItem)
626 local newItem = {};
627 for k, v in DynamicData.item.defaultItem do
628 newItem[k] = v;
629 end
630 if ( baseItem ) then
631 for k, v in baseItem do
632 newItem[k] = v;
633 end
634 end
635 return newItem;
636 end;
637  
638  
639 --
640 -- makeScanList (numberOfScansPerList, bag)
641 --
642 -- Makes a list of scans.
643 --
644 makeScanLists = function (bag)
645 if ( not DynamicData.item.scanList ) then
646 DynamicData.item.scanList = {};
647 end
648 if ( not bag ) then
649 for bag = 0, 4, 1 do
650 for slot = 1, GetContainerNumSlots(bag), 1 do
651 if ( not DynamicData.item.scanList[bag] ) then
652 DynamicData.item.scanList[bag] = {};
653 end
654 DynamicData.item.scanList[bag][slot] = 1;
655 end
656 end
657 bag = -1;
658 for slot = 1, 19, 1 do
659 if ( not DynamicData.item.scanList[bag] ) then
660 DynamicData.item.scanList[bag] = {};
661 end
662 DynamicData.item.scanList[bag][slot] = 1;
663 end
664 elseif ( bag <= -1 ) then
665 bag = -1;
666 if ( not DynamicData.item.scanList[bag] ) then
667 DynamicData.item.scanList[bag] = {};
668 end
669 for slot = 1, 19, 1 do
670 DynamicData.item.scanList[bag][slot] = 1;
671 end
672 else
673 if ( not DynamicData.item.scanList[bag] ) then
674 DynamicData.item.scanList[bag] = {};
675 end
676 for slot = 1, GetContainerNumSlots(bag), 1 do
677 DynamicData.item.scanList[bag][slot] = 1;
678 end
679 end
680 end;
681  
682 --
683 -- generateScanLists (numberOfScansPerList, bag)
684 --
685 -- Generates a list of scans.
686 --
687 generateScanLists = function (numberOfScansPerList, bag)
688 if ( not numberOfScansPerList ) then
689 numberOfScansPerList = DYNAMICDATA_DEFAULT_NUMBER_OF_TOOLTIP_SCANS_PER_UPDATE;
690 end
691 local lists = {};
692 local numberOfCurrentScans = 0;
693 local currentList = {};
694 local slot;
695 if ( not bag ) then
696 for bag = 0, 4, 1 do
697 for slot = 1, GetContainerNumSlots(bag), 1 do
698 if ( not currentList[bag] ) then
699 currentList[bag] = {};
700 end
701 table.insert(currentList[bag], slot);
702 numberOfCurrentScans = numberOfCurrentScans + 1;
703 if ( numberOfCurrentScans >= numberOfScansPerList) then
704 table.insert(lists, currentList);
705 currentList = {};
706 numberOfCurrentScans = 0;
707 end
708 end
709 end
710 bag = -1;
711 for slot = 1, 19, 1 do
712 if ( not currentList[bag] ) then
713 currentList[bag] = {};
714 end
715 table.insert(currentList[bag], slot);
716 numberOfCurrentScans = numberOfCurrentScans + 1;
717 if ( numberOfCurrentScans >= numberOfScansPerList) then
718 table.insert(lists, currentList);
719 currentList = {};
720 numberOfCurrentScans = 0;
721 end
722 end
723 elseif ( bag <= -1 ) then
724 bag = -1;
725 for slot = 1, 19, 1 do
726 if ( not currentList[bag] ) then
727 currentList[bag] = {};
728 end
729 table.insert(currentList[bag], slot);
730 numberOfCurrentScans = numberOfCurrentScans + 1;
731 if ( numberOfCurrentScans >= numberOfScansPerList) then
732 table.insert(lists, currentList);
733 currentList = {};
734 numberOfCurrentScans = 0;
735 end
736 end
737 else
738 for slot = 1, GetContainerNumSlots(bag), 1 do
739 if ( not currentList[bag] ) then
740 currentList[bag] = {};
741 end
742 table.insert(currentList[bag], slot);
743 numberOfCurrentScans = numberOfCurrentScans + 1;
744 if ( numberOfCurrentScans >= numberOfScansPerList) then
745 table.insert(lists, currentList);
746 currentList = {};
747 numberOfCurrentScans = 0;
748 end
749 end
750 end
751 if ( numberOfCurrentScans > 0) then
752 table.insert(lists, currentList);
753 end
754 return lists;
755 end;
756  
757 --
758 -- doQuickScan (bag)
759 --
760 -- does a quick scan of the bag (or of the whole inventory if bag is not specified).
761 --
762 doQuickScan = function(bag)
763 if ( bag ) then
764 DynamicData.item.scanItemsInBag(bag, DYNAMICDATA_ITEM_SCAN_TYPE_QUICK);
765 else
766 for i = 0, 4, 1 do
767 DynamicData.item.scanItemsInBag(i, DYNAMICDATA_ITEM_SCAN_TYPE_QUICK);
768 end
769 DynamicData.item.scanItemsInBag(-1, DYNAMICDATA_ITEM_SCAN_TYPE_QUICK);
770 end
771 DynamicData.item.notifyUpdateHandlers(bag, DYNAMICDATA_ITEM_SCAN_TYPE_QUICK);
772 DynamicData.item.notifyItemCooldownUpdateHandlers();
773 end;
774  
775 --
776 -- scanItemsInBag (bag, scanType)
777 --
778 -- scans all items in bag and puts the info into the database
779 -- can be retailored to only scan the tooltip, everything but the tooltip and everything.
780 --
781 scanItemsInBag = function(bag, scanType)
782 local bag, slot, v;
783 if ( not bag ) then
784 return;
785 end
786 if ( bag <= -1 ) then
787 for slot = 1, 19, 1 do
788 DynamicData.item.scanItem(-1, slot, scanType);
789 end
790 else
791 for slot = 1, GetContainerNumSlots(bag), 1 do
792 DynamicData.item.scanItem(bag, slot, scanType);
793 end
794 end
795 end;
796  
797 --
798 -- scanItems (list, scanType)
799 --
800 -- scans a list of item slots item and puts the info into the database
801 -- can be retailored to only scan the tooltip, everything but the tooltip and everything.
802 -- list format : list[bag] = { slot1, slot2, slot3 ... };
803 --
804 scanItems = function(scanType)
805 local curTime = GetTime();
806 local numberScanned = 0;
807 local scanned = false;
808 for bag, bagValue in DynamicData.item.scanList do
809 for slot, value in bagValue do
810 if ( value == 1 ) then
811 DynamicData.item.scanItem(bag, slot, scanType);
812 DynamicData.item.scanList[bag][slot] = 0;
813 if ( not DynamicData.item.scanListScanned ) then
814 DynamicData.item.scanListScanned = {};
815 end
816 if ( not DynamicData.item.scanListScanned[bag] ) then
817 DynamicData.item.scanListScanned[bag] = {};
818 end
819 DynamicData.item.scanListScanned[bag][slot] = curTime;
820 numberScanned = numberScanned + 1;
821 scanned = true;
822 if ( numberScanned >= DYNAMICDATA_DEFAULT_NUMBER_OF_TOOLTIP_SCANS_PER_UPDATE ) then
823 return scanned;
824 end
825 end
826 end
827 end
828 return scanned;
829 --[[
830 for bag, v in list do
831 for key, slot in v do
832 DynamicData.item.scanItem(bag, slot, scanType);
833 end
834 end
835 ]]--
836 end;
837  
838 --
839 -- scanItem (bag, slot)
840 --
841 -- scans an item and puts the info into the item database
842 --
843 scanItem = function(bag, slot, scanType)
844 if ( not scanType ) then
845 scanType = DYNAMICDATA_ITEM_SCAN_TYPE_EVERYTHING;
846 end
847 local strings = nil;
848 local itemName = nil;
849 local element = nil;
850 if ( not DynamicData.item.scanListScanned ) then
851 DynamicData.item.scanListScanned = {};
852 end
853 if ( not DynamicData.item.scanListScanned[bag] ) then
854 DynamicData.item.scanListScanned[bag] = {};
855 end
856 if ( not DynamicData.item.scanListScanned[bag][slot] ) then
857 DynamicData.item.scanListScanned[bag][slot] = GetTime();
858 end
859 if ( bag > -1 ) then
860 if ( not DynamicData.item.player ) then
861 DynamicData.item.player = {};
862 end
863 if ( not DynamicData.item.player.itemsByBag ) then
864 DynamicData.item.player.itemsByBag = {};
865 end
866 if ( not DynamicData.item.player.itemsByBag[bag] ) then
867 DynamicData.item.player.itemsByBag[bag] = {};
868 end
869 if ( GetContainerNumSlots(bag) < slot ) then
870 return nil;
871 end
872 if ( not DynamicData.item.player.itemsByBag[bag][slot] ) then
873 DynamicData.item.player.itemsByBag[bag][slot] = DynamicData.item.createBaseItem();
874 end
875 element = DynamicData.item.player.itemsByBag[bag][slot];
876 if ( not element.previousElement ) then
877 element.previousElement = {};
878 end
879 if ( ( scanType and DYNAMICDATA_ITEM_SCAN_TYPE_COOLDOWN ) > 0 ) then
880 local ic_start, ic_duration, ic_enable = GetContainerItemCooldown(bag, slot);
881 local itemCooldown = DynamicData.item.getOldCooldown(bag, slot);
882 itemCooldown[1] = ic_start;
883 itemCooldown[2] = ic_duration;
884 itemCooldown[3] = ic_enable;
885 itemCooldown.start = ic_start;
886 itemCooldown.duration = ic_duration;
887 itemCooldown.enable = ic_enable;
888 element.cooldown = itemCooldown;
889 end
890 if ( ( scanType and DYNAMICDATA_ITEM_SCAN_TYPE_ITEMINFO ) > 0 ) then
891 local textureName, itemCount, itemLocked, itemQuality, itemReadable = GetContainerItemInfo(bag, slot);
892 local name = DynamicData.util.getItemNameFromLink(GetContainerItemLink(bag, slot));
893 if ( name ) then
894 element.name = name;
895 end
896 element.count = itemCount;
897 element.texture = textureName;
898 element.locked = itemLocked;
899 element.quality = itemQuality;
900 element.readable = itemReadable;
901 end
902 if ( ( scanType and DYNAMICDATA_ITEM_SCAN_TYPE_TOOLTIP ) > 0 ) then
903 if ( scanType == DYNAMICDATA_ITEM_SCAN_TYPE_TOOLTIP ) or ( not element.previousElement ) or ( element.previousElement.name ~= element.name ) or ( element.previousElement.cooldown.start ~= 0 ) or ( element.cooldown.start ~= 0 ) then
904 strings = DynamicData.util.getItemTooltipInfo(bag, slot);
905 if ( strings[1] ) and ( strings[1].left ) then
906 itemName = strings[1].left;
907 else
908 itemName = "";
909 end
910 element.name = itemName;
911 element.strings = strings;
912 element.itemType = DynamicData.util.getItemStringType(strings);
913  
914 local itemCurrentDurability, itemMaxDurability = DynamicData.util.getCurrentAndMaxDurability(strings);
915 element.durability = itemCurrentDurability;
916 element.maxDurability = itemMaxDurability;
917 if ( not element.previousElement ) then
918 element.previousElement = {};
919 end
920 for k, v in element do
921 if ( type(v) == "table" ) then
922 if ( not element.previousElement[k] ) then
923 element.previousElement[k] = {};
924 end
925 for key, value in v do
926 if ( type(value) == "table" ) then
927 if ( not element.previousElement[k][key] ) then
928 element.previousElement[k][key] = {};
929 end
930 for keyKey, valueValue in value do
931 element.previousElement[k][key][keyKey] = valueValue;
932 end
933 else
934 element.previousElement[k][key] = value;
935 end
936 end
937 else
938 element.previousElement[k] = v;
939 end
940 end
941 end
942 end
943 DynamicData.item.player.itemsByBag[bag][slot] = element;
944 else
945 bag = -1;
946 if ( not DynamicData.item.player ) then
947 DynamicData.item.player = {};
948 end
949 if ( not DynamicData.item.player.itemsByBag ) then
950 DynamicData.item.player.itemsByBag = {};
951 end
952 if ( not DynamicData.item.player.itemsByBag[bag] ) then
953 DynamicData.item.player.itemsByBag[bag] = {};
954 end
955 if ( not DynamicData.item.player.itemsByBag[bag][slot] ) then
956 DynamicData.item.player.itemsByBag[bag][slot] = DynamicData.item.createBaseItem();
957 end
958 element = DynamicData.item.player.itemsByBag[bag][slot];
959  
960 if ( ( scanType and DYNAMICDATA_ITEM_SCAN_TYPE_COOLDOWN ) > 0 ) then
961 local ic_start, ic_duration, ic_enable = GetInventoryItemCooldown("player", slot);
962 local itemCooldown = DynamicData.item.getOldCooldown(bag, slot);
963 itemCooldown[1] = ic_start;
964 itemCooldown[2] = ic_duration;
965 itemCooldown[3] = ic_enable;
966 itemCooldown.start = ic_start;
967 itemCooldown.duration = ic_duration;
968 itemCooldown.enable = ic_enable;
969 element.cooldown = itemCooldown;
970 end
971 if ( ( scanType and DYNAMICDATA_ITEM_SCAN_TYPE_ITEMINFO ) > 0 ) then
972 local itemCount = GetInventoryItemCount("player", slot);
973 local textureName = GetInventoryItemTexture("player", slot);
974 element.count = itemCount;
975 element.slotTexture = slotTextureName;
976 element.texture = textureName;
977 element.locked = IsInventoryItemLocked(slot);
978 element.broken = GetInventoryItemBroken("player", slot);
979 --element.quality = GetInventoryItemQuality("player", slot);
980 end
981 if ( ( scanType and DYNAMICDATA_ITEM_SCAN_TYPE_TOOLTIP ) > 0 ) then
982 strings = DynamicData.util.getItemTooltipInfo(-1, slot);
983 element.strings = strings;
984 if ( strings[1] ) and ( strings[1].left ) then
985 itemName = strings[1].left;
986 else
987 itemName = "";
988 end
989 element.name = itemName;
990 element.itemType = DynamicData.util.getItemStringType(strings);
991  
992 local itemCurrentDurability, itemMaxDurability = DynamicData.util.getCurrentAndMaxDurability(strings);
993 element.durability = itemCurrentDurability;
994 element.maxDurability = itemMaxDurability;
995 end
996 DynamicData.item.player.itemsByBag[bag][slot] = element;
997 end
998 return element;
999 end;
1000  
1001 getOldCooldown = function(bag, slot)
1002 if ( DynamicData.item.player.itemsByBag )
1003 and ( DynamicData.item.player.itemsByBag[bag] )
1004 and ( DynamicData.item.player.itemsByBag[bag][slot] )
1005 and ( DynamicData.item.player.itemsByBag[bag][slot].cooldown ) then
1006 itemCooldown = DynamicData.item.player.itemsByBag[bag][slot].cooldown;
1007 else
1008 itemCooldown = { };
1009 end
1010 return itemCooldown;
1011 end;
1012  
1013 --
1014 -- getInventorySlotScanned(bag, slot)
1015 --
1016 -- retrieves when the slot was last scanned or nil if never
1017 --
1018 getInventorySlotScanned = function (bag, slot)
1019 if ( not DynamicData.item.scanListScanned ) then
1020 DynamicData.item.scanListScanned = {};
1021 end
1022 if ( not DynamicData.item.scanListScanned[bag] ) then
1023 DynamicData.item.scanListScanned[bag] = {};
1024 end
1025 return DynamicData.item.scanListScanned[bag][slot];
1026 end;
1027  
1028 --
1029 -- scanInventorySlotIfTime(bag, slot)
1030 --
1031 -- scans the slot if necessary.
1032 --
1033 scanInventorySlotIfTime = function(bag, slot)
1034 local curTime = GetTime();
1035 local lastScanned = DynamicData.item.getInventorySlotScanned(bag, slot);
1036 if ( not lastScanned ) or ( ( lastScanned + 0.2 ) < GetTime() ) then
1037 DynamicData.item.scanItem(bag, slot, DYNAMICDATA_ITEM_SCAN_TYPE_QUICK);
1038 end
1039 end;
1040  
1041 };
1042