-- -- Crafting mod -- By Kaadmy, for Pixture -- crafting = {} crafting.registered_crafts = {} -- Crafting can only take 4 itemstacks as input for sanity/interface reasons crafting.max_inputs = 4 -- Default crafting definition values crafting.default_craftdef = { output = nil, description = "", items = {}, } function crafting.register_craft(output, def) -- `output` can be any ItemStack value, but count is NOT used local itemstack = ItemStack(output) local itemn = itemstack:get_name() if crafting.registered_crafts[itemn] ~= nil then minetest.log("warning", "Tried to register an existing craft " .. itemn) return end local craftdef = { output = itemstack, description = def.description or minetest.registered_items[itemn].description, items = def.items or default.default_craftdef.items, } if #craftdef.items > 4 then minetest.log("warning", "Attempting to register craft " .. itemn .." with more than " .. crafting.max_inputs .. " inputs, keeping") end for i = 1, crafting.max_inputs do craftdef.items[i] = ItemStack(craftdef.items[i]) end crafting.registered_crafts[itemn] = craftdef minetest.log("info", "Registered recipe for " .. itemn .. ": " .. dump(crafting.registered_crafts[itemn])) end function crafting.craft(output, items) -- `output` can be any ItemStack value -- Duplicate items in `items` should work correctly print(dump(output)) local wanted_itemstack = ItemStack(output) print(dump(wanted_itemstack:to_string())) local craftdef = crafting.registered_crafts[wanted_itemstack:get_name()] if craftdef == nil then minetest.log("warning", "Tried to craft an unregistered item " .. wanted_itemstack:get_name()) return nil end --print("Craftdef items: " .. dump(craftdef.items)) print("Input before: " .. dump(items)) -- Check for validity local craft_count = wanted_itemstack:get_count() for i = 1, crafting.max_inputs do local required_itemstack = ItemStack(craftdef.items[i]) local itemc = 0 if required_itemstack ~= nil and required_itemstack:get_count() ~= 0 then for j = 1, crafting.max_inputs do local input_itemstack = ItemStack(items[j]) if input_itemstack:get_name() == required_itemstack:get_name() then itemc = itemc + input_itemstack:get_count() end end craft_count = math.min(craft_count, math.floor(itemc / required_itemstack:get_count())) if craft_count < 1 then minetest.log("warning", "Not enough items to craft " .. wanted_itemstack:get_name()) return nil -- Not enough items end end end --print("Craft count: " .. craft_count .. "/" .. output.count) -- Iterate through second time to take items used for crafting local function remove_used_item(itemn, count) local items_required = count for i = 1, crafting.max_inputs do local input_itemstack = ItemStack(items[i]) if items[i] ~= nil and input_itemstack:get_name() == itemn then local items_left = items_required - input_itemstack:get_count() print("Taking " .. items_required .. " items from " .. itemn) input_itemstack:take_item(items_required) if items_left > 0 then items_required = items_required - (items_required - items_left) else items[i] = input_itemstack:to_table() break end items[i] = input_itemstack:to_table() end end end for i = 1, crafting.max_inputs do local required_itemstack = ItemStack(craftdef.items[i]) if craftdef.items[i] ~= nil then remove_used_item(required_itemstack:get_name(), required_itemstack:get_count() * craft_count) end end print("Input after: " .. dump(items)) return items end crafting.register_craft( "default:stone 4", { items = { {name = "default:stick", count = 3}, {name = "default:fiber", count = 2}, {name = "group:stone", count = 2}, }, }) crafting.craft( "default:stone 2", { {name = "default:stick", count = 4}, -- 0 leftover {name = "default:stick", count = 5}, -- 3 leftover {name = "default:fiber", count = 9}, -- 5 leftover {name = "group:stone", count = 4}, -- 0 leftover }) local function on_player_recieve_fields(player, form_name, fields) if form_name ~= "crafting:crafting" or fields.cancel then return end local inv = player:get_inventory() if fields.trade then local item = player:get_wielded_item() local trade_wanted1 = inv:get_stack("gold_trade_wanted", 1):to_string() local trade_wanted2 = inv:get_stack("gold_trade_wanted", 2):to_string() local trade_in1 = inv:get_stack("gold_trade_in", 1):to_string() local trade_in2 = inv:get_stack("gold_trade_in", 2):to_string() local matches = trade_wanted1 == trade_in1 and trade_wanted2 == trade_in2 local meta = minetest.deserialize(item:get_metadata()) local trade = {"gold:gold", "gold:gold", "default:stick"} local trade_type = "" if meta then trade = meta.trade trade_type = meta.trade_type end if matches then if inv:room_for_item("gold_trade_out", trade[3]) then inv:add_item("gold_trade_out", trade[3]) inv:set_stack("gold_trade_in", 1, "") inv:set_stack("gold_trade_in", 2, "") end end end end minetest.register_on_player_receive_fields(on_player_recieve_fields) default.log("mod:crafting", "loaded")