Files

171 lines
5.2 KiB
Lua

-- Organize items in the craft inventory following a pattern:
local ui = unified_inventory
local uip = unified_inventory_plus
local default_stack_max = tonumber(minetest.settings:get("default_stack_max")) or 99
-- Backup to inject code
uip.craft_organize = ui.pages["craft"].get_formspec
ui.pages["craft"] = {
get_formspec = function(player, perplayer_formspec)
local formspec = uip.craft_organize(player, perplayer_formspec).formspec
local btnsz = ui.imgscale / 3
local btnspc = ui.imgscale / 2
if perplayer_formspec.pagecols == 4 then
-- UI is in lite mode.
for i, v in ipairs(uip.craft_patterns) do
formspec = formspec ..
("image_button[%f,%f;%f,%f;%s;craft_organize_%i;]"):format(
perplayer_formspec.craft_x + btnspc * (i - 1),
perplayer_formspec.craft_y + 0.1 - btnspc,
btnsz,
btnsz,
v.ico,
i
)
end
else
for i, v in ipairs(uip.craft_patterns) do
formspec = formspec ..
("image_button[%f,%f;%f,%f;%s;craft_organize_%i;]"):format(
perplayer_formspec.craft_x + btnspc * ((i - 1) % 6) + 0.1,
perplayer_formspec.craft_y + 0.22 - (math.ceil(i / 6)) * btnspc,
btnsz,
btnsz,
v.ico,
i
)
end
end
return { formspec = formspec }
end,
}
local function get_pattern_id(fields)
for k, _ in pairs(fields) do
local pattern_id = tonumber(k:match("craft_organize_(.*)"))
if pattern_id then
return pattern_id
end
end
end
local function get_single_item(craft_list)
for _, stk in ipairs(craft_list) do
if not stk:is_empty() then
local item = ItemStack(stk)
item:set_count(1)
return item
end
end
end
local function all_identical(craft_list)
local single_strings = {}
for _, stk in ipairs(craft_list) do
if not stk:is_empty() then
local item = ItemStack(stk)
item:set_count(1)
table.insert(single_strings, item:to_string())
end
end
if #single_strings == 0 then return false end
local first = single_strings[1]
for i = 2, #single_strings do
if first ~= single_strings[i] then
return false
end
end
return true
end
local function count_items(craft_list)
local count = 0
for _, stk in ipairs(craft_list) do
count = count + stk:get_count()
end
return count
end
-- Organize items in the craft inventory following a pattern
local function craft_organize(player, fields)
local player_name = player:get_player_name()
local pattern_id = get_pattern_id(fields)
if not pattern_id or not uip.craft_patterns[pattern_id] then
minetest.chat_send_player(player_name, "Unexpected pattern!?")
return
end
local pattern = uip.craft_patterns[pattern_id].pattern
local pattern_size = #pattern
local player_inv = player:get_inventory()
local craft_list = player_inv:get_list("craft")
local single_item = get_single_item(craft_list)
if not single_item then
-- craft inv is empty
minetest.chat_send_player(player_name, "Inventory empty.")
return
end
if not all_identical(craft_list) then
minetest.chat_send_player(player_name, "You can only organize one type of item.")
return
end
local itemname = single_item:get_name()
local def = minetest.registered_items[itemname]
if not def then
minetest.chat_send_player(player_name, "You can't organize an unknown item.")
return
end
local stacksize = def.stack_max or default_stack_max
local num_items = count_items(craft_list)
if num_items > stacksize * pattern_size then
minetest.chat_send_player(player_name, "Too many items to stack in that pattern.")
return
end
if num_items < pattern_size then
minetest.chat_send_player(player_name, "Not enough items.")
return
end
local new_stack_size = math.floor(num_items / pattern_size)
local remainder = num_items % pattern_size
local new_craft_list = {
ItemStack(), ItemStack(), ItemStack(),
ItemStack(), ItemStack(), ItemStack(),
ItemStack(), ItemStack(), ItemStack(),
}
-- because remainder is strictly less than pattern_size, this should always finish w/ remainder = 0
for _, index in ipairs(pattern) do
local new_item = ItemStack(single_item)
if remainder > 0 then
new_item:set_count(new_stack_size + 1)
remainder = remainder - 1
else
new_item:set_count(new_stack_size)
end
new_craft_list[index] = new_item
end
player_inv:set_list("craft", new_craft_list)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
for k, _ in pairs(fields) do
if k:match("craft_organize_") then
craft_organize(player, fields)
return
end
end
end)