require "TimedActions/ISBaseTimedAction" ISInventoryTransferAction = ISBaseTimedAction:derive("ISInventoryTransferAction"); -- The PutItemInBag FMOD event duration is 10 seconds long, which stops it playing too frequently. ISInventoryTransferAction.putSoundDelay = 9.5 ISInventoryTransferAction.putSoundTime = 0 -- keep only one instance of this action so we can queue item to transfer and avoid ton of instance when moving lot of items. function ISInventoryTransferAction:countItemsRecursive(_containerList, _itemsNum) local itemsNum = _itemsNum; if #_containerList > 0 then local nextContainerList = {}; for i = 1, #_containerList do local containerObj = _containerList[i]; local containerList = containerObj:getItemsFromCategory("Container"); for j = 0, containerList:size() - 1 do table.insert(nextContainerList, containerList:get(j):getInventory()); end; itemsNum = itemsNum + containerObj:getItems():size(); end; return self:countItemsRecursive(nextContainerList, itemsNum); else return itemsNum; end; end function ISInventoryTransferAction:findRootInventory(_inventory) local inventory = _inventory; local containingItem = inventory:getContainingItem(); if containingItem and containingItem:getContainer() and containingItem:getContainer():getContainingItem() then return self:findRootInventory(containingItem:getInventory()); end; return inventory; end function ISInventoryTransferAction:isValid() if not self.item then return false; end self.dontAdd = false; if not self.destContainer or not self.srcContainer then return false; end if self.allowMissingItems and not self.srcContainer:contains(self.item) then -- if the item is destroyed before, for example when crafting something, we want to transfer the items left back to their original position, but some might be destroyed by the recipe (like molotov, the gas can will be returned, but the ripped sheet is destroyed) -- self:stop(); self.dontAdd = true; return true; end if (not self.destContainer:isExistYet()) or (not self.srcContainer:isExistYet()) then return false end local parent = self.srcContainer:getParent() -- Duplication exploit: drag items from a corpse to another container while pickup up the corpse. -- ItemContainer:isExistYet() would detect this if SystemDisabler.doWorldSyncEnable was true. if instanceof(parent, "IsoDeadBody") and parent:getStaticMovingObjectIndex() == -1 then return false end -- Don't fail if the item was transferred by a previous action. if self:isAlreadyTransferred(self.item) then return true end -- Limit items per container in MP if isClient() then if not isItemTransactionConsistent(self.item, self.srcContainer, self.destContainer) then return false end local limit = getServerOptions():getInteger("ItemNumbersLimitPerContainer"); if limit > 0 and (not instanceof(self.destContainer:getParent(), "IsoGameCharacter")) then --allow dropping full bags on an empty square or put full container in an empty container if not self.destContainer:getItems():isEmpty() then local destRoot = self:findRootInventory(self.destContainer); local srcRoot = self:findRootInventory(self.srcContainer); --total count remains the same if the same root container if srcRoot ~= destRoot then local tranferItemsNum = 1; if self.item:getCategory() == "Container" then tranferItemsNum = self:countItemsRecursive({self.item:getInventory()}, 1); end; --count items from the root container local destContainerItemsNum = self:countItemsRecursive({destRoot}, 0); --if destination is an item then add 1 if destRoot:getContainingItem() then destContainerItemsNum = destContainerItemsNum + 1; end; --total items must not exceed the server limit if destContainerItemsNum + tranferItemsNum > limit then return false; end; end; end; end; end; if ISTradingUI.instance and ISTradingUI.instance:isVisible() then return false; end if not self.srcContainer:contains(self.item) then return false; end if self.srcContainer == self.destContainer then return false; end if self.destContainer:getType()=="floor" then if instanceof(self.item, "Moveable") and self.item:getSpriteGrid()==nil then if not self.item:CanBeDroppedOnFloor() then return false; end end if self:getNotFullFloorSquare(self.item) == nil then return false; end elseif not self.destContainer:hasRoomFor(self.character, self.item) then return false; end if not self.srcContainer:isRemoveItemAllowed(self.item) then return false; end if not self.destContainer:isItemAllowed(self.item) then return false; end if self.item:getContainer() == self.srcContainer and not self.destContainer:isInside(self.item) then return true; end if isClient() and self.srcContainer:getSourceGrid() and SafeHouse.isSafeHouse(self.srcContainer:getSourceGrid(), self.character:getUsername(), true) then return false; end return false; end function ISInventoryTransferAction:update() -- reopen the correct container if self.selectedContainer then if self.selectedContainer:getParent() then self.character:faceThisObject(self.selectedContainer:getParent()) end if self.character:shouldBeTurning() then getPlayerLoot(self.character:getPlayerNum()):setForceSelectedContainer(self.selectedContainer) end getPlayerLoot(self.character:getPlayerNum()):selectButtonForContainer(self.selectedContainer) end -- if self.updateDestCont then -- self.destContainer:setSourceGrid(self.character:getCurrentSquare()); -- end -- -- if self.updateSrcCont then -- self.srcContainer:setSourceGrid(self.character:getCurrentSquare()); -- end self.item:setJobDelta(self.action:getJobDelta()); self.character:setMetabolicTarget(Metabolics.LightWork); end function ISInventoryTransferAction:removeItemOnCharacter() self.character:removeAttachedItem(self.item) if not self.character:isEquipped(self.item) then return true end local addToWorld = self.character:removeFromHands(self.item) self.character:removeWornItem(self.item, false) triggerEvent("OnClothingUpdated", self.character) return addToWorld; end ISInventoryTransferAction.putSound = nil; function ISInventoryTransferAction:doActionAnim(cont) -- for now we can't walk & do animations, so forget it for putting stuff on ground -- if cont:getType()=="floor" then -- return; -- end if not self.stopOnWalk and (self.character:isPlayerMoving() or self.character:pressedMovement(false)) then self:setActionAnim("DropWhileMoving"); return end self:setActionAnim("Loot"); self:setAnimVariable("LootPosition", ""); self:setOverrideHandModels(nil, nil); self.character:clearVariable("LootPosition"); if cont:getContainerPosition() then self:setAnimVariable("LootPosition", cont:getContainerPosition()); end if cont:getType() == "freezer" and cont:getFreezerPosition() then self:setAnimVariable("LootPosition", cont:getFreezerPosition()); end if instanceof(cont:getParent(), "IsoDeadBody") or cont:getType() == "floor" then self:setAnimVariable("LootPosition", "Low"); end if cont:getContainingItem() and cont:getContainingItem():getWorldItem() then self:setAnimVariable("LootPosition", "Low"); end self.character:reportEvent("EventLootItem"); createItemTransaction(self.item, self.srcContainer, self.destContainer) table.insert(self.transactions, { self.item, self.srcContainer, self.destContainer }) end function ISInventoryTransferAction:startActionAnim() self.item:setJobType(getText("IGUI_MovingToContainer")); -- self.jobType = getText("IGUI_JobType_Grabbing", self.item:getName()); if self.srcContainer == self.character:getInventory() then if self.destContainer:isInCharacterInventory(self.character) then self.item:setJobType(getText("IGUI_Packing")); self:setActionAnim("TransferItemOnSelf"); else self.item:setJobType(getText("IGUI_PuttingInContainer")); self.selectedContainer = self.destContainer self:doActionAnim(self.destContainer); end elseif self.srcContainer:isInCharacterInventory(self.character) then if self.destContainer == self.character:getInventory() then self.item:setJobType(getText("IGUI_Unpacking")); self:setActionAnim("TransferItemOnSelf"); else self.item:setJobType(getText("IGUI_TakingFromContainer")); self.selectedContainer = self.destContainer self:doActionAnim(self.destContainer); end elseif not self.srcContainer:isInCharacterInventory(self.character) then if self.destContainer:isInCharacterInventory(self.character) then self.item:setJobType(getText("IGUI_TakingFromContainer")); self.selectedContainer = self.srcContainer self:doActionAnim(self.srcContainer); elseif self.srcContainer:getType() == "floor" then self:doActionAnim(self.srcContainer); else self:doActionAnim(self.destContainer); end end self.jobType = self.item:getJobType() .. ": " .. self.item:getName() end function ISInventoryTransferAction:start() if self:isAlreadyTransferred(self.item) then self.selectedContainer = nil self.action:setTime(0) return end if self.dontAdd then self.selectedContainer = nil self.action:setTime(0) return end if self.character:isPlayerMoving() then self.maxTime = self.maxTime * 1.5 self.action:setTime(self.maxTime) end -- stop microwave working when putting new stuff in it if self.destContainer and self.destContainer:getType() == "microwave" and self.destContainer:getParent() and self.destContainer:getParent():Activated() then self.destContainer:getParent():setActivated(false); end if self.srcContainer and self.srcContainer:getType() == "microwave" and self.srcContainer:getParent() and self.srcContainer:getParent():Activated() then self.srcContainer:getParent():setActivated(false); end -- if self.destContainer:getPutSound() then if not ISInventoryTransferAction.putSound or not self.character:getEmitter():isPlaying(ISInventoryTransferAction.putSound) then -- Players with the Deaf trait don't play sounds. In multiplayer, we mustn't send multiple sounds to other clients. if ISInventoryTransferAction.putSoundTime + ISInventoryTransferAction.putSoundDelay < getTimestamp() then ISInventoryTransferAction.putSoundTime = getTimestamp() ISInventoryTransferAction.putSound = self.character:getEmitter():playSound("PutItemInBag") end end -- end self:startActionAnim() end function ISInventoryTransferAction:stop() self.item:setJobDelta(0.0); if self.action then self.action:setLoopedAction(false); end if self.transactions then for _,transaction in ipairs(self.transactions) do removeItemTransaction(transaction[1], transaction[2], transaction[3]) end end ISBaseTimedAction.stop(self); end function ISInventoryTransferAction:forceComplete() self.item:setJobDelta(0.0); if self.action then self.action:setLoopedAction(false); end ISBaseTimedAction.perform(self); end function ISInventoryTransferAction:forceStop() self.item:setJobDelta(0.0); if self.action then self.action:setLoopedAction(false); end ISBaseTimedAction.stop(self); end function ISInventoryTransferAction:perform() -- I would have done this in start(), however the first action added to the queue -- is started immediately, before any other actions can be added. self:checkQueueList() self.item:setJobDelta(0.0) -- print("perform on item", self.item, self.item:getDisplayName()) -- take the next item in our queue list local queuedItem = table.remove(self.queueList, 1); -- reopen the correct container if self.selectedContainer then getPlayerLoot(self.character:getPlayerNum()):selectButtonForContainer(self.selectedContainer) end for i,item in ipairs(queuedItem.items) do self.item = item -- Check destination container capacity and item-count limit. if not self:isValid() then self.queueList = {} break end self:transferItem(item); end -- if we still have other item to transfer in our queue list, we "reset" the action if #self.queueList > 0 then queuedItem = self.queueList[1] self.item = queuedItem.items[1]; -- print("reset with new item: ", queuedItem.items[1], #queuedItem.items) local time = queuedItem.time; if self:isAlreadyTransferred(self.item) then time = 0 end if self.allowMissingItems and not self.srcContainer:contains(self.item) then time = 0 end self.maxTime = time self.action:setTime(tonumber(time)) self:resetJobDelta(); self:startActionAnim() else self.action:stopTimedActionAnim(); self.action:setLoopedAction(false); if self.onCompleteFunc then local args = self.onCompleteArgs self.onCompleteFunc(args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]) end -- needed to remove from queue / start next. ISBaseTimedAction.perform(self); end if instanceof(self.item, "Radio") then self.character:updateEquippedRadioFreq(); end end function ISInventoryTransferAction:isAlreadyTransferred(item) return self.destContainer:contains(item) end function ISInventoryTransferAction:floorHasRoomFor(square, item) local capacity = self.destContainer:getEffectiveCapacity(self.character) local totalWeight = square:getTotalWeightOfItemsOnFloor() if totalWeight >= capacity then return false end if ItemContainer.floatingPointCorrection(totalWeight) + item:getUnequippedWeight() <= capacity then return true end -- Hack for single bag greater than 50 weight if item:getUnequippedWeight() >= capacity then return true end return false end function ISInventoryTransferAction:canDropOnFloor(square) if not square then return false end if not square:TreatAsSolidFloor() then return false end if square:isSolid() or square:isSolidTrans() then return false end local current = self.character:getCurrentSquare() if current ~= nil and square ~= current then if current:isBlockedTo(square) or current:isWindowTo(square) then return false end if current:HasStairs() ~= square:HasStairs() then return false end if current:HasStairs() and not current:isSameStaircase(square:getX(), square:getY(), square:getZ()) then return false end end return true end function ISInventoryTransferAction:getNotFullFloorSquare(item) local square = self.character:getCurrentSquare() if self:canDropOnFloor(square) and self:floorHasRoomFor(square, item) then return square end local cx = self.character:getX() local cy = self.character:getY() local cz = self.character:getZ() local capacity = self.destContainer:getEffectiveCapacity(self.character) for dy=-1,1 do for dx=-1,1 do if dx ~= 0 or dy ~= 0 then local square = getCell():getGridSquare(cx + dx, cy + dy, cz) if self:canDropOnFloor(square) and self:floorHasRoomFor(square, item) then return square end end end end return nil end function ISInventoryTransferAction.GetDropItemOffset(character, square, item) -- local dropX = character:getX() - math.floor(character:getX()) -- local dropY = character:getY() - math.floor(character:getY()) local dropX = ZombRand(0.0 ,1.0) local dropY = ZombRand(0.0 ,1.0) local dropZ = character:getZ() - math.floor(character:getZ()) if character:isSeatedInVehicle() then dropZ = math.floor(character:getZ()) end -- if (square ~= character:getCurrentSquare()) or getCore():getOptionDropItemsOnSquareCenter() then if getCore():getOptionDropItemsOnSquareCenter() then dropX = ZombRand(3, 7) / 10.0 dropY = ZombRand(3, 7) / 10.0 dropZ = square:getApparentZ(dropX, dropY) - square:getZ() end return dropX,dropY,dropZ end -- TODO: function to remove a list of items on server function ISInventoryTransferAction:transferItem(item) if self:isAlreadyTransferred(item) then return end if isItemTransactionConsistent(self.item, self.srcContainer, self.destContainer) then removeItemTransaction(self.item, self.srcContainer, self.destContainer) for index,transaction in ipairs(self.transactions) do if transaction[1] == self.item and transaction[2] == self.srcContainer and transaction[3] == self.destContainer then table.remove(self.transactions, index) break end end else self.queueList = {} return end if self.dontAdd then -- Crafting ingredient was destroyed and can't be put back into the container it came from. return end -- print("transfering ", item) self.item = item; --self.character:ClearVariable("LootPosition"); self.item:setJobDelta(0.0); if self.item:isFavorite() and not self.destContainer:isInCharacterInventory(self.character) then -- ISBaseTimedAction.perform(self); return; end if self.srcContainer:getType() ~= "TradeUI" and isClient() and not self.destContainer:isInCharacterInventory(self.character) and self.destContainer:getType()~="floor" then self.destContainer:addItemOnServer(self.item); end if self.srcContainer:getType() ~= "TradeUI" and isClient() and not self.srcContainer:isInCharacterInventory(self.character) and self.srcContainer:getType()~="floor" then self.srcContainer:removeItemOnServer(self.item); end if self.destContainer:getType() ~= "TradeUI" then self.srcContainer:DoRemoveItem(self.item); end -- clear it from the queue. self.srcContainer:setDrawDirty(true); self.srcContainer:setHasBeenLooted(true); self.destContainer:setDrawDirty(true); -- deal with containers that are floor if self.destContainer:getType()=="floor" then local square = self:getNotFullFloorSquare(item) if square then local addToWorld = self:removeItemOnCharacter(); -- might have been added by the masking system (if you have a bag equipped and drop it on ground for example) if addToWorld then self.destContainer:DoAddItemBlind(self.item); local dropX,dropY,dropZ = ISInventoryTransferAction.GetDropItemOffset(self.character, square, self.item) square:AddWorldInventoryItem(item, dropX, dropY, dropZ) if instanceof(item, "Radio") then local _obj = IsoRadio.new(getCell(), square, nil) local deviceData = item:getDeviceData(); if deviceData then _obj:setDeviceData(deviceData); end _obj:getModData().RadioItemID = item:getID() square:AddSpecialObject(_obj, square:getObjects():size()) if isClient() then _obj:transmitCompleteItemToServer(); end _obj:transmitModData() triggerEvent("OnObjectAdded", _obj) square:RecalcProperties() square:RecalcAllWithNeighbours(true) end end else error "no square to drop item on" end elseif self.srcContainer:getType()=="floor" and self.item:getWorldItem() ~= nil then if instanceof(self.item, "Radio") then local square = self.item:getWorldItem():getSquare() local _obj = nil for i=0, square:getObjects():size()-1 do local tObj = square:getObjects():get(i) if instanceof(tObj, "IsoRadio") then if tObj:getModData().RadioItemID == self.item:getID() then _obj = tObj break end end end if _obj ~= nil then local deviceData = _obj:getDeviceData(); if deviceData then self.item:setDeviceData(deviceData); end square:transmitRemoveItemFromSquare(_obj) square:RecalcProperties(); square:RecalcAllWithNeighbours(true); end end self.item:getWorldItem():getSquare():transmitRemoveItemFromSquare(self.item:getWorldItem()); self.item:getWorldItem():getSquare():removeWorldObject(self.item:getWorldItem()); -- self.item:getWorldItem():getSquare():getObjects():remove(self.item:getWorldItem()); self.item:setWorldItem(nil); self.destContainer:AddItem(self.item); else if self.srcContainer:getType() ~= "TradeUI" then self.destContainer:AddItem(self.item); end if self.character:getInventory() ~= self.destContainer then self:removeItemOnCharacter(); end if self.item:getType() == "CandleLit" then local candle = self.destContainer:AddItem("Base.Candle"); candle:setUsedDelta(self.item:getUsedDelta()); candle:setCondition(self.item:getCondition()); candle:setFavorite(self.item:isFavorite()); self.destContainer:Remove(self.item) self.item = candle; end end if self.destContainer:getParent() and instanceof(self.destContainer:getParent(), "BaseVehicle") and self.destContainer:getParent():getPartById(self.destContainer:getType()) then local part = self.destContainer:getParent():getPartById(self.destContainer:getType()); part:setContainerContentAmount(part:getItemContainer():getCapacityWeight()); end if self.srcContainer:getParent() and instanceof(self.srcContainer:getParent(), "BaseVehicle") and self.srcContainer:getParent():getPartById(self.srcContainer:getType()) then local part = self.srcContainer:getParent():getPartById(self.srcContainer:getType()); part:setContainerContentAmount(part:getItemContainer():getCapacityWeight()); end if instanceof(self.srcContainer:getParent(), "IsoDeadBody") then self.item:setAttachedSlot(-1); self.item:setAttachedSlotType(nil); self.item:setAttachedToModel(nil); end if instanceof(self.destContainer:getParent(), 'IsoMannequin') then local mannequin = self.destContainer:getParent() mannequin:wearItem(self.item, self.character) end -- Hack for giving cooking XP. if instanceof(self.item, "Food") then self.item:setChef(self.character:getFullName()) end if self.destContainer:getType() == "stonefurnace" then self.item:setWorker(self.character:getFullName()); end local pdata = getPlayerData(self.character:getPlayerNum()); ISInventoryPage.renderDirty = true -- pdata.playerInventory:refreshBackpacks(); -- pdata.lootInventory:refreshBackpacks(); -- do the overlay sprite if not isClient() then if self.srcContainer:getParent() and self.srcContainer:getParent():getOverlaySprite() then ItemPicker.updateOverlaySprite(self.srcContainer:getParent()) end if self.destContainer:getParent() then ItemPicker.updateOverlaySprite(self.destContainer:getParent()) end end end function ISInventoryTransferAction:setOnComplete(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) self.onCompleteFunc = func self.onCompleteArgs = { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 } end function ISInventoryTransferAction:getTimeDelta() return 0; end function ISInventoryTransferAction:canMergeAction(action) if not action then return false end if action.Type ~= self.Type then return false end if action.srcContainer ~= self.srcContainer then return false end if action.destContainer ~= self.destContainer then return false end if action.onCompleteFunc or self.onCompleteFunc then return false end if action.allowMissingItems ~= self.allowMissingItems then return false end return true end function ISInventoryTransferAction:checkQueueList() local actionQueue = ISTimedActionQueue.getTimedActionQueue(self.character) local indexSelf = actionQueue:indexOf(self) if indexSelf == -1 then return end local index = indexSelf + 1 while index <= #actionQueue.queue do local action = actionQueue.queue[index] if not self:canMergeAction(action) then break end local typeAlreadyExist = false -- we check if in our queue list an item with the same type exist, so we can transfer them in bulk -- limit this to 20 items (so transfer 20 per 20 nails) -- only for item with weight < 0.1 if round(action.item:getWeight(), 3) <= 0.1 then for i,v in ipairs(self.queueList) do if v.type == action.item:getFullType() and #v.items < 20 then -- print("found same type in list", action.item:getFullType()) table.insert(v.items, action.item) typeAlreadyExist = true break end end end -- add the current item to our queue list if not typeAlreadyExist then -- print("adding to queue", action.item, action.item:getDisplayName()) table.insert(self.queueList, {items = {action.item}, time = action.maxTime, type = action.item:getFullType()}) end table.remove(actionQueue.queue, index) table.wipe(action) end end -- This is to support returning crafting ingredients to the container they were originally in. -- When true, this action does not fail if the item is no longer in the source container. function ISInventoryTransferAction:setAllowMissingItems(allow) self.allowMissingItems = allow end function ISInventoryTransferAction:getExtraLogData() local srcContainer = self.srcContainer:getType(); local destContainer = self.destContainer:getType(); if self.srcContainer == self.character:getInventory() then srcContainer = "inventory"; end; if self.destContainer == self.character:getInventory() then destContainer = "inventory"; end; return { self.item:getFullType(), "-"..srcContainer, "+"..destContainer, }; end function ISInventoryTransferAction:new (character, item, srcContainer, destContainer, time) local o = {} setmetatable(o, self) self.__index = self o.character = character; o.item = item; o.dontAdd = false; o.srcContainer = srcContainer; o.destContainer = destContainer; o.transactions = {} -- handle people right click the same item while eating it if not srcContainer or not destContainer then o.maxTime = 0; return o; end -- o.stopOnWalk = ((not o.destContainer:isInCharacterInventory(o.character)) or (not o.srcContainer:isInCharacterInventory(o.character))) and (o.destContainer:getType() ~= "floor"); -- o.stopOnRun = o.destContainer:getType() ~= "floor"; o.stopOnWalk = not o.destContainer:isInCharacterInventory(o.character) or (not o.srcContainer:isInCharacterInventory(o.character)) if (o.srcContainer == character:getInventory()) and (o.destContainer:getType() == "floor") then o.stopOnWalk = false end o.stopOnRun = true; if destContainer:getType() ~= "TradeUI" and srcContainer:getType() ~= "TradeUI" then o.maxTime = 120; -- increase time for bigger objects or when backpack is more full. local destCapacityDelta = 1.0; if o.srcContainer == o.character:getInventory() then if o.destContainer:isInCharacterInventory(o.character) then -- self.item:setJobType("Packing"); destCapacityDelta = o.destContainer:getCapacityWeight() / o.destContainer:getMaxWeight(); else -- self.item:setJobType("Putting in container"); o.maxTime = 50; end elseif not o.srcContainer:isInCharacterInventory(o.character) then if o.destContainer:isInCharacterInventory(o.character) then -- self.item:setJobType("Taking from container"); o.maxTime = 50; end end if destCapacityDelta < 0.4 then destCapacityDelta = 0.4; end if item then -- kludge to fix error when filling gas bottles out of backpack local w = item:getActualWeight(); if w > 3 then w = 3; end; o.maxTime = o.maxTime * (w) * destCapacityDelta; end if getCore():getGameMode()=="LastStand" then o.maxTime = o.maxTime * 0.3; end if o.destContainer:getType()=="floor" then if o.srcContainer == o.character:getInventory() then o.maxTime = o.maxTime * 0.1; elseif o.srcContainer:isInCharacterInventory(o.character) then -- Unpack -> drop else o.maxTime = o.maxTime * 0.2; end end if character:HasTrait("Dextrous") then o.maxTime = o.maxTime * 0.5 end if character:HasTrait("AllThumbs") then o.maxTime = o.maxTime * 4.0 end else o.maxTime = 0; end if time then o.maxTime = time; end if character:isTimedActionInstant() then o.maxTime = 1; end if item then -- kludge to fix error when filling gas bottles out of backpack if item:isFavorite() and not o.destContainer:isInCharacterInventory(o.character) then o.maxTime = 0; end end if item then -- kludge to fix error when filling gas bottles out of backpack o.queueList = {}; local queuedItem = {items = {o.item}, time = o.maxTime, type = o.item:getFullType()}; table.insert(o.queueList, queuedItem); o.loopedAction = true end return o end function javaTransferItems(character, item, srcContainer, destContainer) if instanceof(destContainer, "InventoryContainer") then destContainer = destContainer:getInventory() end if instanceof(srcContainer, "InventoryContainer") then srcContainer = srcContainer:getInventory() end if srcContainer == nil then return; end if not srcContainer:contains(item) then return; end if srcContainer == destContainer then return; end if destContainer:getCapacity() < (destContainer:getCapacityWeight() + item:getActualWeight()) then return; end if item:getContainer() ~= srcContainer or destContainer:isInside(item) or not destContainer:hasRoomFor(item) then return; end ISTimedActionQueue.add(ISInventoryTransferAction:new(character, item, srcContainer, destContainer, 10)); end