-- Called when user click on the keybind / press the key.
local bagToScan = SHARED_INVENTORY:GenerateFullSlotData(nil, bagId)
Roomba.scanInStackableBag(bagToScan)
if NonContiguousCount(Roomba.duplicates) > 0 then Roomba.restackStackableBag(bagId, duplicateList) end
-- Scan in a stackable bag
function Roomba.scanInStackableBag(bagToScan)
Roomba.lookUp = {}
Roomba.duplicates = {}
local duplitemp = {}
-- We only need to store slots with items
for index, slot in pairs(bagToScan) do
-- Stack at max?
local stack, maxStack = GetSlotStackSize(slot.bagId, slot.slotIndex)
-- Stack is not at max
if stack ~= maxStack then
-- itemId
local itemInstanceId = slot.itemInstanceId
-- We already find this item before
if Roomba.lookUp[itemInstanceId] then
-- Already marked as duplicate?
if not duplitemp[itemInstanceId] then
-- Duplicate
duplitemp[itemInstanceId] = Roomba.lookUp[itemInstanceId]
end
else
-- New item found
Roomba.lookUp[itemInstanceId] = {}
end
-- Now group all items by id
table.insert(Roomba.lookUp[itemInstanceId], {slot = slot.slotIndex, stack = stack, texture = slot.iconFile, name = slot.name, itemInstanceId = slot.itemInstanceId})
end
end
local i = 1
for _, data in pairs(duplitemp) do
Roomba.duplicates[i] = data
i = i + 1
end
end
-- duplicateList is Roomba.duplicates
function Roomba.restackStackableBag(bagId, duplicateList)
local restartAfter = false
local itemIndex = 0
local indexItemsDuplicated, dataItems = next(duplicateList)
local result = {}
-- Loop for item X/Y/Z
while indexItemsDuplicated do
local index = 1
local itemInfo = dataItems[index]
local baseSlot = nil
local lastMoveWasSingleStack = false
local lastMoveWasMultiStack = false
result[indexItemsDuplicated] = {}
-- Loop for item X and slots 1/2/3/y
while itemInfo do
-- 1st loop : we go in
if baseSlot == nil then
-- Our actual stack / Our max size
baseSlot = itemInfo
baseSlot.actualStack, baseSlot.maxStack = GetSlotStackSize(bagId, itemInfo.slot)
else
local qty
-- If stacking, will we get 1 or 2 stacks ?
itemInfo.maxStack = baseSlot.maxStack
if (baseSlot.actualStack + itemInfo.stack) <= baseSlot.maxStack then
-- Only 1 stack, we can merge stacks
qty = itemInfo.stack
-- Merging
if IsProtectedFunction("RequestMoveItem") then
CallSecureProtected("RequestMoveItem", bagId, itemInfo.slot, bagId, baseSlot.slot, qty)
else
RequestMoveItem(bagId, itemInfo.slot, bagId, baseSlot.slot, qty)
end
-- Update values baseSlot can still be used in next loop
baseSlot.actualStack = baseSlot.actualStack + itemInfo.stack
baseSlot.stack = baseSlot.actualStack
if lastMoveWasMultiStack == true then
result[indexItemsDuplicated][#result[indexItemsDuplicated]] = baseSlot
lastMoveWasSingleStack = true
lastMoveWasMultiStack = false
elseif lastMoveWasSingleStack == true then
result[indexItemsDuplicated][#result[indexItemsDuplicated]] = baseSlot
lastMoveWasMultiStack = false
else
table.insert(result[indexItemsDuplicated], baseSlot)
lastMoveWasSingleStack = true
lastMoveWasMultiStack = false
end
else
-- It won't fit, just move the qty to match maxStack, no need to rescan because slots don't move, only stacks.
qty = baseSlot.maxStack - baseSlot.actualStack
-- Merging
if IsProtectedFunction("RequestMoveItem") then
CallSecureProtected("RequestMoveItem", bagId, itemInfo.slot, bagId, baseSlot.slot, qty)
else
RequestMoveItem(bagId, itemInfo.slot, bagId, baseSlot.slot, qty)
end
if lastMoveWasMultiStack == true then
result[indexItemsDuplicated][#result[indexItemsDuplicated]].stack = baseSlot.maxStack
result[indexItemsDuplicated][#result[indexItemsDuplicated]].actualStack = baseSlot.maxStack
table.insert(result[indexItemsDuplicated], itemInfo)
result[indexItemsDuplicated][#result[indexItemsDuplicated]].stack = itemInfo.stack - qty
result[indexItemsDuplicated][#result[indexItemsDuplicated]].actualStack = itemInfo.stack - qty
lastMoveWasSingleStack = false
elseif lastMoveWasSingleStack == true then
result[indexItemsDuplicated][#result[indexItemsDuplicated]].stack = baseSlot.maxStack
result[indexItemsDuplicated][#result[indexItemsDuplicated]].actualStack = baseSlot.maxStack
table.insert(result[indexItemsDuplicated], itemInfo)
result[indexItemsDuplicated][#result[indexItemsDuplicated]].stack = itemInfo.stack - qty
result[indexItemsDuplicated][#result[indexItemsDuplicated]].actualStack = itemInfo.stack - qty
lastMoveWasSingleStack = false
lastMoveWasMultiStack = true
else
table.insert(result[indexItemsDuplicated], baseSlot)
result[indexItemsDuplicated][#result[indexItemsDuplicated]].stack = baseSlot.maxStack
result[indexItemsDuplicated][#result[indexItemsDuplicated]].actualStack = baseSlot.maxStack
table.insert(result[indexItemsDuplicated], itemInfo)
result[indexItemsDuplicated][#result[indexItemsDuplicated]].stack = itemInfo.stack - qty
result[indexItemsDuplicated][#result[indexItemsDuplicated]].actualStack = itemInfo.stack - qty
lastMoveWasSingleStack = false
lastMoveWasMultiStack = true
end
-- Baseslot is now at max, we cannot use it anymore
baseSlot = itemInfo
baseSlot.actualStack = itemInfo.stack - qty
end
end
index = index + 1
itemInfo = dataItems[index]
end
itemIndex = itemIndex + 1
indexItemsDuplicated, dataItems = next(duplicateList, itemIndex)
end
-- Rescan to permit the user press the keybind again. Because Bank got a lag, we need to call Roomba.onBankReady() and its zo_callLater to avoid having our restacking job still unknown
if bagId == BAG_BANK then
Roomba.onBankReady()
-- Only on restacking bag
elseif bagId == BAG_BACKPACK then
Roomba.onSceneStateChange(SCENE_HIDDEN, SCENE_SHOWING)
end
end