169 lines
5.0 KiB
Lua
169 lines
5.0 KiB
Lua
local function add_or_create(t, i, n)
|
|
t[i] = t[i] and t[i] + n or n
|
|
end
|
|
|
|
local function get_group_item(invCache, groups)
|
|
local maxCount = 0
|
|
local maxItem
|
|
local isInGroups
|
|
|
|
for item, count in pairs(invCache) do
|
|
isInGroups = true
|
|
|
|
for _, group in ipairs(groups) do
|
|
if minetest.get_item_group(item, group) == 0 then
|
|
isInGroups = false
|
|
break
|
|
end
|
|
end
|
|
|
|
if isInGroups and count > maxCount then
|
|
maxItem = item
|
|
maxCount = count
|
|
end
|
|
end
|
|
|
|
return maxItem
|
|
end
|
|
|
|
function cg.auto_get_craftable(player, craft)
|
|
local inv = player:get_inventory():get_list("main")
|
|
local invCache = {}
|
|
|
|
-- Create a cache of the inventory with itemName = count pairs.
|
|
-- This speeds up searching for items.
|
|
for _, stack in ipairs(inv) do
|
|
if stack:get_count() > 0 then
|
|
add_or_create(invCache, stack:get_name(), stack:get_count())
|
|
end
|
|
end
|
|
|
|
local reqItems = {}
|
|
local reqGroups = {}
|
|
|
|
-- Find out how many of each item/group is required to craft one item.
|
|
for _, item in pairs(craft.items) do
|
|
if item:sub(1, 6) == "group:" then
|
|
add_or_create(reqGroups, item, 1)
|
|
else
|
|
add_or_create(reqItems, item, 1)
|
|
end
|
|
end
|
|
|
|
local gMaxItem
|
|
|
|
-- For each group, find the item in that group from the player's inventory
|
|
-- with the largest count.
|
|
for group, count in pairs(reqGroups) do
|
|
gMaxItem = get_group_item(invCache, group:sub(7):split(","))
|
|
|
|
if gMaxItem then
|
|
add_or_create(reqItems, gMaxItem, count)
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
local craftable = 1000
|
|
|
|
for item, count in pairs(reqItems) do
|
|
if invCache[item] then
|
|
craftable = math.min(craftable, math.floor(invCache[item] / count))
|
|
else
|
|
return 0
|
|
end
|
|
|
|
-- We can't craft more than the stack_max of our ingredients.
|
|
if minetest.registered_items[item].stack_max then
|
|
craftable = math.min(craftable,
|
|
minetest.registered_items[item].stack_max)
|
|
end
|
|
end
|
|
|
|
return craftable
|
|
end
|
|
|
|
function cg.auto_craft(player, craft, num)
|
|
local inv = player:get_inventory()
|
|
|
|
if not inv:is_empty("craft") then
|
|
-- Attempt to move items to the player's main inventory.
|
|
for idx, stack in ipairs(inv:get_list("craft")) do
|
|
if not stack:is_empty() then
|
|
stack = inv:add_item("main", stack)
|
|
inv:set_stack("craft", idx, stack)
|
|
end
|
|
end
|
|
|
|
-- Check again, and return if not all items were moved.
|
|
if not inv:is_empty("craft") then
|
|
minetest.chat_send_player(player:get_player_name(),
|
|
cg.S("Item could not be crafted!"))
|
|
return
|
|
end
|
|
end
|
|
|
|
if craft.width > inv:get_width("craft")
|
|
or table.maxn(craft.items) > inv:get_size("craft") then
|
|
return
|
|
end
|
|
|
|
local invList = inv:get_list("main")
|
|
local width = craft.width == 0 and inv:get_width("craft") or craft.width
|
|
local stack, invCache
|
|
local groupCache = {}
|
|
|
|
for idx, item in pairs(craft.items) do
|
|
-- Shift the indices so the items in the craft go to the right spots on
|
|
-- the crafting grid.
|
|
idx = (idx + (inv:get_width("craft") - width) *
|
|
math.floor((idx - 1) / width))
|
|
|
|
if item:sub(1, 6) == "group:" then
|
|
-- Create an inventory cache.
|
|
if not invCache then
|
|
invCache = {}
|
|
|
|
for _, stack in ipairs(invList) do
|
|
if stack:get_count() > 0 then
|
|
add_or_create(invCache, stack:get_name(),
|
|
stack:get_count())
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Get the most plentiful item in the group.
|
|
if not groupCache[item] then
|
|
groupCache[item] = get_group_item(invCache,
|
|
item:sub(7):split(","))
|
|
end
|
|
|
|
-- Move the selected item.
|
|
if groupCache[item] then
|
|
stack = inv:remove_item("main",
|
|
ItemStack({name = groupCache[item], count = num}))
|
|
inv:set_stack("craft", idx, stack)
|
|
end
|
|
else
|
|
-- Move the item.
|
|
stack = inv:remove_item("main",
|
|
ItemStack({name = item, count = num}))
|
|
inv:set_stack("craft", idx, stack)
|
|
end
|
|
end
|
|
end
|
|
|
|
minetest.register_on_player_inventory_action(
|
|
function(player, action, inventory, inventory_info)
|
|
-- Hide the autocrafting menu when the player drops an item.
|
|
if cg.AUTOCRAFTING and inventory_info.listname == "main" then
|
|
local context = sfinv.get_or_create_context(player)
|
|
|
|
if context.cg_auto_menu then
|
|
context.cg_auto_menu = false
|
|
sfinv.set_player_inventory_formspec(player)
|
|
end
|
|
end
|
|
end
|
|
)
|