Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Date: ???
- Fixed incompatibility with Extended Vanilla. Resolves https://github.com/pyanodon/pybugreports/issues/1265
- Added py.find_latest_undo_action to find the latest undo action referencing a supplied entity
- Fixed that reproductive complex had extremely small alt-mode icons. Resolves https://github.com/pyanodon/pybugreports/issues/1377
- Added py.transfer_stack, py.transfer_stack_to_cursor, py.transfer_cursor_to_stack, and py.transfer_inventory_items
---------------------------------------------------------------------------------------------------
Version: 3.0.41
Date: 2025-12-28
Expand Down
1 change: 1 addition & 0 deletions lib/control-stage.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require "events"
require "vector"
require "smuggler"
require "compound-entities"
require "inventory"

---Draws a red error icon at the entity's position.
---@param entity LuaEntity
Expand Down
4 changes: 3 additions & 1 deletion lib/data-stage.lua
Original file line number Diff line number Diff line change
Expand Up @@ -520,4 +520,6 @@ py.flip_4way_animation = function(animation4way)
end

---@diagnostic disable-next-line: duplicate-set-field
py.on_event = function() end
---@param event defines.events|defines.events[]|string
---@param f function
py.on_event = function(event, f) end
1 change: 0 additions & 1 deletion lib/events.lua
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ _G.gui_events = {
[defines.events.on_gui_text_changed] = {},
[defines.events.on_gui_checked_state_changed] = {},
[defines.events.on_gui_selection_state_changed] = {},
[defines.events.on_gui_checked_state_changed] = {},
[defines.events.on_gui_elem_changed] = {},
[defines.events.on_gui_value_changed] = {},
[defines.events.on_gui_location_changed] = {},
Expand Down
115 changes: 115 additions & 0 deletions lib/inventory.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
-- all things relating to inventory management and transfers

---@param stack LuaItemStack
---@return boolean simple whether or not the stack is simple, in that is has no special data to be managed
local function is_simple_stack(stack)
return not stack.is_item_with_label and
not stack.is_item_with_entity_data and
not stack.is_tool and
not stack.grid
end

---@param stack LuaItemStack
---@param inventory LuaInventory
---@param amount_to_transfer? uint|double maximum amount to transfer, attempts to transfer full stack if omitted. can be specified as number of items or ratio of current stack size
---@return uint amount_transferred
py.transfer_stack = function(stack, inventory, amount_to_transfer)
if not stack or not stack.valid_for_read or not inventory then return 0 end
if not inventory.can_insert(stack) then return 0 end
local destination = inventory.find_empty_stack(stack)
if stack.grid and not destination then return 0 end -- special case for grid items, can only use transfer_stack
if amount_to_transfer and amount_to_transfer < 1 then
amount_to_transfer = math.floor(stack.count * amount_to_transfer + 0.5)
end
---@cast amount_to_transfer uint
if not destination or is_simple_stack(stack) then
local pre_transfer_amount = stack.count
stack.count = amount_to_transfer and amount_to_transfer < stack.count and amount_to_transfer or stack.count
-- full, or almost full
local amount_transferred = inventory.insert(stack)
if amount_transferred == pre_transfer_amount then
stack.clear()
else
stack.count = pre_transfer_amount - amount_transferred
end
return amount_transferred
end
destination.transfer_stack(stack, amount_to_transfer)
return amount_to_transfer or destination.count
end

---@param player LuaPlayer
---@param stack LuaItemStack
---@param amount_to_transfer? uint|double maximum amount to transfer, attempts to transfer full stack if omitted. can be specified as number of items or ratio of current stack size
py.transfer_stack_to_cursor = function(player, stack, amount_to_transfer)
if not stack or not stack.valid_for_read or player.controller_type == defines.controllers.spectator then return end
local cursor_stack = player.cursor_stack
if amount_to_transfer and amount_to_transfer < 1 then
amount_to_transfer = math.floor(stack.count * amount_to_transfer + 0.5)
end
---@cast amount_to_transfer uint
if is_simple_stack(stack) then
cursor_stack.set_stack{
name = stack.name,
quality = stack.quality,
count = amount_to_transfer or stack.count,
spoil_percent = stack.spoil_percent,
health = stack.health
}
if amount_to_transfer then
stack.count = stack.count - amount_to_transfer
else
stack.clear()
end
else
cursor_stack.transfer_stack(stack, amount_to_transfer)
end
end

---@param player LuaPlayer
---@param stack LuaItemStack
---@param amount_to_transfer? uint|double maximum amount to transfer, attempts to transfer full stack if omitted. can be specified as number of items or ratio of current stack size
py.transfer_cursor_to_stack = function(player, stack, amount_to_transfer)
local cursor_stack = player.cursor_stack
if not cursor_stack or not cursor_stack.valid_for_read then return end
if amount_to_transfer and amount_to_transfer < 1 then
amount_to_transfer = math.floor(cursor_stack.count * amount_to_transfer + 0.5)
end
---@cast amount_to_transfer uint
if is_simple_stack(cursor_stack) then
stack.set_stack{
name = cursor_stack.name,
quality = cursor_stack.quality,
count = amount_to_transfer or cursor_stack.count,
spoil_percent = cursor_stack.spoil_percent,
health = cursor_stack.health
}
if amount_to_transfer then
cursor_stack.count = cursor_stack.count - amount_to_transfer
else
cursor_stack.clear()
end
else
stack.transfer_stack(cursor_stack, amount_to_transfer)
end
end

---@param inventory LuaInventory
---@param target_inventory LuaInventory
---@param stack_to_match? LuaItemStack item stack to match. attempts to match quality and name, transfers all items if omitted or no items in the stack
---@param amount_to_transfer? uint|double maximum amount to transfer, attempts to transfer full stack if omitted. can be specified as number of items or ratio of current stack size
---@param is_supported? function whether the target inventory is supported
py.transfer_inventory_items = function(inventory, target_inventory, stack_to_match, amount_to_transfer, is_supported)
local total_transferred = 0

local item = stack_to_match and stack_to_match.valid_for_read and {name = stack_to_match.name, quality = stack_to_match.quality}
for i = 1, #inventory do
if not inventory[i].valid_for_read or is_supported and not is_supported(inventory[i]) then goto continue end
if item and (inventory[i].name ~= item.name or inventory[i].quality ~= item.quality) then goto continue end

total_transferred = total_transferred + py.transfer_stack(inventory[i], target_inventory, amount_to_transfer)

::continue::
end
return total_transferred
end
Loading