Compare commits

...

10 Commits

Author SHA1 Message Date
BlackImpostor
5d97e6d401
Add Russian translation (#17) 2024-11-02 10:45:27 +01:00
SmallJoker
5bfa6d67ee Add .luacheckrc 2024-10-20 14:40:58 +02:00
SmallJoker
d3108574a2 Fix error in LBM caused by mod-placed nodes 2024-10-20 14:35:50 +02:00
Niklp
b8353d781b
Fix item duplication bug (#15)
Uses some code from https://github.com/fluxionary/minetest-crafting_bench, with the author's permission.

- Improve item movement log messages
- Only allow one item per stack in the recipe field
- Adding a recipe doesn't take the items anymore
- Add LBM to move leftover items from >1 items big stacks to the craft output
2024-05-06 17:29:03 +02:00
MysticTempest
f34e5aaef8
Fixes for mcl* compatibility (#13) 2024-01-22 18:25:31 +01:00
Cora de la Mouche
5ebbac55e8
Add mcl* compatibility (#12)
Makes this simple but useful mod compatible with mcl*, it's mostly a formspec adaptation + made the inventory lists a bit smaller (2x3 / 1x3) to make it fit more nicely.
2023-11-22 20:26:27 +01:00
tenplus1
3b3309ea43
Respect all slots upon digging and disallow TNT blasts (#11)
This pull stops players digging a workbench containing items in any inventory, it also stops them being removed with tnt.
2023-05-14 14:52:47 +02:00
nixnoxus
9dc6074987
Add listring in formspec (#7) 2022-02-02 18:53:49 +01:00
fluxionary
64e7ee216b
Fix return of replacement items (#5) 2021-08-21 09:42:22 +02:00
sfan5
69083ed6f5 Fix incorrect crafting_rate type
closes #3
2020-05-27 20:57:45 +02:00
4 changed files with 227 additions and 50 deletions

18
.luacheckrc Normal file
View File

@ -0,0 +1,18 @@
unused_args = false -- Allow them
max_line_length = 999
globals = {
-- None
}
read_globals = {
"ItemStack",
"core",
"minetest",
"default",
"hopper",
"mcl_formspec",
"mcl_sounds",
}

240
init.lua
View File

@ -1,17 +1,84 @@
local S = minetest.get_translator("crafting_bench") local S = minetest.get_translator("crafting_bench")
local F = minetest.formspec_escape
local C = minetest.colorize
minetest.register_alias("castle:workbench", "crafting_bench:workbench") minetest.register_alias("castle:workbench", "crafting_bench:workbench")
local has_mcl = minetest.get_modpath("mcl_formspec")
local has_default = minetest.get_modpath("default")
local usage_help = S("The inventory on the left is for raw materials, the inventory on the right holds finished products. The crafting grid in the center defines what recipe this workbench will make use of; place raw materials into it in the crafting pattern corresponding to what you want to build.") local usage_help = S("The inventory on the left is for raw materials, the inventory on the right holds finished products. The crafting grid in the center defines what recipe this workbench will make use of; place raw materials into it in the crafting pattern corresponding to what you want to build.")
if minetest.get_modpath("hopper") and hopper ~= nil and hopper.add_container ~= nil then if ( minetest.get_modpath("hopper") and hopper ~= nil and hopper.add_container ~= nil ) or has_mcl then
usage_help = usage_help .. "\n\n" .. S("This workbench is compatible with hoppers. Hoppers will insert into the raw material inventory and remove items from the finished goods inventory.") usage_help = usage_help .. "\n\n" .. S("This workbench is compatible with hoppers. Hoppers will insert into the raw material inventory and remove items from the finished goods inventory.")
end end
local crafting_rate = minetest.settings:get("crafting_bench_crafting_rate") local crafting_rate = tonumber(minetest.settings:get("crafting_bench_crafting_rate")) or 5
if crafting_rate == nil then crafting_rate = 5 end
if not has_default and not has_mcl then
error("The crafting bench mod needs either the default mod (minetest game) or mineclonia/mineclone2 to work")
end
local invsize_src = 2 * 4
local invsize_dst = 1 * 4
if has_mcl then
invsize_src = 2 * 3
invsize_dst = 1 * 3
end
local groups, mcl_hardness, mcl_blast_res, sounds
local steel_ingot, wood, tree
local formspec
if has_default then
formspec = 'size[10,10;]' ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
'label[1,0;'..S('Source Material')..']' ..
'list[context;src;1,1;2,4;]' ..
'label[4,0;'..S('Recipe to Use')..']' ..
'list[context;rec;4,1;3,3;]' ..
'label[7.5,0;'..S('Craft Output')..']' ..
'list[context;dst;8,1;1,4;]' ..
'list[current_player;main;1,6;8,4;]' ..
'listring[current_name;dst]'..
'listring[current_player;main]'..
'listring[current_name;src]'..
'listring[current_player;main]'
groups = {choppy=2, oddly_breakable_by_hand=2, flammable=2}
sounds = default.node_sound_wood_defaults()
elseif has_mcl then
formspec ='formspec_version[4]'..
'size[11.75,10.425]'..
mcl_formspec.get_itemslot_bg_v4(1, 0.75, 2, 3)..
mcl_formspec.get_itemslot_bg_v4(5, 0.75, 3, 3)..
mcl_formspec.get_itemslot_bg_v4(10, 0.75, 1, 3)..
'label[1,0.375;'..S('Source Material')..']' ..
'list[context;src;1,0.75;2,4;]' ..
'label[5,0.375;'..S('Recipe to Use')..']' ..
'list[context;rec;5,0.75;3,3;]' ..
'label[9.5,0.375;'..S('Craft Output')..']' ..
'list[context;dst;10,0.75;1,4;]' ..
'label[0.375,4.7;' .. F(C(mcl_formspec.label_color, S('Inventory'))) .. ']'..
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3)..
'list[current_player;main;0.375,5.1;9,3;9]'..
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1)..
'list[current_player;main;0.375,9.05;9,1;]'..
'listring[current_name;dst]'..
'listring[current_player;main]'..
'listring[current_name;src]'..
'listring[current_player;main]'
groups = {axey=2, handy=1, flammable=-1, container = 4}
sounds = mcl_sounds.node_sound_wood_defaults()
mcl_hardness = 3
mcl_blast_res = 3
end
minetest.register_node("crafting_bench:workbench",{ minetest.register_node("crafting_bench:workbench",{
description = S("Workbench"), description = S("Workbench"),
@ -27,49 +94,99 @@ minetest.register_node("crafting_bench:workbench",{
}, },
paramtype2 = "facedir", paramtype2 = "facedir",
paramtype = "light", paramtype = "light",
groups = {choppy=2,oddly_breakable_by_hand=2,flammable=2}, groups = groups,
sounds = default.node_sound_wood_defaults(), sounds = sounds,
drawtype = "normal", drawtype = "normal",
_mcl_hardness = mcl_hardness,
_mcl_blast_resistance = mcl_blast_res,
on_construct = function ( pos ) on_construct = function ( pos )
local meta = minetest.get_meta( pos ) local meta = minetest.get_meta( pos )
meta:set_string( 'formspec', meta:set_string( 'formspec', formspec)
'size[10,10;]' ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
'label[1,0;'..S('Source Material')..']' ..
'list[context;src;1,1;2,4;]' ..
'label[4,0;'..S('Recipe to Use')..']' ..
'list[context;rec;4,1;3,3;]' ..
'label[7.5,0;'..S('Craft Output')..']' ..
'list[context;dst;8,1;1,4;]' ..
'list[current_player;main;1,6;8,4;]' )
meta:set_string( 'infotext', S('Workbench')) meta:set_string( 'infotext', S('Workbench'))
local inv = meta:get_inventory() local inv = meta:get_inventory()
inv:set_size( 'src', 2 * 4 ) inv:set_size( 'src', invsize_src )
inv:set_size( 'rec', 3 * 3 ) inv:set_size( 'rec', 3 * 3 )
inv:set_size( 'dst', 1 * 4 ) inv:set_size( 'dst', invsize_dst )
end, end,
can_dig = function(pos,player) can_dig = function(pos,player)
local meta = minetest.get_meta(pos); local meta = minetest.get_meta(pos);
local inv = meta:get_inventory() local inv = meta:get_inventory()
return inv:is_empty("main") return inv:is_empty("src") and inv:is_empty("rec") and inv:is_empty("dst")
end,
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
minetest.log("action", player:get_player_name().." moves stuff in workbench at "..minetest.pos_to_string(pos))
end, end,
on_blast = function(pos) end,
on_metadata_inventory_put = function(pos, listname, index, stack, player) on_metadata_inventory_put = function(pos, listname, index, stack, player)
minetest.log("action", player:get_player_name().." moves stuff to workbench at "..minetest.pos_to_string(pos)) minetest.log("action", player:get_player_name().." put "..stack:to_string().." in workbench at "..minetest.pos_to_string(pos))
end, end,
on_metadata_inventory_take = function(pos, listname, index, stack, player) on_metadata_inventory_take = function(pos, listname, index, stack, player)
minetest.log("action", player:get_player_name().." takes stuff from workbench at "..minetest.pos_to_string(pos)) minetest.log("action", player:get_player_name().." takes "..stack:to_string().." from workbench at "..minetest.pos_to_string(pos))
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
if not minetest.is_player(player) or minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if to_list == "dst" then
-- Only allow to take from the output
return 0
elseif to_list == "rec" then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local stack = inv:get_stack(from_list, from_index)
stack:set_count(1)
inv:set_stack(to_list, to_index, stack)
if from_list == "rec" then
-- For convenience: emulate movement instead of duplication
inv:set_stack(from_list, from_index, "")
end
return 0
elseif from_list == "rec" then
-- Remove recipe stack
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_stack(from_list, from_index, "")
return 0
end
return count
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if not minetest.is_player(player) or minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "rec" then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
stack:set_count(1)
inv:set_stack("rec", index, stack)
return 0
elseif listname == "dst" then
return 0
end
return stack:get_count()
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
if not minetest.is_player(player) or minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "rec" then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_stack("rec", index, "")
return 0
end
return stack:get_count()
end, end,
}) })
local get_recipe = function ( inv ) local get_recipe = function ( inv )
local result, needed, input local output, needed, decremented_input
needed = inv:get_list( 'rec' ) needed = inv:get_list( 'rec' )
result, input = minetest.get_craft_result( { output, decremented_input = minetest.get_craft_result( {
method = 'normal', method = 'normal',
width = 3, width = 3,
items = needed items = needed
@ -77,13 +194,13 @@ local get_recipe = function ( inv )
local totalneed = {} local totalneed = {}
if result.item:is_empty() then if output.item:is_empty() then
result = nil output = nil
else else
result = result.item output = output.item
for _, item in ipairs( needed ) do for _, item in ipairs( needed ) do
if item ~= nil and not item:is_empty() and not inv:contains_item( 'src', item ) then if item ~= nil and not item:is_empty() and not inv:contains_item( 'src', item ) then
result = nil output = nil
break break
end end
if item ~= nil and not item:is_empty() then if item ~= nil and not item:is_empty() then
@ -107,13 +224,13 @@ local get_recipe = function ( inv )
end end
end end
if number > 0 then if number > 0 then
result = nil output = nil
break break
end end
end end
end end
return needed, input, result return needed, decremented_input, output
end end
minetest.register_abm( { minetest.register_abm( {
@ -123,38 +240,65 @@ minetest.register_abm( {
action = function ( pos, node ) action = function ( pos, node )
local meta = minetest.get_meta( pos ) local meta = minetest.get_meta( pos )
local inv = meta:get_inventory() local inv = meta:get_inventory()
local result, newinput, needed local output, decremented_input, needed
if not inv:is_empty( 'src' ) then if not inv:is_empty( 'src' ) then
-- Check for a valid recipe and sufficient resources to craft it -- Check for a valid recipe and sufficient resources to craft it
needed, newinput, result = get_recipe( inv ) needed, decremented_input, output = get_recipe( inv )
if result ~= nil and inv:room_for_item( 'dst', result ) then if output ~= nil and inv:room_for_item( 'dst', output) then
inv:add_item( 'dst', result ) inv:add_item( 'dst', output)
for i, item in pairs( needed ) do for _, item in pairs( needed ) do
if item ~= nil and item ~= '' then if item ~= nil and item ~= '' then
inv:remove_item( 'src', ItemStack( item ) ) inv:remove_item( 'src', ItemStack( item ) )
end end
if newinput[i] ~= nil and not newinput[i]:is_empty() then end
inv:add_item( 'src', newinput[i] ) for i = 1, 9 do
end inv:add_item( 'dst', decremented_input.items[i] )
end end
end end
end end
end end
} ) } )
local function has_locked_chest_privilege(meta, player) -- Make sure that all stacks in the 'recipe' inv count 1 item.
if player:get_player_name() ~= meta:get_string("owner") then -- Bigger stacks result in item duplication, see issue#14
return false minetest.register_lbm({
name = "crafting_bench:cleanup_rec_inv",
label = "remove multiple-item-stacks from recipe inv",
nodenames = {"crafting_bench:workbench"},
run_at_every_load = false,
action = function(pos, node)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
-- `get_list` may return `nil` when the node was placed without calling `on_construct`
for i, item in ipairs(inv:get_list("rec") or {}) do
-- Limit to stack size 1 (or keep empty)
inv:set_stack("rec", i, item:peek_item())
local leftover = inv:add_item("dst", item)
if not leftover:is_empty() then
minetest.log("action", "[crafting_bench] deleting leftover " ..
item:to_string() .. " from recipe inv at " .. minetest.pos_to_string(pos))
end
end
end end
return true })
-- Crafting recipe compatibility.
if has_default then
steel_ingot = "default:steel_ingot"
wood = "default:wood"
tree = "default:tree"
elseif has_mcl then
steel_ingot = "mcl_core:iron_ingot"
wood = "mcl_core:wood"
tree = "mcl_core:tree"
end end
minetest.register_craft({ minetest.register_craft({
output = "crafting_bench:workbench", output = "crafting_bench:workbench",
recipe = { recipe = {
{"default:steel_ingot","default:steel_ingot","default:steel_ingot"}, {steel_ingot, steel_ingot, steel_ingot},
{"default:wood", "default:wood","default:steel_ingot"}, {wood, wood, steel_ingot},
{"default:tree", "default:tree","default:steel_ingot"}, {tree, tree, steel_ingot},
} }
}) })

View File

@ -0,0 +1,16 @@
# textdomain: crafting_bench
### init.lua ###
A workbench that does work for you. Set a crafting recipe and provide raw materials and items will magically craft themselves once every @1 seconds.=Верстак работает для вас. Устанавите рецепт крафта и предоставьте сырые материалы и предмет магически скрафтит себя каждые @1 секунд.
Craft Output=Выход Крафта
Recipe to Use=Рецепт чтобы Использовать
Source Material=Источный материал
The inventory on the left is for raw materials, the inventory on the right holds finished products. The crafting grid in the center defines what recipe this workbench will make use of; place raw materials into it in the crafting pattern corresponding to what you want to build.=Инвентарь слева предназначен для сырых материалов, инвентарь справа держит готовые продукты. Сетка крафта в центре находит какой рецепт в верстаке используется; положите сырые материалы в порядке рецепта того, что вы хотите получить.
This workbench is compatible with hoppers. Hoppers will insert into the raw material inventory and remove items from the finished goods inventory.=Этот верстак поддерживает воронки. Воронки будут вставлять сырые материалы и доставать готовые.
Workbench=Верстак

View File

@ -1,4 +1,3 @@
name = crafting_bench name = crafting_bench
description = An auto-crafting bench description = An auto-crafting bench
depends = default optional_depends = hopper, doc, default, mcl_formspec, mcl_hoppers
optional_depends = hopper, doc