So, if you use a "Container" object, you can call "world.containerItemApply(containerId, itemDescriptor, offset)" and it will take care of all the stacking logic (Max stack, filled capture pods, food, blueprints, etc.) But for "itemSlot" only thing we have is "widget.setItemSlotItem(widgetName, itemDescriptor)", that overwrites everything that previously was in the slot without stacking anything. The question is simple, how can I reproduce the behavior of "world.containerItemApply" for an "itemSlot"? Thank you!
To reproduce the same behaviour you to have do it yourself, handle picking up and dropping the items, combining stacks, etc Listen for when an item is dropped in the slot, and you have to handle is it the same type of item, if so it can stack, if it is a different item then swap the items. If it is the same item, will stacking go over the max stack size? And handle picking up items the same, if you pick up too much will it go over the max stack size in your hand? Also, because the item slot doesn't keep its contents, you need to handle giving the items back when the panel is closed, otherwise they are lost forever. I had to do something similar so I mocked up this code. The GUI window has 2 item slots in it, and the Lua is fully commented to hopefully make it easier to understand. This the GUI, the main thing is just setting the callbacks on the itemslots, and the custom property refundOnClose which is a list of item slots to be emptied back to the player when the panel closes. Change scripts to point to the Lua file below Code: { "gui" : { "background" : { "type" : "background", "fileHeader" : "/interface/popup/header.png", "fileBody" : "/interface/popup/body.png", "fileFooter" : "/interface/popup/footer.png" }, "windowtitle" : { "type" : "title", "title" : " Debug Testing Station", "subtitle" : " Input objects to test", "icon" : { "type" : "image", "file" : "/interface/confirmation/confirmationicon.png", "position" : [0, 0], "zlevel" : -1 } }, "close" : { "type" : "button", "base" : "/interface/x.png", "hover" : "/interface/xhover.png", "pressed" : "/interface/xpress.png", "pressedOffset" : [0, 1], "position" : [250, 103], "zlevel" : 100 }, "itemslot" : { "type" : "itemslot", "position" : [15, 52], "backingImage": "/interface/inventory/empty.png", "callback" : "slotleftclick", "rightClickCallback" : "slotrightclick" }, "itemslot2" : { "type" : "itemslot", "position" : [50, 52], "backingImage": "/interface/inventory/empty.png", "callback" : "slotleftclick", "rightClickCallback" : "slotrightclick" } }, "scriptWidgetCallbacks" : [ "slotleftclick", "slotrightclick" ], "scripts" : ["/interface/wtdebugstation/debugui.lua"], "scriptDelta" : 0, "refundOnClose" : ["itemslot","itemslot2"] } And this is The Lua file to handle the UI interactions Code: local_storage = {} --this could just be called 'storage' since ScriptPanes don't have access to the normal storage variable function init() --When the panel inits we read in the list of slots that need to be emptied on close local_storage.slotsToRefund = config.getParameter("refundOnClose",{}) end function uninit() --When the panel closes we want to give the player back any items they left in the slot(s) --For each slot we have configured for _,widget_name in pairs(local_storage.slotsToRefund or {}) do --Get the slotted item local slottedItem = widget.itemSlotItem(widget_name) --If it wasn't empty if slottedItem then --Give the player the item player.giveItem(slottedItem) end end end --Callback for left click on a slot function slotleftclick(slot_widget) --Get (a copy of) the item descriptor the player was holding local heldItem = player.swapSlotItem() --Get (a copy of) the current slotted item local slottedItem = widget.itemSlotItem(slot_widget) --If the current slotted item is blank we just drop in the held item if not slottedItem then --If we aren't dropping anything in then we just end now if not heldItem then return end --Update the slotted item widget.setItemSlotItem(slot_widget,heldItem) --Empty what the player was holding player.setSwapSlotItem(nil) --we are done and can stop here return end --If we reach here then we have an item already in the slot --If the heldItem is empty then we want to pick up what was in the slot if not heldItem then --Update the held item player.setSwapSlotItem(slottedItem) --Empty the slot widget.setItemSlotItem(slot_widget,nil) --we are done and can stop here return end --If we reach here then we are dropping an item onto the slotted item --Does the item being dropped match the slotted item? local itemsMatch = root.itemDescriptorsMatch(heldItem,slottedItem,true) --third arg is true to prevent stacking two weapons with the same name but different secondary attacks --If they don't match then we just swap them around if not itemsMatch then --Give the player the slotted item player.setSwapSlotItem(slottedItem) --Give the slot the players item widget.setItemSlotItem(slot_widget,heldItem) --Done return end --If we reach here the items do match, we need to check the max stack size and handle what happens if we try to go over the max stack --Get max stack size either from the item or the default max stack local itemConfig = root.itemConfig(slottedItem).config local rootConfig = root.assetJson("/items/defaultParameters.config") local maxStack = itemConfig.maxStack and itemConfig.maxStack or rootConfig.defaultMaxStack --Combine the quantities local slotQty = slottedItem.count local heldQty = heldItem.count local combinedQty = slotQty+heldQty --If we are below max stack size we are good to go if combinedQty <= maxStack then --Adjust quantity of slotted item slottedItem.count = combinedQty widget.setItemSlotItem(slot_widget,slottedItem) --Clear held item player.setSwapSlotItem(nil) --Done return end --If we reach here we would go over the max stack size --Adjust quantity of slotted item to max size slottedItem.count = maxStack widget.setItemSlotItem(slot_widget,slottedItem) --Find how many didn't fit in the stack, these will remain in hand local remaining = combinedQty-maxStack --Adjust quantity of held item heldItem.count = remaining player.setSwapSlotItem(heldItem) end --Callback for right click on a slot function slotrightclick(slot_widget) --Get (a copy of) the item descriptor the player was holding local heldItem = player.swapSlotItem() --Get (a copy of) the current slotted item local slottedItem = widget.itemSlotItem(slot_widget) --If the current slotted item is blank we drop in one of the held item if not slottedItem then --If we aren't dropping anything in then we just end now if not heldItem then return end local heldQty = heldItem.count --If we are only holding one item then drop it in and empty our hand if heldQty==1 then --Put the item in the slot widget.setItemSlotItem(slot_widget,heldItem) --Empty the players hand player.setSwapSlotItem(nil) --Done return end --If we reach here we are holding more than 1, we need to drop 1 and decrease held by 1 --Adjust quantity of item and put in slot heldItem.count = 1 widget.setItemSlotItem(slot_widget,heldItem) --Adjust quantity of item and update held heldItem.count = heldQty-1 player.setSwapSlotItem(heldItem) --we are done and can stop here return end --If we reach here there is currently a slotted item local slotQty = slottedItem.count --If we are aren't holding anything we want to pick up 1 quantity if not heldItem then --If there is only 1 in the slot we just pick it up if slotQty==1 then --Give player the item player.setSwapSlotItem(slottedItem) --Empty the slot widget.setItemSlotItem(slot_widget,nil) --Done return end --If we reach here there is more than 1 slotted, we want to pick up only 1 --Adjust quantity of item and put in hand slottedItem.count =1 player.setSwapSlotItem(slottedItem) --Adjust quantity of item and update slot slottedItem.count = slotQty-1 widget.setItemSlotItem(slot_widget,slottedItem) --we are done and can stop here return end --If we reach here we right clicked a slotted item while carrying an item --Are we trying to pick 1 up, or put 1 down? --I am going to assume if the items are different, we want to swap them --If the items are the same, we are trying to pick 1 up local heldQty = heldItem.count --Do the items match local itemsMatch = root.itemDescriptorsMatch(heldItem,slottedItem,true) --third arg is true to prevent stacking two weapons with the same name but different secondary attacks --If they don't match then we just swap them around if not itemsMatch then --Give the player the slotted item player.setSwapSlotItem(slottedItem) --Give the slot the players item widget.setItemSlotItem(slot_widget,heldItem) --Done return end --If we reach here the items do match, we need to check the max stack size and handle what happens if we try to go over the max stack --Calculate new quantities local newHeldQty = heldQty+1 local newSlotQty = slotQty-1 --Get max stack size either from the item or the default max stack local itemConfig = root.itemConfig(slottedItem).config local rootConfig = root.assetJson("/items/defaultParameters.config") local maxStack = itemConfig.maxStack and itemConfig.maxStack or rootConfig.defaultMaxStack --If we are below max stack size we are good to go if newHeldQty <= maxStack then --Adjust quantity of held item heldItem.count = newHeldQty player.setSwapSlotItem(heldItem) --If slot qty dropped to zero then empty slot if newSlotQty==0 then widget.setItemSlotItem(slot_widget,nil) else --Still have some quantity, update item in slot slottedItem.count = newSlotQty widget.setItemSlotItem(slot_widget,slottedItem) end --Done return end --If we reach here we would go over the max stack size --Since we are only trying to pick 1 up, there is nothing more we can do return end
Super clear and super useful! Thank you very much! Have you considered to create a "Tutorial" thread with just that? You have helped me a lot, and I'm quite sure that other people will need the same in the future.