616 lines
20 KiB
Lua
616 lines
20 KiB
Lua
-- ------------------------------------------------------------------------------ --
|
|
-- TradeSkillMaster --
|
|
-- https://tradeskillmaster.com --
|
|
-- All Rights Reserved - Detailed license information included with addon. --
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
local _, TSM = ...
|
|
local BagTracking = TSM.Init("Service.BagTracking")
|
|
local Database = TSM.Include("Util.Database")
|
|
local Delay = TSM.Include("Util.Delay")
|
|
local Event = TSM.Include("Util.Event")
|
|
local SlotId = TSM.Include("Util.SlotId")
|
|
local Log = TSM.Include("Util.Log")
|
|
local TempTable = TSM.Include("Util.TempTable")
|
|
local ItemString = TSM.Include("Util.ItemString")
|
|
local ItemInfo = TSM.Include("Service.ItemInfo")
|
|
local InventoryInfo = TSM.Include("Service.InventoryInfo")
|
|
local Settings = TSM.Include("Service.Settings")
|
|
local private = {
|
|
slotDB = nil,
|
|
quantityDB = nil,
|
|
settings = nil,
|
|
bagUpdates = {
|
|
pending = {},
|
|
bagList = {},
|
|
bankList = {},
|
|
},
|
|
bankSlotUpdates = {
|
|
pending = {},
|
|
list = {},
|
|
},
|
|
reagentBankSlotUpdates = {
|
|
pending = {},
|
|
list = {},
|
|
},
|
|
bankOpen = false,
|
|
isFirstBankOpen = true,
|
|
callbackQuery = nil, -- luacheck: ignore 1004 - just stored for GC reasons
|
|
callbacks = {},
|
|
}
|
|
local BANK_BAG_SLOTS = {}
|
|
local BANK_NON_REAGENT_BAG_SLOTS = {}
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Population of the Static Data
|
|
-- ============================================================================
|
|
|
|
do
|
|
BANK_BAG_SLOTS[BANK_CONTAINER] = true
|
|
BANK_NON_REAGENT_BAG_SLOTS[BANK_CONTAINER] = true
|
|
for i = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do
|
|
BANK_BAG_SLOTS[i] = true
|
|
BANK_NON_REAGENT_BAG_SLOTS[i] = true
|
|
end
|
|
if not TSM.IsWowClassic() then
|
|
BANK_BAG_SLOTS[REAGENTBANK_CONTAINER] = true
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Module Loading
|
|
-- ============================================================================
|
|
|
|
BagTracking:OnSettingsLoad(function()
|
|
Event.Register("BAG_UPDATE", private.BagUpdateHandler)
|
|
Event.Register("BAG_UPDATE_DELAYED", private.BagUpdateDelayedHandler)
|
|
Event.Register("BANKFRAME_OPENED", private.BankOpenedHandler)
|
|
Event.Register("BANKFRAME_CLOSED", private.BankClosedHandler)
|
|
Event.Register("PLAYERBANKSLOTS_CHANGED", private.BankSlotChangedHandler)
|
|
if not TSM.IsWowClassic() then
|
|
Event.Register("PLAYERREAGENTBANKSLOTS_CHANGED", private.ReagentBankSlotChangedHandler)
|
|
end
|
|
private.slotDB = Database.NewSchema("BAG_TRACKING_SLOTS")
|
|
:AddUniqueNumberField("slotId")
|
|
:AddNumberField("bag")
|
|
:AddNumberField("slot")
|
|
:AddStringField("itemLink")
|
|
:AddStringField("itemString")
|
|
:AddSmartMapField("baseItemString", ItemString.GetBaseMap(), "itemString")
|
|
:AddNumberField("itemTexture")
|
|
:AddNumberField("quantity")
|
|
:AddBooleanField("isBoP")
|
|
:AddBooleanField("isBoA")
|
|
:AddIndex("slotId")
|
|
:AddIndex("bag")
|
|
:AddIndex("itemString")
|
|
:AddIndex("baseItemString")
|
|
:Commit()
|
|
private.quantityDB = Database.NewSchema("BAG_TRACKING_QUANTITY")
|
|
:AddUniqueStringField("itemString")
|
|
:AddNumberField("bagQuantity")
|
|
:AddNumberField("bankQuantity")
|
|
:AddNumberField("reagentBankQuantity")
|
|
:Commit()
|
|
private.callbackQuery = private.slotDB:NewQuery()
|
|
:SetUpdateCallback(private.OnCallbackQueryUpdated)
|
|
private.settings = Settings.NewView()
|
|
:AddKey("sync", "internalData", "bagQuantity")
|
|
:AddKey("sync", "internalData", "bankQuantity")
|
|
:AddKey("sync", "internalData", "reagentBankQuantity")
|
|
|
|
local items = TempTable.Acquire()
|
|
local bagQuantity = TempTable.Acquire()
|
|
local bankQuantity = TempTable.Acquire()
|
|
local reagentBankQuantity = TempTable.Acquire()
|
|
for itemString, quantity in pairs(private.settings.bagQuantity) do
|
|
if itemString == ItemString.GetBase(itemString) then
|
|
items[itemString] = true
|
|
bagQuantity[itemString] = quantity
|
|
else
|
|
private.settings.bagQuantity[itemString] = nil
|
|
end
|
|
end
|
|
for itemString, quantity in pairs(private.settings.bankQuantity) do
|
|
if itemString == ItemString.GetBase(itemString) then
|
|
items[itemString] = true
|
|
bankQuantity[itemString] = quantity
|
|
else
|
|
private.settings.bankQuantity[itemString] = nil
|
|
end
|
|
end
|
|
for itemString, quantity in pairs(private.settings.reagentBankQuantity) do
|
|
if itemString == ItemString.GetBase(itemString) then
|
|
items[itemString] = true
|
|
reagentBankQuantity[itemString] = quantity
|
|
else
|
|
private.settings.reagentBankQuantity[itemString] = nil
|
|
end
|
|
end
|
|
private.quantityDB:BulkInsertStart()
|
|
for itemString in pairs(items) do
|
|
local total = (bagQuantity[itemString] or 0) + (bankQuantity[itemString] or 0) + (reagentBankQuantity[itemString] or 0)
|
|
if total > 0 then
|
|
private.quantityDB:BulkInsertNewRow(itemString, bagQuantity[itemString] or 0, bankQuantity[itemString] or 0, reagentBankQuantity[itemString] or 0)
|
|
end
|
|
end
|
|
private.quantityDB:BulkInsertEnd()
|
|
TempTable.Release(items)
|
|
TempTable.Release(bagQuantity)
|
|
TempTable.Release(bankQuantity)
|
|
TempTable.Release(reagentBankQuantity)
|
|
end)
|
|
|
|
BagTracking:OnGameDataLoad(function()
|
|
-- we'll scan all the bags and reagent bank right away, so wipe the existing quantities
|
|
wipe(private.settings.bagQuantity)
|
|
wipe(private.settings.reagentBankQuantity)
|
|
private.quantityDB:SetQueryUpdatesPaused(true)
|
|
local query = private.quantityDB:NewQuery()
|
|
for _, row in query:Iterator() do
|
|
local oldValue = row:GetField("bagQuantity") + row:GetField("reagentBankQuantity")
|
|
if row:GetField("bankQuantity") == 0 then
|
|
-- remove this row
|
|
assert(oldValue > 0)
|
|
private.quantityDB:DeleteRow(row)
|
|
elseif oldValue ~= 0 then
|
|
-- update this row
|
|
row:SetField("bagQuantity", 0)
|
|
:SetField("reagentBankQuantity", 0)
|
|
:Update()
|
|
end
|
|
end
|
|
query:Release()
|
|
private.quantityDB:SetQueryUpdatesPaused(false)
|
|
|
|
-- WoW does not fire an update event for the backpack when you log in, so trigger one
|
|
private.BagUpdateHandler(nil, 0)
|
|
private.BagUpdateDelayedHandler()
|
|
-- trigger an update event for all bank (initial container) and reagent bank slots since we won't get one otherwise on login
|
|
assert(GetContainerNumSlots(BANK_CONTAINER) == NUM_BANKGENERIC_SLOTS)
|
|
for slot = 1, GetContainerNumSlots(BANK_CONTAINER) do
|
|
private.BankSlotChangedHandler(nil, slot)
|
|
end
|
|
if not TSM.IsWowClassic() and IsReagentBankUnlocked() then
|
|
for slot = 1, GetContainerNumSlots(REAGENTBANK_CONTAINER) do
|
|
private.ReagentBankSlotChangedHandler(nil, slot)
|
|
end
|
|
end
|
|
end)
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Module Functions
|
|
-- ============================================================================
|
|
|
|
function BagTracking.RegisterCallback(callback)
|
|
tinsert(private.callbacks, callback)
|
|
end
|
|
|
|
function BagTracking.BaseItemIterator()
|
|
return private.quantityDB:NewQuery()
|
|
:Select("itemString")
|
|
:IteratorAndRelease()
|
|
end
|
|
|
|
function BagTracking.FilterQueryBags(query)
|
|
return query
|
|
:GreaterThanOrEqual("slotId", SlotId.Join(0, 1))
|
|
:LessThanOrEqual("slotId", SlotId.Join(NUM_BAG_SLOTS + 1, 0))
|
|
end
|
|
|
|
function BagTracking.CreateQueryBags()
|
|
return BagTracking.FilterQueryBags(private.slotDB:NewQuery())
|
|
end
|
|
|
|
function BagTracking.CreateQueryBagsAuctionable()
|
|
return BagTracking.CreateQueryBags()
|
|
:Equal("isBoP", false)
|
|
:Equal("isBoA", false)
|
|
:Custom(private.NoUsedChargesQueryFilter)
|
|
end
|
|
|
|
function BagTracking.CreateQueryBagsItem(itemString)
|
|
local query = BagTracking.CreateQueryBags()
|
|
if itemString == ItemString.GetBaseFast(itemString) then
|
|
query:Equal("baseItemString", itemString)
|
|
else
|
|
query:Equal("itemString", itemString)
|
|
end
|
|
return query
|
|
end
|
|
|
|
function BagTracking.CreateQueryBagsItemAuctionable(itemString)
|
|
return BagTracking.CreateQueryBagsItem(itemString)
|
|
:Equal("isBoP", false)
|
|
:Equal("isBoA", false)
|
|
:Custom(private.NoUsedChargesQueryFilter)
|
|
end
|
|
|
|
function BagTracking.GetNumMailable(itemString)
|
|
return BagTracking.CreateQueryBagsItem(itemString)
|
|
:Equal("isBoP", false)
|
|
:SumAndRelease("quantity") or 0
|
|
end
|
|
|
|
function BagTracking.CreateQueryBank()
|
|
return private.slotDB:NewQuery()
|
|
:InTable("bag", BANK_BAG_SLOTS)
|
|
end
|
|
|
|
function BagTracking.CreateQueryBankItem(itemString)
|
|
local query = BagTracking.CreateQueryBank()
|
|
if itemString == ItemString.GetBaseFast(itemString) then
|
|
query:Equal("baseItemString", itemString)
|
|
else
|
|
query:Equal("itemString", itemString)
|
|
end
|
|
return query
|
|
end
|
|
|
|
function BagTracking.ForceBankQuantityDeduction(itemString, quantity)
|
|
if private.bankOpen then
|
|
return
|
|
end
|
|
private.slotDB:SetQueryUpdatesPaused(true)
|
|
local query = private.slotDB:NewQuery()
|
|
:Equal("itemString", itemString)
|
|
:InTable("bag", BANK_NON_REAGENT_BAG_SLOTS)
|
|
local baseItemString = ItemString.GetBaseFast(itemString)
|
|
for _, row in query:Iterator() do
|
|
if quantity > 0 then
|
|
local rowQuantity, rowBag = row:GetFields("quantity", "bag")
|
|
if rowQuantity <= quantity then
|
|
private.ChangeBagItemTotal(rowBag, baseItemString, -rowQuantity)
|
|
private.slotDB:DeleteRow(row)
|
|
quantity = quantity - rowQuantity
|
|
else
|
|
row:SetField("quantity", rowQuantity - quantity)
|
|
:Update()
|
|
private.ChangeBagItemTotal(rowBag, baseItemString, -quantity)
|
|
quantity = 0
|
|
end
|
|
end
|
|
end
|
|
query:Release()
|
|
private.slotDB:SetQueryUpdatesPaused(false)
|
|
end
|
|
|
|
function BagTracking.GetQuantityBySlotId(slotId)
|
|
return private.slotDB:GetUniqueRowField("slotId", slotId, "quantity")
|
|
end
|
|
|
|
function BagTracking.GetBagsQuantityByBaseItemString(baseItemString)
|
|
return private.quantityDB:GetUniqueRowField("itemString", baseItemString, "bagQuantity") or 0
|
|
end
|
|
|
|
function BagTracking.GetBankQuantityByBaseItemString(baseItemString)
|
|
return private.quantityDB:GetUniqueRowField("itemString", baseItemString, "bankQuantity") or 0
|
|
end
|
|
|
|
function BagTracking.GetReagentBankQuantityByBaseItemString(baseItemString)
|
|
return private.quantityDB:GetUniqueRowField("itemString", baseItemString, "reagentBankQuantity") or 0
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Event Handlers
|
|
-- ============================================================================
|
|
|
|
function private.BankOpenedHandler()
|
|
if private.isFirstBankOpen then
|
|
private.isFirstBankOpen = false
|
|
-- this is the first time opening the bank so we'll scan all the items so wipe our existing quantities
|
|
wipe(private.settings.bankQuantity)
|
|
private.quantityDB:SetQueryUpdatesPaused(true)
|
|
local query = private.quantityDB:NewQuery()
|
|
for _, row in query:Iterator() do
|
|
local oldValue = row:GetField("bankQuantity")
|
|
if row:GetField("bagQuantity") + row:GetField("reagentBankQuantity") == 0 then
|
|
-- remove this row
|
|
assert(oldValue > 0)
|
|
private.quantityDB:DeleteRow(row)
|
|
elseif oldValue ~= 0 then
|
|
-- update this row
|
|
row:SetField("bankQuantity", 0)
|
|
:Update()
|
|
end
|
|
end
|
|
query:Release()
|
|
private.quantityDB:SetQueryUpdatesPaused(false)
|
|
end
|
|
private.bankOpen = true
|
|
private.BagUpdateDelayedHandler()
|
|
private.BankSlotUpdateDelayed()
|
|
end
|
|
|
|
function private.BankClosedHandler()
|
|
private.bankOpen = false
|
|
end
|
|
|
|
function private.BagUpdateHandler(_, bag)
|
|
if private.bagUpdates.pending[bag] then
|
|
return
|
|
end
|
|
private.bagUpdates.pending[bag] = true
|
|
if bag >= BACKPACK_CONTAINER and bag <= NUM_BAG_SLOTS then
|
|
tinsert(private.bagUpdates.bagList, bag)
|
|
elseif bag == BANK_CONTAINER or (bag > NUM_BAG_SLOTS and bag <= NUM_BAG_SLOTS + NUM_BANKBAGSLOTS) then
|
|
tinsert(private.bagUpdates.bankList, bag)
|
|
elseif bag ~= KEYRING_CONTAINER then
|
|
error("Unexpected bag: "..tostring(bag))
|
|
end
|
|
end
|
|
|
|
function private.BagUpdateDelayedHandler()
|
|
private.slotDB:SetQueryUpdatesPaused(true)
|
|
|
|
-- scan any pending bags
|
|
for i = #private.bagUpdates.bagList, 1, -1 do
|
|
local bag = private.bagUpdates.bagList[i]
|
|
if private.ScanBagOrBank(bag) then
|
|
private.bagUpdates.pending[bag] = nil
|
|
tremove(private.bagUpdates.bagList, i)
|
|
end
|
|
end
|
|
if #private.bagUpdates.bagList > 0 then
|
|
-- some failed to scan so try again
|
|
Delay.AfterFrame("bagBankScan", 2, private.BagUpdateDelayedHandler)
|
|
end
|
|
|
|
if private.bankOpen then
|
|
-- scan any pending bank bags
|
|
for i = #private.bagUpdates.bankList, 1, -1 do
|
|
local bag = private.bagUpdates.bankList[i]
|
|
if private.ScanBagOrBank(bag) then
|
|
private.bagUpdates.pending[bag] = nil
|
|
tremove(private.bagUpdates.bankList, i)
|
|
end
|
|
end
|
|
if #private.bagUpdates.bankList > 0 then
|
|
-- some failed to scan so try again
|
|
Delay.AfterFrame("bagBankScan", 2, private.BagUpdateDelayedHandler)
|
|
end
|
|
end
|
|
|
|
private.slotDB:SetQueryUpdatesPaused(false)
|
|
end
|
|
|
|
function private.BankSlotChangedHandler(_, slot)
|
|
if slot > NUM_BANKGENERIC_SLOTS then
|
|
private.BagUpdateHandler(nil, slot - NUM_BANKGENERIC_SLOTS)
|
|
return
|
|
end
|
|
if private.bankSlotUpdates.pending[slot] then
|
|
return
|
|
end
|
|
private.bankSlotUpdates.pending[slot] = true
|
|
tinsert(private.bankSlotUpdates.list, slot)
|
|
Delay.AfterFrame("bankSlotScan", 2, private.BankSlotUpdateDelayed)
|
|
end
|
|
|
|
-- this is not a WoW event, but we fake it based on a delay from private.BankSlotChangedHandler
|
|
function private.BankSlotUpdateDelayed()
|
|
if not private.bankOpen then
|
|
return
|
|
end
|
|
private.slotDB:SetQueryUpdatesPaused(true)
|
|
|
|
-- scan any pending slots
|
|
for i = #private.bankSlotUpdates.list, 1, -1 do
|
|
local slot = private.bankSlotUpdates.list[i]
|
|
if private.ScanBankSlot(slot) then
|
|
private.bankSlotUpdates.pending[slot] = nil
|
|
tremove(private.bankSlotUpdates.list, i)
|
|
end
|
|
end
|
|
if #private.bankSlotUpdates.list > 0 then
|
|
-- some failed to scan so try again
|
|
Delay.AfterFrame("bankSlotScan", 2, private.BankSlotUpdateDelayed)
|
|
end
|
|
|
|
private.slotDB:SetQueryUpdatesPaused(false)
|
|
end
|
|
|
|
function private.ReagentBankSlotChangedHandler(_, slot)
|
|
if private.reagentBankSlotUpdates.pending[slot] then
|
|
return
|
|
end
|
|
private.reagentBankSlotUpdates.pending[slot] = true
|
|
tinsert(private.reagentBankSlotUpdates.list, slot)
|
|
Delay.AfterFrame("reagentBankSlotScan", 2, private.ReagentBankSlotUpdateDelayed)
|
|
end
|
|
|
|
-- this is not a WoW event, but we fake it based on a delay from private.ReagentBankSlotChangedHandler
|
|
function private.ReagentBankSlotUpdateDelayed()
|
|
private.slotDB:SetQueryUpdatesPaused(true)
|
|
|
|
-- scan any pending slots
|
|
for i = #private.reagentBankSlotUpdates.list, 1, -1 do
|
|
local slot = private.reagentBankSlotUpdates.list[i]
|
|
if private.ScanReagentBankSlot(slot) then
|
|
private.reagentBankSlotUpdates.pending[slot] = nil
|
|
tremove(private.reagentBankSlotUpdates.list, i)
|
|
end
|
|
end
|
|
if #private.reagentBankSlotUpdates.list > 0 then
|
|
-- some failed to scan so try again
|
|
Delay.AfterFrame("reagentBankSlotScan", 2, private.ReagentBankSlotUpdateDelayed)
|
|
end
|
|
|
|
private.slotDB:SetQueryUpdatesPaused(false)
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Scanning Functions
|
|
-- ============================================================================
|
|
|
|
function private.ScanBagOrBank(bag)
|
|
local numSlots = GetContainerNumSlots(bag)
|
|
private.RemoveExtraSlots(bag, numSlots)
|
|
local result = true
|
|
for slot = 1, numSlots do
|
|
if not private.ScanBagSlot(bag, slot) then
|
|
result = false
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
function private.ScanBankSlot(slot)
|
|
return private.ScanBagSlot(BANK_CONTAINER, slot)
|
|
end
|
|
|
|
function private.ScanReagentBankSlot(slot)
|
|
return private.ScanBagSlot(REAGENTBANK_CONTAINER, slot)
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Private Helper Functions
|
|
-- ============================================================================
|
|
|
|
function private.NoUsedChargesQueryFilter(row)
|
|
return not InventoryInfo.HasUsedCharges(row:GetFields("bag", "slot"))
|
|
end
|
|
|
|
function private.RemoveExtraSlots(bag, numSlots)
|
|
-- the number of slots of this bag may have changed, in which case we should remove any higher ones from our DB
|
|
local query = private.slotDB:NewQuery()
|
|
:Equal("bag", bag)
|
|
:GreaterThan("slot", numSlots)
|
|
for _, row in query:Iterator() do
|
|
local baseItemString, quantity = row:GetFields("baseItemString", "quantity")
|
|
private.ChangeBagItemTotal(bag, baseItemString, -quantity)
|
|
private.slotDB:DeleteRow(row)
|
|
end
|
|
query:Release()
|
|
end
|
|
|
|
function private.ScanBagSlot(bag, slot)
|
|
local texture, quantity, _, _, _, _, link, _, _, itemId = GetContainerItemInfo(bag, slot)
|
|
if quantity and not itemId then
|
|
-- we are pending item info for this slot so try again later to scan it
|
|
return false
|
|
elseif quantity == 0 then
|
|
-- this item is going away, so try again later to scan it
|
|
return false
|
|
end
|
|
local baseItemString = link and ItemString.GetBase(link)
|
|
local slotId = SlotId.Join(bag, slot)
|
|
local row = private.slotDB:GetUniqueRow("slotId", slotId)
|
|
if baseItemString then
|
|
local isBoP, isBoA = nil, nil
|
|
if row then
|
|
if row:GetField("itemLink") == link then
|
|
-- the item didn't change, so use the previous values
|
|
isBoP, isBoA = row:GetFields("isBoP", "isBoA")
|
|
else
|
|
isBoP, isBoA = InventoryInfo.IsSoulbound(bag, slot)
|
|
if isBoP == nil then
|
|
Log.Err("Failed to get soulbound info for %d,%d (%s)", bag, slot, link or "?")
|
|
return false
|
|
end
|
|
end
|
|
-- remove the old row from the item totals
|
|
local oldBaseItemString, oldQuantity = row:GetFields("baseItemString", "quantity")
|
|
private.ChangeBagItemTotal(bag, oldBaseItemString, -oldQuantity)
|
|
else
|
|
isBoP, isBoA = InventoryInfo.IsSoulbound(bag, slot)
|
|
if isBoP == nil then
|
|
Log.Err("Failed to get soulbound info for %d,%d (%s)", bag, slot, link or "?")
|
|
return false
|
|
end
|
|
-- there was nothing here previously so create a new row
|
|
row = private.slotDB:NewRow()
|
|
:SetField("slotId", slotId)
|
|
:SetField("bag", bag)
|
|
:SetField("slot", slot)
|
|
end
|
|
-- update the row
|
|
row:SetField("itemLink", link)
|
|
:SetField("itemString", ItemString.Get(link))
|
|
:SetField("itemTexture", texture or ItemInfo.GetTexture(link))
|
|
:SetField("quantity", quantity)
|
|
:SetField("isBoP", isBoP)
|
|
:SetField("isBoA", isBoA)
|
|
:CreateOrUpdateAndRelease()
|
|
-- add to the item totals
|
|
private.ChangeBagItemTotal(bag, baseItemString, quantity)
|
|
elseif row then
|
|
-- nothing here now so delete the row and remove from the item totals
|
|
local oldBaseItemString, oldQuantity = row:GetFields("baseItemString", "quantity")
|
|
private.ChangeBagItemTotal(bag, oldBaseItemString, -oldQuantity)
|
|
private.slotDB:DeleteRow(row)
|
|
row:Release()
|
|
end
|
|
return true
|
|
end
|
|
|
|
function private.OnCallbackQueryUpdated()
|
|
for _, callback in ipairs(private.callbacks) do
|
|
callback()
|
|
end
|
|
end
|
|
|
|
function private.ChangeBagItemTotal(bag, itemString, changeQuantity)
|
|
local totalsTable = nil
|
|
local field = nil
|
|
if bag >= BACKPACK_CONTAINER and bag <= NUM_BAG_SLOTS then
|
|
totalsTable = private.settings.bagQuantity
|
|
field = "bagQuantity"
|
|
elseif bag == BANK_CONTAINER or (bag > NUM_BAG_SLOTS and bag <= NUM_BAG_SLOTS + NUM_BANKBAGSLOTS) then
|
|
totalsTable = private.settings.bankQuantity
|
|
field = "bankQuantity"
|
|
elseif bag == REAGENTBANK_CONTAINER then
|
|
totalsTable = private.settings.reagentBankQuantity
|
|
field = "reagentBankQuantity"
|
|
else
|
|
error("Unexpected bag: "..tostring(bag))
|
|
end
|
|
totalsTable[itemString] = (totalsTable[itemString] or 0) + changeQuantity
|
|
private.UpdateQuantity(itemString, field, changeQuantity)
|
|
assert(totalsTable[itemString] >= 0)
|
|
if totalsTable[itemString] == 0 then
|
|
totalsTable[itemString] = nil
|
|
end
|
|
end
|
|
|
|
function private.UpdateQuantity(itemString, field, quantity)
|
|
assert(itemString and field and quantity)
|
|
assert(quantity ~= 0)
|
|
if not private.quantityDB:HasUniqueRow("itemString", itemString) then
|
|
-- create a new row
|
|
private.quantityDB:NewRow()
|
|
:SetField("itemString", itemString)
|
|
:SetField("bagQuantity", 0)
|
|
:SetField("bankQuantity", 0)
|
|
:SetField("reagentBankQuantity", 0)
|
|
:Create()
|
|
end
|
|
|
|
local row = private.quantityDB:GetUniqueRow("itemString", itemString)
|
|
local totalQuantity = row:GetField("bagQuantity") + row:GetField("bankQuantity") + row:GetField("reagentBankQuantity")
|
|
local oldValue = row:GetField(field)
|
|
local newValue = oldValue + quantity
|
|
assert(newValue >= 0)
|
|
if newValue == 0 and totalQuantity == oldValue then
|
|
-- remove this row
|
|
private.quantityDB:DeleteRow(row)
|
|
else
|
|
-- update this row
|
|
row:SetField(field, oldValue + quantity)
|
|
:Update()
|
|
end
|
|
row:Release()
|
|
end
|