forked from minetest-mods/unified_inventory
Implement new crafting algorithm (#132)
* Implement new crafting algorithm * Take craft width into account when creating craft index * Fix moving logic, correctly check for empty stacks * Return early when there's not enough items for craft * Bound match_count with smallest stack_max value, take from inventory only if needed * Continue if item can't be moved to the current position. * Fix metadata loss and. Improve placement for some corner cases. * Drop items from oversized stacks on the ground * Place items exactly as displayed in the guide * One source list one destination. Try to take from destination list first
This commit is contained in:
parent
4a1414bacc
commit
ca6d9a10df
1
api.lua
1
api.lua
@ -305,4 +305,3 @@ function unified_inventory.is_creative(playername)
|
|||||||
return minetest.check_player_privs(playername, {creative=true})
|
return minetest.check_player_privs(playername, {creative=true})
|
||||||
or minetest.settings:get_bool("creative_mode")
|
or minetest.settings:get_bool("creative_mode")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
1
init.lua
1
init.lua
@ -65,6 +65,7 @@ dofile(modpath.."/group.lua")
|
|||||||
dofile(modpath.."/api.lua")
|
dofile(modpath.."/api.lua")
|
||||||
dofile(modpath.."/internal.lua")
|
dofile(modpath.."/internal.lua")
|
||||||
dofile(modpath.."/callbacks.lua")
|
dofile(modpath.."/callbacks.lua")
|
||||||
|
dofile(modpath.."/match_craft.lua")
|
||||||
dofile(modpath.."/register.lua")
|
dofile(modpath.."/register.lua")
|
||||||
|
|
||||||
if minetest.settings:get_bool("unified_inventory_bags") ~= false then
|
if minetest.settings:get_bool("unified_inventory_bags") ~= false then
|
||||||
|
409
match_craft.lua
Normal file
409
match_craft.lua
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
-- match_craft.lua
|
||||||
|
-- Find and automatically move inventory items to the crafting grid
|
||||||
|
-- according to the recipe.
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Retrieve items from inventory lists and calculate their total count.
|
||||||
|
Return a table of "item name" - "total count" pairs.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
inv: minetest inventory reference
|
||||||
|
lists: names of inventory lists to use
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
-- Count items in "main" and "craft" lists of player inventory
|
||||||
|
unified_inventory.count_items(player_inv_ref, {"main", "craft"})
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
{
|
||||||
|
["default:pine_wood"] = 2,
|
||||||
|
["default:acacia_wood"] = 4,
|
||||||
|
["default:chest"] = 3,
|
||||||
|
["default:axe_diamond"] = 2, -- unstackable item are counted too
|
||||||
|
["wool:white"] = 6
|
||||||
|
}
|
||||||
|
]]--
|
||||||
|
function unified_inventory.count_items(inv, lists)
|
||||||
|
local counts = {}
|
||||||
|
|
||||||
|
for i = 1, #lists do
|
||||||
|
local name = lists[i]
|
||||||
|
local size = inv:get_size(name)
|
||||||
|
local list = inv:get_list(name)
|
||||||
|
|
||||||
|
for j = 1, size do
|
||||||
|
local stack = list[j]
|
||||||
|
|
||||||
|
if not stack:is_empty() then
|
||||||
|
local item = stack:get_name()
|
||||||
|
local count = stack:get_count()
|
||||||
|
|
||||||
|
counts[item] = (counts[item] or 0) + count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return counts
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Retrieve craft recipe items and their positions in the crafting grid.
|
||||||
|
Return a table of "craft item name" - "set of positions" pairs.
|
||||||
|
|
||||||
|
Note that if craft width is not 3 then positions are recalculated as
|
||||||
|
if items were placed on a 3x3 grid. Also note that craft can contain
|
||||||
|
groups of items with "group:" prefix.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
craft: minetest craft recipe
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
-- Bed recipe
|
||||||
|
{
|
||||||
|
["wool:white"] = {[1] = true, [2] = true, [3] = true}
|
||||||
|
["group:wood"] = {[4] = true, [5] = true, [6] = true}
|
||||||
|
}
|
||||||
|
--]]
|
||||||
|
function unified_inventory.count_craft_positions(craft)
|
||||||
|
local positions = {}
|
||||||
|
local craft_items = craft.items
|
||||||
|
local craft_type = unified_inventory.registered_craft_types[craft.type]
|
||||||
|
or unified_inventory.craft_type_defaults(craft.type, {})
|
||||||
|
local display_width = craft_type.dynamic_display_size
|
||||||
|
and craft_type.dynamic_display_size(craft).width
|
||||||
|
or craft_type.width
|
||||||
|
local craft_width = craft_type.get_shaped_craft_width
|
||||||
|
and craft_type.get_shaped_craft_width(craft)
|
||||||
|
or display_width
|
||||||
|
local i = 0
|
||||||
|
|
||||||
|
for y = 1, 3 do
|
||||||
|
for x = 1, craft_width do
|
||||||
|
i = i + 1
|
||||||
|
local item = craft_items[i]
|
||||||
|
|
||||||
|
if item ~= nil then
|
||||||
|
local pos = 3 * (y - 1) + x
|
||||||
|
local set = positions[item]
|
||||||
|
|
||||||
|
if set ~= nil then
|
||||||
|
set[pos] = true
|
||||||
|
else
|
||||||
|
positions[item] = {[pos] = true}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return positions
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
For every craft item find all matching inventory items.
|
||||||
|
- If craft item is a group then find all inventory items that matches
|
||||||
|
this group.
|
||||||
|
- If craft item is not a group (regular item) then find only this item.
|
||||||
|
|
||||||
|
If inventory doesn't contain needed item then found set is empty for
|
||||||
|
this item.
|
||||||
|
|
||||||
|
Return a table of "craft item name" - "set of matching inventory items"
|
||||||
|
pairs.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
inv_items: table with items names as keys
|
||||||
|
craft_items: table with items names or groups as keys
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
{
|
||||||
|
["group:wood"] = {
|
||||||
|
["default:pine_wood"] = true,
|
||||||
|
["default:acacia_wood"] = true
|
||||||
|
},
|
||||||
|
["wool:white"] = {
|
||||||
|
["wool:white"] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--]]
|
||||||
|
function unified_inventory.find_usable_items(inv_items, craft_items)
|
||||||
|
local get_group = minetest.get_item_group
|
||||||
|
local result = {}
|
||||||
|
|
||||||
|
for craft_item in pairs(craft_items) do
|
||||||
|
local group = craft_item:match("^group:(.+)")
|
||||||
|
local found = {}
|
||||||
|
|
||||||
|
if group ~= nil then
|
||||||
|
for inv_item in pairs(inv_items) do
|
||||||
|
if get_group(inv_item, group) > 0 then
|
||||||
|
found[inv_item] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if inv_items[craft_item] ~= nil then
|
||||||
|
found[craft_item] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result[craft_item] = found
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Match inventory items with craft grid positions.
|
||||||
|
For every position select the matching inventory item with maximum
|
||||||
|
(total_count / (times_matched + 1)) value.
|
||||||
|
|
||||||
|
If for some position matching item cannot be found or match count is 0
|
||||||
|
then return nil.
|
||||||
|
|
||||||
|
Return a table of "matched item name" - "set of craft positions" pairs
|
||||||
|
and overall match count.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
inv_counts: table of inventory items counts from "count_items"
|
||||||
|
craft_positions: table of craft positions from "count_craft_positions"
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
match_table = {
|
||||||
|
["wool:white"] = {[1] = true, [2] = true, [3] = true}
|
||||||
|
["default:acacia_wood"] = {[4] = true, [6] = true}
|
||||||
|
["default:pine_wood"] = {[5] = true}
|
||||||
|
}
|
||||||
|
match_count = 2
|
||||||
|
--]]
|
||||||
|
function unified_inventory.match_items(inv_counts, craft_positions)
|
||||||
|
local usable = unified_inventory.find_usable_items(inv_counts, craft_positions)
|
||||||
|
local match_table = {}
|
||||||
|
local match_count
|
||||||
|
local matches = {}
|
||||||
|
|
||||||
|
for craft_item, pos_set in pairs(craft_positions) do
|
||||||
|
local use_set = usable[craft_item]
|
||||||
|
|
||||||
|
for pos in pairs(pos_set) do
|
||||||
|
local pos_item
|
||||||
|
local pos_count
|
||||||
|
|
||||||
|
for use_item in pairs(use_set) do
|
||||||
|
local count = inv_counts[use_item]
|
||||||
|
local times_matched = matches[use_item] or 0
|
||||||
|
local new_pos_count = math.floor(count / (times_matched + 1))
|
||||||
|
|
||||||
|
if pos_count == nil or pos_count < new_pos_count then
|
||||||
|
pos_item = use_item
|
||||||
|
pos_count = new_pos_count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if pos_item == nil or pos_count == 0 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local set = match_table[pos_item]
|
||||||
|
|
||||||
|
if set ~= nil then
|
||||||
|
set[pos] = true
|
||||||
|
else
|
||||||
|
match_table[pos_item] = {[pos] = true}
|
||||||
|
end
|
||||||
|
|
||||||
|
matches[pos_item] = (matches[pos_item] or 0) + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for match_item, times_matched in pairs(matches) do
|
||||||
|
local count = inv_counts[match_item]
|
||||||
|
local item_count = math.floor(count / times_matched)
|
||||||
|
|
||||||
|
if match_count == nil or item_count < match_count then
|
||||||
|
match_count = item_count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return match_table, match_count
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Remove item from inventory lists.
|
||||||
|
Return stack of actually removed items.
|
||||||
|
|
||||||
|
This function replicates the inv:remove_item function but can accept
|
||||||
|
multiple lists.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
inv: minetest inventory reference
|
||||||
|
lists: names of inventory lists
|
||||||
|
stack: minetest item stack
|
||||||
|
--]]
|
||||||
|
function unified_inventory.remove_item(inv, lists, stack)
|
||||||
|
local removed = ItemStack(nil)
|
||||||
|
local leftover = ItemStack(stack)
|
||||||
|
|
||||||
|
for i = 1, #lists do
|
||||||
|
if leftover:is_empty() then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
local cur_removed = inv:remove_item(lists[i], leftover)
|
||||||
|
removed:add_item(cur_removed)
|
||||||
|
leftover:take_item(cur_removed:get_count())
|
||||||
|
end
|
||||||
|
|
||||||
|
return removed
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Add item to inventory lists.
|
||||||
|
Return leftover stack.
|
||||||
|
|
||||||
|
This function replicates the inv:add_item function but can accept
|
||||||
|
multiple lists.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
inv: minetest inventory reference
|
||||||
|
lists: names of inventory lists
|
||||||
|
stack: minetest item stack
|
||||||
|
--]]
|
||||||
|
function unified_inventory.add_item(inv, lists, stack)
|
||||||
|
local leftover = ItemStack(stack)
|
||||||
|
|
||||||
|
for i = 1, #lists do
|
||||||
|
if leftover:is_empty() then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
leftover = inv:add_item(lists[i], leftover)
|
||||||
|
end
|
||||||
|
|
||||||
|
return leftover
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Move items from source list to destination list if possible.
|
||||||
|
Skip positions specified in exclude set.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
inv: minetest inventory reference
|
||||||
|
src_list: name of source list
|
||||||
|
dst_list: name of destination list
|
||||||
|
exclude: set of positions to skip
|
||||||
|
--]]
|
||||||
|
function unified_inventory.swap_items(inv, src_list, dst_list, exclude)
|
||||||
|
local size = inv:get_size(src_list)
|
||||||
|
local empty = ItemStack(nil)
|
||||||
|
|
||||||
|
for i = 1, size do
|
||||||
|
if exclude == nil or exclude[i] == nil then
|
||||||
|
local stack = inv:get_stack(src_list, i)
|
||||||
|
|
||||||
|
if not stack:is_empty() then
|
||||||
|
inv:set_stack(src_list, i, empty)
|
||||||
|
local leftover = inv:add_item(dst_list, stack)
|
||||||
|
|
||||||
|
if not leftover:is_empty() then
|
||||||
|
inv:set_stack(src_list, i, leftover)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Move matched items to the destination list.
|
||||||
|
|
||||||
|
If destination list position is already occupied with some other item
|
||||||
|
then function tries to (in that order):
|
||||||
|
1. Move it to the source list
|
||||||
|
2. Move it to some other unused position in destination list itself
|
||||||
|
3. Drop it to the ground if nothing else is possible.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
player: minetest player object
|
||||||
|
src_list: name of source list
|
||||||
|
dst_list: name of destination list
|
||||||
|
match_table: table of matched items
|
||||||
|
amount: amount of items per every position
|
||||||
|
--]]
|
||||||
|
function unified_inventory.move_match(player, src_list, dst_list, match_table, amount)
|
||||||
|
local inv = player:get_inventory()
|
||||||
|
local item_drop = minetest.item_drop
|
||||||
|
local src_dst_list = {src_list, dst_list}
|
||||||
|
local dst_src_list = {dst_list, src_list}
|
||||||
|
|
||||||
|
local needed = {}
|
||||||
|
local moved = {}
|
||||||
|
|
||||||
|
-- Remove stacks needed for craft
|
||||||
|
for item, pos_set in pairs(match_table) do
|
||||||
|
local stack = ItemStack(item)
|
||||||
|
local stack_max = stack:get_stack_max()
|
||||||
|
local bounded_amount = math.min(stack_max, amount)
|
||||||
|
stack:set_count(bounded_amount)
|
||||||
|
|
||||||
|
for pos in pairs(pos_set) do
|
||||||
|
needed[pos] = unified_inventory.remove_item(inv, dst_src_list, stack)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add already removed stacks
|
||||||
|
for pos, stack in pairs(needed) do
|
||||||
|
local occupied = inv:get_stack(dst_list, pos)
|
||||||
|
inv:set_stack(dst_list, pos, stack)
|
||||||
|
|
||||||
|
if not occupied:is_empty() then
|
||||||
|
local leftover = unified_inventory.add_item(inv, src_dst_list, occupied)
|
||||||
|
|
||||||
|
if not leftover:is_empty() then
|
||||||
|
inv:set_stack(dst_list, pos, leftover)
|
||||||
|
local oversize = unified_inventory.add_item(inv, src_dst_list, stack)
|
||||||
|
|
||||||
|
if not oversize:is_empty() then
|
||||||
|
item_drop(oversize, player, player:get_pos())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
moved[pos] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Swap items from unused positions to src (moved positions excluded)
|
||||||
|
unified_inventory.swap_items(inv, dst_list, src_list, moved)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Find craft match and move matched items to the destination list.
|
||||||
|
|
||||||
|
If match cannot be found or match count is smaller than the desired
|
||||||
|
amount then do nothing.
|
||||||
|
|
||||||
|
If amount passed is -1 then amount is defined by match count itself.
|
||||||
|
This is used to indicate "craft All" case.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
player: minetest player object
|
||||||
|
src_list: name of source list
|
||||||
|
dst_list: name of destination list
|
||||||
|
craft: minetest craft recipe
|
||||||
|
amount: desired amount of output items
|
||||||
|
--]]
|
||||||
|
function unified_inventory.craftguide_match_craft(player, src_list, dst_list, craft, amount)
|
||||||
|
local inv = player:get_inventory()
|
||||||
|
local src_dst_list = {src_list, dst_list}
|
||||||
|
|
||||||
|
local counts = unified_inventory.count_items(inv, src_dst_list)
|
||||||
|
local positions = unified_inventory.count_craft_positions(craft)
|
||||||
|
local match_table, match_count = unified_inventory.match_items(counts, positions)
|
||||||
|
|
||||||
|
if match_table == nil or match_count < amount then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if amount == -1 then
|
||||||
|
amount = match_count
|
||||||
|
end
|
||||||
|
|
||||||
|
unified_inventory.move_match(player, src_list, dst_list, match_table, amount)
|
||||||
|
end
|
99
register.lua
99
register.lua
@ -441,65 +441,6 @@ local function craftguide_giveme(player, formname, fields)
|
|||||||
player_inv:add_item("main", {name = output, count = amount})
|
player_inv:add_item("main", {name = output, count = amount})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Takes any stack from "main" where the `amount` of `needed_item` may fit
|
|
||||||
-- into the given crafting stack (`craft_item`)
|
|
||||||
local function craftguide_move_stacks(inv, craft_item, needed_item, amount)
|
|
||||||
if craft_item:get_count() >= amount then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local get_item_group = minetest.get_item_group
|
|
||||||
local group = needed_item:match("^group:(.+)")
|
|
||||||
if group then
|
|
||||||
if not craft_item:is_empty() then
|
|
||||||
-- Source item must be the same to fill
|
|
||||||
if get_item_group(craft_item:get_name(), group) ~= 0 then
|
|
||||||
needed_item = craft_item:get_name()
|
|
||||||
else
|
|
||||||
-- TODO: Maybe swap unmatching "craft" items
|
|
||||||
-- !! Would conflict with recursive function call
|
|
||||||
return
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- Take matching group from the inventory (biggest stack)
|
|
||||||
local main = inv:get_list("main")
|
|
||||||
local max_found = 0
|
|
||||||
for i, stack in ipairs(main) do
|
|
||||||
if stack:get_count() > max_found and
|
|
||||||
get_item_group(stack:get_name(), group) ~= 0 then
|
|
||||||
needed_item = stack:get_name()
|
|
||||||
max_found = stack:get_count()
|
|
||||||
if max_found >= amount then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if not craft_item:is_empty() and
|
|
||||||
craft_item:get_name() ~= needed_item then
|
|
||||||
return -- Item must be identical
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
needed_item = ItemStack(needed_item)
|
|
||||||
local to_take = math.min(amount, needed_item:get_stack_max())
|
|
||||||
to_take = to_take - craft_item:get_count()
|
|
||||||
if to_take <= 0 then
|
|
||||||
return -- Nothing to do
|
|
||||||
end
|
|
||||||
needed_item:set_count(to_take)
|
|
||||||
|
|
||||||
local taken = inv:remove_item("main", needed_item)
|
|
||||||
local leftover = taken:add_item(craft_item)
|
|
||||||
if not leftover:is_empty() then
|
|
||||||
-- Somehow failed to add the existing "craft" item. Undo the action.
|
|
||||||
inv:add_item("main", leftover)
|
|
||||||
return taken
|
|
||||||
end
|
|
||||||
return taken
|
|
||||||
end
|
|
||||||
|
|
||||||
local function craftguide_craft(player, formname, fields)
|
local function craftguide_craft(player, formname, fields)
|
||||||
local amount
|
local amount
|
||||||
for k, v in pairs(fields) do
|
for k, v in pairs(fields) do
|
||||||
@ -508,17 +449,14 @@ local function craftguide_craft(player, formname, fields)
|
|||||||
end
|
end
|
||||||
if not amount then return end
|
if not amount then return end
|
||||||
|
|
||||||
amount = tonumber(amount) or 99 -- fallback for "all"
|
amount = tonumber(amount) or -1 -- fallback for "all"
|
||||||
if amount <= 0 or amount > 99 then return end
|
if amount == 0 or amount < -1 or amount > 99 then return end
|
||||||
|
|
||||||
local player_name = player:get_player_name()
|
local player_name = player:get_player_name()
|
||||||
|
|
||||||
local output = unified_inventory.current_item[player_name] or ""
|
local output = unified_inventory.current_item[player_name] or ""
|
||||||
if output == "" then return end
|
if output == "" then return end
|
||||||
|
|
||||||
local player_inv = player:get_inventory()
|
|
||||||
local craft_list = player_inv:get_list("craft")
|
|
||||||
|
|
||||||
local crafts = unified_inventory.crafts_for[
|
local crafts = unified_inventory.crafts_for[
|
||||||
unified_inventory.current_craft_direction[player_name]][output] or {}
|
unified_inventory.current_craft_direction[player_name]][output] or {}
|
||||||
if #crafts == 0 then return end
|
if #crafts == 0 then return end
|
||||||
@ -528,38 +466,7 @@ local function craftguide_craft(player, formname, fields)
|
|||||||
local craft = crafts[alternate]
|
local craft = crafts[alternate]
|
||||||
if craft.width > 3 then return end
|
if craft.width > 3 then return end
|
||||||
|
|
||||||
local needed = craft.items
|
unified_inventory.craftguide_match_craft(player, "main", "craft", craft, amount)
|
||||||
local width = craft.width
|
|
||||||
if width == 0 then
|
|
||||||
-- Shapeless recipe
|
|
||||||
width = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
-- To spread the items evenly
|
|
||||||
local STEPSIZE = math.ceil(math.sqrt(amount) / 5) * 5
|
|
||||||
local current_count = 0
|
|
||||||
repeat
|
|
||||||
current_count = math.min(current_count + STEPSIZE, amount)
|
|
||||||
local index = 1
|
|
||||||
for y = 1, 3 do
|
|
||||||
for x = 1, width do
|
|
||||||
local needed_item = needed[index]
|
|
||||||
if needed_item then
|
|
||||||
local craft_index = ((y - 1) * 3) + x
|
|
||||||
local craft_item = craft_list[craft_index]
|
|
||||||
local newitem = craftguide_move_stacks(player_inv,
|
|
||||||
craft_item, needed_item, current_count)
|
|
||||||
|
|
||||||
if newitem then
|
|
||||||
craft_list[craft_index] = newitem
|
|
||||||
end
|
|
||||||
end
|
|
||||||
index = index + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
until current_count == amount
|
|
||||||
|
|
||||||
player_inv:set_list("craft", craft_list)
|
|
||||||
|
|
||||||
unified_inventory.set_inventory_formspec(player, "craft")
|
unified_inventory.set_inventory_formspec(player, "craft")
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user