forked from AssemblerManiac/InventoryInsight
-
Notifications
You must be signed in to change notification settings - Fork 0
/
InventoryInsight_DataCollection.lua
826 lines (725 loc) · 29.1 KB
/
InventoryInsight_DataCollection.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
local task = IIfA.task or LibAsync:Create("IIfA_DataCollection")
IIfA.task = task
local function p(...)
if nil == IIfA or nil == IIfA.DebugOut then return end
IIfA:DebugOut(...)
end
local function IIfA_GetItemID(itemLink)
local ret = nil
if itemLink then
ret = tostring(GetItemLinkItemId(itemLink))
end
return ret
end
local function grabBagContent(bagId)
if bagId >= BAG_HOUSE_BANK_ONE and bagId <= BAG_HOUSE_BANK_TEN and not IsOwnerOfCurrentHouse() then return end
local bagItems = GetBagSize(bagId)
p("grabBagContent(<<1>>", bagId)
for slotIndex = 0, bagItems, 1 do
-- (bagId, slotIndex, qty, itemLink, itemName, locationID)
local dbItem, itemKey = IIfA:EvalBagItem(bagId, slotIndex)
end
end
function IIfA:DeleteCharacterData(name)
if (name) then
--delete selected character
for characterName, charId in pairs(IIfA.CharNameToId) do
if characterName == name then
--d("Deleting char " .. name .. ", Id=" .. charId)
IIfA.CharNameToId[name] = nil
IIfA.CharIdToName[charId] = nil
IIfA:ClearUnowned()
end
end
end
end
function IIfA:DeleteGuildData(name)
if (name) then
--delete selected guild
for guildName, guild in pairs(IIfA.guildBanks) do
if guildName == name then
p("Deleting Guild Bank data for <<1>>", name)
IIfA.guildBanks[name] = { bCollectData = false, lastCollected = IIfA.EMPTY_STRING, items = 0 }
IIfA:ClearLocationData(name)
end
end
end
end
function IIfA:CollectGuildBank(curGuild)
-- add roomba support
if Roomba and Roomba.WorkInProgress and Roomba.WorkInProgress() then
CALLBACK_MANAGER:FireCallbacks("Roomba-EndStacking", function() IIfA:CollectGuildBank() end)
return
end
local curGB = GetSelectedGuildBankId()
if not IIfA.data.bCollectGuildBankData or curGB == nil then
return
end
if not IIfA.guildBanks then IIfA.guildBanks = {} end
curGuild = GetGuildName(curGB)
p("Collecting Guild Bank Data for " .. curGuild)
if IIfA.guildBanks[curGuild] ~= nil then
if not IIfA.guildBanks[curGuild].bCollectData then
return
end
else
-- init a new guild bank
IIfA.guildBanks[curGuild] = { bCollectData = false, lastCollected = IIfA.EMPTY_STRING, items = 0 }
end
SelectGuildBank(curGB)
IIfA.BagSlotInfo[curGuild] = nil
-- call with libAsync to avoid lag
task:Call(function()
if not IIfA then return end
IIfA.BagSlotInfo = IIfA.BagSlotInfo or {}
p("Collect guild bank - <<1>>", curGuild)
local guildData = IIfA.guildBanks[curGuild]
local itemCount, slotIndex
--[[
11-8-18 AM - ?old debugging code? removed to speed up the data collection process
itemCount = 0
slotIndex = ZO_GetNextBagSlotIndex(BAG_GUILDBANK, nil)
while slotIndex do
itemCount = itemCount + 1
slotIndex = ZO_GetNextBagSlotIndex(BAG_GUILDBANK, slotIndex)
end
p("GuildBank Item Count = " .. itemCount)
]]--
guildData.lastCollected = GetDate() .. "@" .. GetFormattedTime();
IIfA:ClearLocationData(curGuild)
itemCount = 0
slotIndex = ZO_GetNextBagSlotIndex(BAG_GUILDBANK, nil)
while slotIndex do
itemCount = itemCount + 1
-- (bagId, slotId, qty, itemLink, itemName, locationID)
local dbItem, itemKey = IIfA:EvalBagItem(BAG_GUILDBANK, slotIndex)
-- p("Collect guild bank from <<1>> - slot/key <<2>> / <<3>>", curGuild, slotIndex, itemKey)
if not IIfA.BagSlotInfo or not curGuild then return end -- be paranoid because this might happen in the middle of unloading
IIfA.BagSlotInfo[curGuild] = IIfA.BagSlotInfo[curGuild] or {}
if not IIfA.BagSlotInfo[curGuild] then return end -- be paranoid because this might happen in the middle of unloading
IIfA.BagSlotInfo[curGuild][slotIndex] = itemKey
slotIndex = ZO_GetNextBagSlotIndex(BAG_GUILDBANK, slotIndex)
end
guildData.items = itemCount
p("IIfA - Guild Bank Collected - " .. curGuild .. ", itemCount=" .. itemCount)
end)
end
function IIfA:ScanCurrentCharacter()
IIfA:ClearLocationData(IIfA.currentCharacterId)
if not IIfA:IsCharacterEquipIgnored() then
-- call with libAsync to avoid lags
task:Call(function()
grabBagContent(BAG_WORN)
end)
end
if not IIfA:IsCharacterInventoryIgnored() then
-- call with libAsync to avoid lags
task:Call(function()
grabBagContent(BAG_BACKPACK)
end)
end
task:Call(function()
IIfA:MakeBSI()
end)
end
--[[
Developer note: In TryScanHouseBank, the call to IIfA:ClearLocationData will fail because collectibleId is zero
bagId on the other hand DOES work, possibly because it's in use by the for loop
]]--
local function tryScanHouseBank()
if not IsOwnerOfCurrentHouse() then return end
local bagId, collectibleId
for bagId = BAG_HOUSE_BANK_ONE, BAG_HOUSE_BANK_TEN do
collectibleId = GetCollectibleForHouseBankBag(bagId)
if IsCollectibleUnlocked(collectibleId) then
p(zo_strformat("tryScanHouseBank(<<1>>)", collectibleId))
-- call with libAsync to avoid lag
-- task:Call(function()
-- local collectibleId = GetCollectibleForHouseBankBag(bagId) -- required code - MUST stay here if using task, or collectibleId is 0
IIfA:ClearLocationData(collectibleId)
-- end):Then(function()
grabBagContent(bagId)
-- end)
end
end
end
function IIfA:ScanBank()
-- call with libAsync to avoid lag
task:Call(function()
IIfA:ClearLocationData(GetString(IIFA_BAG_BANK))
-- end):Then(function()
grabBagContent(BAG_BANK)
-- end):Then(function()
grabBagContent(BAG_SUBSCRIBER_BANK)
end):Then(function()
IIfA:ClearLocationData(GetString(IIFA_BAG_CRAFTBAG))
local slotIndex = GetNextVirtualBagSlotId(slotIndex)
while slotIndex ~= nil do
-- (bagId, slotIndex, qty, itemLink, itemName, locationID)
IIfA:EvalBagItem(BAG_VIRTUAL, slotIndex)
slotIndex = GetNextVirtualBagSlotId(slotIndex)
end
end):Then(function()
tryScanHouseBank()
end)
end
-- only grabs the content of bagpack and worn on the first login - hence we set the function to insta-return below.
function IIfA:OnFirstInventoryOpen()
if IIfA.BagsScanned then return end
IIfA.BagsScanned = true
-- do not async this, each scan function does that itself
IIfA:ScanBank()
IIfA:ScanCurrentCharacter()
end
function IIfA:CheckForAgedGuildBankData(days)
local results = false
local days = days or 5
if IIfA.data.bCollectGuildBankData then
IIfA:UpdateGuildBankData()
for guildName, guildData in pairs(IIfA.guildBanks) do
local today = GetDate()
local lastCollected = guildData.lastCollected:match('(........)')
if guildData.bCollectData and lastCollected and lastCollected ~= IIfA.EMPTY_STRING then
if (today - lastCollected) >= days then
d("[IIfA]:Warning - " .. guildName .. " Guild Bank data not collected in " .. days .. " or more days!")
results = true
end
else
d("[IIfA]:Warning - " .. guildName .. " Guild Bank data has not been collected!")
results = true
end
end
return results
end
return true
end
function IIfA:UpdateGuildBankData()
if IIfA.data.bCollectGuildBankData then
for index = 1, GetNumGuilds() do
local guildName = GetGuildName(index)
local guildBank = IIfA.guildBanks[guildName]
if not guildBank then
IIfA.guildBanks[guildName] = { bCollectData = false, lastCollected = IIfA.EMPTY_STRING, items = 0 }
end
end
end
local emptyGuild = IIfA.guildBanks[IIfA.EMPTY_STRING]
if emptyGuild then
IIfA.guildBanks[IIfA.EMPTY_STRING] = nil
end
end
function IIfA:GuildBankReady()
-- call with libAsync to avoid lag
task:Call(function()
p("GuildBankReady...")
IIfA.isGuildBankReady = false
IIfA:UpdateGuildBankData()
IIfA:CollectGuildBank()
end)
end
function IIfA:GuildBankDelayReady()
p("GuildBankDelayReady...")
if not IIfA.isGuildBankReady then
IIfA.isGuildBankReady = true
IIfA:GuildBankReady()
end
end
function IIfA:GuildBankAddRemove(eventCode, slotId, addedByLocalPlayer, itemSoundCategory, isLastUpdateForMessage)
p("Guild Bank Add or Remove...")
if not IIfA.data.bCollectGuildBankData then return end
-- call with libAsync to avoid lag
task:Call(function()
IIfA:UpdateGuildBankData()
--IIfA:CollectGuildBank()
local dbItem, itemKey
local guildName = GetGuildName(GetSelectedGuildBankId())
if eventCode == EVENT_GUILD_BANK_ITEM_ADDED then
p("GB Add - Slot <<1>>", slotId)
-- (bagId, slotId, qty, itemLink, itemName, locationID)
dbItem, itemKey = IIfA:EvalBagItem(BAG_GUILDBANK, slotId)
-- IIfA:ValidateItemCounts(BAG_GUILDBANK, slotId, dbItem, itemKey)
if not IIfA.BagSlotInfo[guildName] then
IIfA.BagSlotInfo[guildName] = {}
end
IIfA.BagSlotInfo[guildName][slotId] = itemKey
else
if IIfA.BagSlotInfo[guildName] and IIfA.BagSlotInfo[guildName][slotId] then
local itemLink = IIfA.BagSlotInfo[guildName][slotId]
if #itemLink < 10 then
itemLink = IIfA.database[itemLink].itemLink
end
p("GB Remove - Slot <<1>>, Link <<2>>, ", slotId, itemLink)
-- (bagId, slotId, qty, itemLink, itemName, locationID)
dbItem, itemKey = IIfA:EvalBagItem(BAG_GUILDBANK, slotId, nil, itemLink)
-- IIfA:ValidateItemCounts(BAG_GUILDBANK, slotId, dbItem, itemKey)
IIfA.BagSlotInfo[guildName][slotId] = nil
else
p("GB Remove - Slot <<1>> - no BSI found", slotId)
end
end
end)
end
function IIfA:RescanHouse(houseCollectibleId)
houseCollectibleId = houseCollectibleId or GetCollectibleIdForHouse(GetCurrentZoneHouseId())
if not houseCollectibleId or not IIfA.trackedBags[houseCollectibleId] then return end
IIfA.data.collectHouseData[houseCollectibleId] = IIfA.data.collectHouseData[houseCollectibleId] or IIfA:GetHouseTracking()
if not IIfA.data.collectHouseData[houseCollectibleId] then
if IIfA:GetHouseTracking() and IIfA:GetIgnoredHouseIds()[houseCollectibleId] then
IIfA.trackedBags[houseCollectibleId] = false
return
end
IIfA.trackedBags[houseCollectibleId] = true
end
-- TODO: Debug this
--- stuff them all into an array
local function getAllPlacedFurniture()
local ret = {}
local counter = 1
local furnitureId = nil
while (true) do
furnitureId = GetNextPlacedHousingFurnitureId(furnitureId)
if (not furnitureId or counter > 10000) then return ret end
local itemLink = GetPlacedFurnitureLink(furnitureId, LINK_STYLE_BRACKETS)
-- if not ret[itemLink] then
-- ret[itemLink] = 1
-- else
ret[itemLink] = (ret[itemLink] or 0) + 1
-- end
counter = counter + 1
end
return ret
end
IIfA.getAllPlacedFurniture = getAllPlacedFurniture
-- call with libAsync to avoid lag
task:Call(function()
-- clear and re-create, faster than conditionally updating
IIfA:ClearLocationData(houseCollectibleId)
end):Then(function()
-- TODO - can this go again? Having it in here at least prevented the crash
local placedFurniture = getAllPlacedFurniture()
for itemLink, itemCount in pairs(placedFurniture) do
-- (bagId, slotId, fromXfer, itemCount, itemLink, itemName, locationID)
local itemName = zo_strformat(SI_TOOLTIP_ITEM_NAME, GetItemLinkName(itemLink))
p("furniture item <<1>> x<<2>>", itemLink, itemCount)
-- (bagId, slotId, qty, itemLink, itemName, locationID)
IIfA:EvalBagItem(houseCollectibleId, tonumber(IIfA_GetItemID(itemLink)), itemCount, itemLink, itemName, houseCollectibleId)
end
end)
end
-- try to read item name from bag/slot - if that's empty, we read it from item link
local function getItemName(bagId, slotId, itemLink)
local itemName = zo_strformat(SI_TOOLTIP_ITEM_NAME, GetItemName(bagId, slotId))
if itemName ~= "" then return itemName end
if itemLink == nil then return end
local itemNameByItemLink = zo_strformat(SI_TOOLTIP_ITEM_NAME, GetItemLinkName(itemLink))
return itemNameByItemLink
end
--[[
Data collection notes:
Currently crafting items are coming back from getitemlink with level info in them.
If it's a crafting item, strip the level info and store only the item number as the itemKey
Use function GetItemCraftingInfo, if usedInCraftingType indicates it's NOT a material, check for other item types
When showing items in tooltips, check for both stolen & owned, show both
--]]
-- returns the item's db key, we only save under the item link if we need to save level information etc, else we use the ID
function IIfA:GetItemKey(itemLink)
-- Return an empty string immediately if itemLink is nil or an empty string
if not itemLink or #itemLink == 0 then
return IIfA.EMPTY_STRING
end
if CanItemLinkBeVirtual(itemLink) then
-- Anything that goes in the craft bag - must be a crafting material
return IIfA_GetItemID(itemLink)
else
-- Other oddball items that might have level info in them
local itemType, specializedItemType = GetItemLinkItemType(itemLink)
if (itemType == ITEMTYPE_TOOL and specializedItemType == SPECIALIZED_ITEMTYPE_TOOL) or
(itemType == ITEMTYPE_CONTAINER and specializedItemType == SPECIALIZED_ITEMTYPE_CONTAINER) or -- 4-6-19 AM - runeboxes appear to have level info in them
itemType == ITEMTYPE_LOCKPICK and specializedItemType == SPECIALIZED_ITEMTYPE_LOCKPICK or -- 11-19-24 Sharlikran - added because Lockpicks are no longer Tools
itemType == ITEMTYPE_SOUL_GEM and specializedItemType == SPECIALIZED_ITEMTYPE_SOUL_GEM or -- 11-19-24 Sharlikran - added because soul gems have level info
itemType == ITEMTYPE_RACIAL_STYLE_MOTIF or -- 9-12-16 AM - added because motifs now appear to have level info in them
itemType == ITEMTYPE_TROPHY or -- 11-19-24 Sharlikran - added because trophies can have level info
itemType == ITEMTYPE_RECIPE then
return IIfA_GetItemID(itemLink)
end
end
return itemLink
end
local function getItemCount(bagId, slotId, itemLink)
if bagId > BAG_MAX_VALUE then return 1 end -- it's furniture because of the out of range id, always count of 1
local _, itemCount = GetItemInfo(bagId, slotId)
-- p("getItemCount: bag/slot <<1>> / <<2>>, count=<<3>>", bagId, slotId, itemCount)
if itemCount > 0 then return itemCount end
-- return 0 if no item count was found, possibly an out of date index to a house container that no longer exists
return 0
end
local function getLocation(bagId)
if (bagId == BAG_BACKPACK or bagId == BAG_WORN) then
return IIfA.currentCharacterId
elseif (bagId == BAG_BANK or bagId == BAG_SUBSCRIBER_BANK) then
return GetString(IIFA_BAG_BANK)
elseif (bagId == BAG_VIRTUAL) then
return GetString(IIFA_BAG_CRAFTBAG)
elseif (bagId == BAG_GUILDBANK) then
return GetGuildName(GetSelectedGuildBankId())
elseif 0 < GetCollectibleForHouseBankBag(bagId) then
return GetCollectibleForHouseBankBag(bagId)
end
end
function IIfA:AddOrRemoveFurnitureItem(itemLink, itemCount, houseCollectibleId, fromInitialize)
-- d(zo_strformat("trying to add/remove <<1>> x <<2>> from houseCollectibleId <<3>>", itemLink, itemCount, houseCollectibleId))
local itemName = zo_strformat(SI_TOOLTIP_ITEM_NAME, GetItemLinkName(itemLink))
-- (bagId, slotId, qty, itemLink, itemName, locationID)
IIfA:EvalBagItem(houseCollectibleId, IIfA_GetItemID(itemLink), itemCount, itemLink, itemName, houseCollectibleId)
end
function IIfA:TableCount(tbl)
local slotId, itemCount, cnt
cnt = 0
for slotId, itemCount in pairs(tbl) do
cnt = cnt + 1
end
return cnt
end
--@Baertram:
-- Added for other addons like FCOItemSaver to get the item instance or the unique ID
-->Returns itemInstance or uniqueId as 1st return value
-->Returns a boolean value as 2nd retun value: true if the bagId should build an itemInstance or unique ID / false if not
local function getItemInstanceOrUniqueId(bagId, slotIndex, itemLink)
local itemInstanceOrUniqueId = 0
local isBagToBuildItemInstanceOrUniqueId = false
if FCOIS == nil or FCOIS.getItemInstanceOrUniqueId == nil then return 0, false end
--Call function within addon FCOItemSaver, file FCOIS_OtherAddons.lua -> IIfA section
itemInstanceOrUniqueId, isBagToBuildItemInstanceOrUniqueId = FCOIS.getItemInstanceOrUniqueId(bagId, slotIndex, itemLink)
return itemInstanceOrUniqueId, isBagToBuildItemInstanceOrUniqueId
end
function IIfA:EvalBagItem(bagId, slotId, qty, itemLink, itemName, locationID)
if not IIfA.trackedBags[bagId] then return end
IIfA.database = IIfA.database or {}
local DBv3 = IIfA.database
-- item link is either passed as arg or we need to read it from the system
itemLink = itemLink or GetItemLink(bagId, slotId)
-- return if we don't have any item to track
if itemLink == nil or #itemLink == 0 then return end
itemLink = string.gsub(itemLink, '|H0', '|H1') -- always store/eval with brackets on the link
if #itemLink < 10 then
p("Item link error - <<1>> should be > 10, but it's an itemKey instead", itemLink)
-- deliberate crash
IIfA.database.junk["nothing"] = "something"
end
-- item names is either passed or we get it from bag/slot or item link
if itemName and #itemName == 0 then itemName = nil end
itemName = itemName or getItemName(bagId, slotId, itemLink)
-- item count is either passed or we have to get it from bag/slot ID or item link
local bAddQty = false
if qty ~= nil then bAddQty = true end
local itemCount = qty or getItemCount(bagId, slotId, itemLink)
--@Baertram:
--Item instance/unique id (needed for other addons like FCOItemSaver to (un)mark items via that id)
local itemInstanceOrUniqueId, isBagToBuildItemInstanceOrUniqueId = getItemInstanceOrUniqueId(bagId, slotId, itemLink)
if isBagToBuildItemInstanceOrUniqueId then
-- p("[EvalBagItem]Item instance or unique ID: <<1>>", itemInstanceOrUniqueId)
end
-- p("[EvalBagItem] - trying to save <<1>> x<<2>>", itemLink, itemCount)
local itemQuality = GetItemLinkDisplayQuality(itemLink)
local itemType = GetItemLinkItemType(itemLink)
local itemKey
if bagId == BAG_VIRTUAL then
itemKey = tostring(slotId)
else
itemKey = IIfA:GetItemKey(itemLink) or itemLink
end
if nil == itemKey then return end
local itemFilterType = GetItemFilterTypeInfo(bagId, slotId) or 0
local DBitem = DBv3[itemKey]
local location = locationID or getLocation(bagId) or IIfA.EMPTY_STRING
IIfA:DebugOut("[EvalBagItem] - bAddQty: <<1>>, itemCount: <<2>>, for: <<3>>", tostring(bAddQty), itemCount, itemKey)
if (DBitem) then
if itemCount == 0 then
if DBitem.locations[location] and DBitem.locations[location].bagSlot then
DBitem.locations[location].bagSlot[slotId] = nil
end
if bagId == BAG_GUILDBANK then
IIfA.BagSlotInfo[location][slotId] = nil
else
IIfA.BagSlotInfo[bagId][slotId] = nil
end
else
if DBitem.locations[location] then
if type(DBitem.locations[location].bagSlot) ~= "table" then
local bagSlot = DBitem.locations[location].bagSlot
DBitem.locations[location].bagSlot = {}
DBitem.locations[location].bagSlot[bagSlot] = DBitem.locations[location].itemCount
DBitem.locations[location].itemCount = nil
end
if DBitem.locations[location].bagSlot[slotId] then
if bAddQty then
DBitem.locations[location].bagSlot[slotId] = DBitem.locations[location].bagSlot[slotId] + itemCount
else
DBitem.locations[location].bagSlot[slotId] = itemCount
end
if DBitem.locations[location].bagSlot[slotId] == 0 then
DBitem.locations[location].bagSlot[slotId] = nil
if bagId == BAG_GUILDBANK then
IIfA.BagSlotInfo[location][slotId] = nil
else
IIfA.BagSlotInfo[bagId][slotId] = nil
end
end
else
DBitem.locations[location].bagSlot[slotId] = itemCount
end
else
DBitem.locations[location] = {}
DBitem.locations[location].bagID = bagId
DBitem.locations[location].bagSlot = {}
DBitem.locations[location].bagSlot[slotId] = itemCount
end
end
else
DBv3[itemKey] = {}
DBv3[itemKey].filterType = itemFilterType
DBv3[itemKey].itemQuality = itemQuality
DBv3[itemKey].itemName = itemName
DBv3[itemKey].locations = {}
DBv3[itemKey].locations[location] = {}
DBv3[itemKey].locations[location].bagID = bagId
DBv3[itemKey].locations[location].bagSlot = {}
DBv3[itemKey].locations[location].bagSlot[slotId] = itemCount
DBitem = DBv3[itemKey]
end
--@Baertram:
--Added for other addons like FCOItemSaver. Only needed for non-account wide bags!
if isBagToBuildItemInstanceOrUniqueId then
DBitem.itemInstanceOrUniqueId = itemInstanceOrUniqueId
end
if nil ~= location and DBitem.locations and DBitem.locations[location] and IIfA:TableCount(DBitem.locations[location].bagSlot) == 0 then
p("Zapping location=<<1>>, bag=<<2>>, slot=<<3>>", location, bagId, slotId)
DBitem.locations[location] = nil
end
if zo_strlen(itemKey) < 10 then
DBv3[itemKey].itemLink = itemLink
end
-- p("saved bag/slot=<<1>>/<<2>> <<3>> x<<4>> -> <<5>>, loc=<<6>>", bagId, slotId, itemLink, itemCount, itemKey, location)
return DBv3[itemKey], itemKey
end
--[[
function IIfA:ValidateItemCounts(bagID, slotId, dbItem, itemKey, itemLinkOverride, override)
local itemCount
local itemLink, itemLinkCheck
local guildName = GetGuildName(GetSelectedGuildBankId())
if zo_strlen(itemKey) < 10 then
if override and itemLinkOverride then
itemLink = itemLinkOverride
else
itemLink = dbItem.itemLink or GetItemLink(bagID, slotId)
end
else
itemLink = itemKey
end
p(zo_strformat("ValidateItemCounts: <<1>> in bag <<2>>/<<3>>", itemLink, bagID, slotId))
for locName, data in pairs(dbItem.locations) do
if (data.bagID == BAG_GUILDBANK and locName == guildName) or
-- we're looking at the right guild bank
data.bagID == BAG_VIRTUAL or
data.bagID == BAG_BANK or
data.bagID == BAG_SUBSCRIBER_BANK or
nil ~= GetCollectibleForHouseBankBag and nil ~= GetCollectibleForHouseBankBag(data.bagID) or -- is housing bank, mana
((data.bagID == BAG_BACKPACK or data.bagID == BAG_WORN) and locName == GetCurrentCharacterId()) then
itemLinkCheck = GetItemLink(data.bagID, data.bagSlot, LINK_STYLE_BRACKETS)
if itemLinkCheck == nil then
itemLinkCheck = (override and itemLinkOverride) or IIfA.EMPTY_STRING
end
if itemLinkCheck ~= itemLink then
if bagID ~= data.bagID and slotId ~= data.bagSlot then
-- it's no longer the same item, or it's not there at all
IIfA.database[itemKey].locations[locName] = nil
end
-- item link is valid, just make sure we have our count right
elseif bagId == data.bagID then
_, data.itemCount = GetItemInfo(bagID, slotId)
end
end
end
end
--]]
local function CollectBag(bagId, tracked)
if bagId <= BAG_MAX_VALUE and bagId ~= BAG_SUBSCRIBER_BANK then
-- ignore subscriber bank, it's handled along with the regular bank
local bagItems
bagItems = GetBagSize(bagId)
if bagId == BAG_WORN then
IIfA:ClearLocationData(IIfA.currentCharacterId, BAG_WORN)
elseif bagId == BAG_BANK then
-- do NOT add BAG_SUBSCRIBER_BANK here, it'll wipe whatever already got put into the bank on first hit
IIfA:ClearLocationData(GetString(IIFA_BAG_BANK))
elseif bagId == BAG_BACKPACK then
IIfA:ClearLocationData(IIfA.currentCharacterId, BAG_BACKPACK)
elseif bagId == BAG_VIRTUAL then
IIfA:ClearLocationData(GetString(IIFA_BAG_CRAFTBAG))
elseif bagId >= BAG_HOUSE_BANK_ONE and bagId <= BAG_HOUSE_BANK_TEN then
if IsOwnerOfCurrentHouse() then
IIfA:ClearLocationData(GetCollectibleForHouseBankBag(bagId))
else
return -- prevent reading the house bag if we're not in our own home
end
end
if tracked then
if bagId ~= BAG_VIRTUAL then
if bagId ~= BAG_SUBSCRIBER_BANK then
grabBagContent(bagId)
if bagId == BAG_BANK then
grabBagContent(BAG_SUBSCRIBER_BANK)
end
end
else
-- it's bag virtual
local slotId = GetNextVirtualBagSlotId(nil)
while slotId ~= nil do
-- (bagId, slotId, qty, itemLink, itemName, locationID)
IIfA:EvalBagItem(bagId, slotId)
slotId = GetNextVirtualBagSlotId(slotId)
end
end
end
end
end
function IIfA:CollectAll(b_useAsync)
local BagList = IIfA:GetTrackedBags() -- 20.1. mana: Iterating over a list now
local bagId, tracked
for bagId, tracked in pairs(BagList) do
-- do NOT use ipairs, it's non-linear list (holes in the # sequence)
if b_useAsync then
task:Call(function() CollectBag(bagId, tracked) end)
else
CollectBag(bagId, tracked)
end
end
-- when b_useAsync is true, this isn't being called from the player unloaded event, so we need to re-make bag/slot index
if b_useAsync then
-- 6-3-17 AM - need to clear unowned items when deleting char/guildbank too
-- 4-4-18 AM - need to call AFTER collectbag is called
task:Call(function()
IIfA:ClearUnowned()
IIfA:MakeBSI()
end, 1000)
else
-- 6-3-17 AM - need to clear unowned items when deleting char/guildbank too
-- 4-4-18 AM - call immediately after collectbag calls above
IIfA:ClearUnowned()
IIfA:MakeBSI() -- 5-11-19 AM - added missing call (if this is on player unload, it's not necessary, but might be used some other time)
end
end
function IIfA:ClearUnowned()
-- 2015-3-7 Assembler Maniac - new code added to go through full inventory list, remove any un-owned items
local n, ItemLink, DBItem
local ItemOwner, ItemData
for ItemLink, DBItem in pairs(IIfA.database) do
n = 0
for ItemOwner, ItemData in pairs(DBItem.locations) do
if ItemOwner == IIfA.EMPTY_STRING then
DBItem.locations[IIfA.EMPTY_STRING] = nil
else
n = n + 1
if ItemOwner ~= "Bank" and ItemOwner ~= "CraftBag" then
if ItemData.bagID == BAG_BACKPACK or ItemData.bagID == BAG_WORN then
if IIfA.CharIdToName[ItemOwner] == nil then
DBItem.locations[ItemOwner] = nil
n = n - 1
end
elseif ItemData.bagID == BAG_GUILDBANK then
if IIfA.guildBanks[ItemOwner] == nil or IIfA.guildBanks[ItemOwner].bCollectData == false then
DBItem.locations[ItemOwner] = nil
n = n - 1
end
end
end
end
end
if (n == 0) then
IIfA.database[ItemLink] = nil
end
end
-- 2015-3-7 end of addition
end
function IIfA:ClearLocationData(location, bagID)
-- if loc is characterid, bagID can be BAG_BACKPACK, or BAG_WORN, if nil, don't do anything
local DBv3 = IIfA.database
local itemLocation = nil
local LocationCount = 0
local itemName, itemData
local bChar = nil
if bagID ~= nil then
bChar = location == IIfA.currentCharacterId
end
if (DBv3) then
p(zo_strformat("IIfA:ClearLocationData(<<1>>, <<2>>)", location, bagID))
for itemName, itemData in pairs(DBv3) do
itemLocation = itemData.locations[location]
if itemLocation and (bChar == nil or (bChar and itemLocation.bagID == bagID)) then
itemData.locations[location] = nil
end
LocationCount = 0
for locName, location in pairs(itemData.locations) do
LocationCount = LocationCount + 1
break
end
if (LocationCount == 0) then
DBv3[itemName] = nil
end
end
end
end
-- rewrite item links with proper level value in them, instead of random value based on who knows what
-- written by SirInsidiator
--[[
local function RewriteItemLink(itemLink)
local requiredLevel = select(6, ZO_LinkHandler_ParseLink(itemLink))
requiredLevel = tonumber(requiredLevel)
local trueRequiredLevel = GetItemLinkRequiredLevel(itemLink)
itemLink = string.gsub(itemLink, "|H(%d):item:(.*)" , "|H0:item:%2")
if requiredLevel ~= trueRequiredLevel then
itemLink = string.gsub(itemLink, "|H0:item:(%d+):(%d+):(%d+)(.*)" , "|H0:item:%1:%2:".. trueRequiredLevel .."%4")
end
return itemLink
end
local function GetItemIdentifier(itemLink)
local itemType = GetItemLinkItemType(itemLink)
local data = {zo_strsplit(":", itemLink:match("|H(.-)|h.-|h"))}
local itemId = data[3]
local level = GetItemLinkRequiredLevel(itemLink)
local cp = GetItemLinkRequiredChampionPoints(itemLink)
-- local results
-- results.itemId = itemId
-- results.itemType = itemType
-- results.level = level
-- results.cp = cp
if(itemType == ITEMTYPE_WEAPON or itemType == ITEMTYPE_ARMOR) then
local trait = GetItemLinkTraitInfo(itemLink)
return string.format("%s,%s,%d,%d,%d", itemId, data[4], trait, level, cp)
elseif(itemType == ITEMTYPE_POISON or itemType == ITEMTYPE_POTION) then
return string.format("%s,%d,%d,%s", itemId, level, cp, data[23])
-- elseif(hasDifferentQualities[itemType]) then
-- return string.format("%s,%s", itemId, data[4])
else
return itemId
end
end
--]]
function IIfA:RenameItems()
local DBv3 = IIfA.database
local item = nil
local itemName
if (DBv3) then
for item, itemData in pairs(DBv3) do
itemName = nil
if item:match("|H") then
itemName = zo_strformat(SI_TOOLTIP_ITEM_NAME, GetItemLinkName(item))
else
itemName = zo_strformat(SI_TOOLTIP_ITEM_NAME, GetItemLinkName(itemData.itemLink))
end
if itemName ~= nil then
itemData.itemName = itemName
end
end
end
end