Chests API expansion

This commit is contained in:
Mikita Wiśniewski 2024-09-20 12:22:30 +07:00
parent 513413afc7
commit 5fb564a93d
3 changed files with 155 additions and 128 deletions

@ -9,6 +9,8 @@ local table = table
local sf = string.format local sf = string.format
local concat = table.concat
-- Recursively merge tables with eachother -- Recursively merge tables with eachother
local function table_merge(tbl, ...) local function table_merge(tbl, ...)
local t = table.copy(tbl) local t = table.copy(tbl)
@ -415,6 +417,56 @@ local function get_chest_inventories(pos, side)
return top_inv, bottom_inv return top_inv, bottom_inv
end end
local inv_fs = {}
function inv_fs.small(name, pos)
return concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,0.75;9,3;]", pos.x, pos.y, pos.z),
"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;]",
sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
"listring[current_player;main]",
})
end
function inv_fs.double(name, pos, pos_other)
return concat({
"formspec_version[4]",
"size[11.75,14.15]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,0.75;9,3;]", pos.x, pos.y, pos.z),
mcl_formspec.get_itemslot_bg_v4(0.375, 4.5, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,4.5;9,3;]", pos_other.x, pos_other.y, pos_other.z),
"label[0.375,8.45;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 8.825, 9, 3),
"list[current_player;main;0.375,8.825;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 12.775, 9, 1),
"list[current_player;main;0.375,12.775;9,1;]",
--BEGIN OF LISTRING WORKAROUND
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;input]", pos.x, pos.y, pos.z),
--END OF LISTRING WORKAROUND
"listring[current_player;main]" ..
sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;main]", pos_other.x, pos_other.y, pos_other.z),
})
end
-- Functions used in double chest registration code -- Functions used in double chest registration code
-- ------------------------------------------------ -- ------------------------------------------------
-- The `return function` wrapping is necessary to avoid stacking up parameters. -- The `return function` wrapping is necessary to avoid stacking up parameters.
@ -504,16 +556,76 @@ local function log_inventory_put_double(side) return function(pos, listname, ind
-- END OF LISTRING WORKAROUND -- END OF LISTRING WORKAROUND
end end end end
-- Prototype and template tables
-- -----------------------------
-- Used in chest registration code, moved here for performance reasons
-- Group templates
local t_groups_inv = { deco_block = 1 }
local t_groups_small = {
container = 2,
deco_block = 1,
chest_entity = 1,
not_in_creative_inventory = 1
}
local t_groups_left = { double_chest = 1 }
local t_groups_right = {
-- In a double chest, the entity is assigned to the left side, but not the right one.
chest_entity = 0,
double_chest = 2
}
local t_inv_size = {
w = 9,
h = 3
}
local dummy_tiles = { "blank.png^[resize:16x16" }
local nodebox_small = {
type = "fixed",
fixed = { -0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375 },
}
local nodebox_left = {
type = "fixed",
fixed = { -0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375 },
}
local nodebox_right = {
type = "fixed",
fixed = { -0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375 },
}
local simple_kinds = { "small", "double" }
-- This is a helper function to register regular chests (both small and double variants). -- This is a helper function to register regular chests (both small and double variants).
-- Some parameters here are only utilized by trapped chests. -- Some parameters here are only utilized by trapped chests.
function mcl_chests.register_chest(basename, d) function mcl_chests.register_chest(basename, d)
-- If this passes without crash, we know for a fact that d = {...} -- If this passes without crash, we know for a fact that d = {...}
assert((d and type(d) == "table"), "Second argument to mcl_chests.register_chest must be a table") assert((d and type(d) == "table"), "Second argument to mcl_chests.register_chest must be a table")
if d.double == nil then
d.double = true
end
-- Fallback for when there is no `title` field -- Fallback for when there is no `title` field
if not d.title then d.title = {} end if not d.title then d.title = {} end
d.title.small = d.title.small or d.desc d.title.small = d.title.small or d.desc
d.title.double = d.title.double or ("Large " .. d.title.small) if d.double then d.title.double = d.title.double or ("Large " .. d.title.small) end
-- Inventory fallbacks
if not d.inv then d.inv = {} end
if not d.inv.size then
d.inv.size = t_inv_size
end
if not d.inv.fs then d.inv.fs = {} end
for i = 1, #simple_kinds do
if not d.inv.fs[simple_kinds[i]] then
d.inv.fs[simple_kinds[i]] = inv_fs[simple_kinds[i]]
end
end
local small_w = d.inv.size.w
local small_h = d.inv.size.h
if not d.drop then if not d.drop then
d.drop = "mcl_chests:" .. basename d.drop = "mcl_chests:" .. basename
@ -531,10 +643,6 @@ function mcl_chests.register_chest(basename, d)
if not d.on_rightclick_right then if not d.on_rightclick_right then
d.on_rightclick_right = d.on_rightclick d.on_rightclick_right = d.on_rightclick
end end
--[[local on_rightclick_side = {
left = d.on_rightclick_left or d.on_rightclick,
right = d.on_rightclick_right or d.on_rightclick,
}]]
if not d.sounds or type(d.sounds) ~= "table" then if not d.sounds or type(d.sounds) ~= "table" then
d.sounds = { nil, "default_chest" } d.sounds = { nil, "default_chest" }
@ -557,44 +665,34 @@ function mcl_chests.register_chest(basename, d)
-- c = canonical -- c = canonical
-- r = reverse (only for double chests) -- r = reverse (only for double chests)
-- cr = canonical, reverse (only for double chests) -- cr = canonical, reverse (only for double chests)
local names = { local names = {}
small = { names.small = {
a = "mcl_chests:" .. basename .. "_small", a = concat({"mcl_chests:", basename, "_small"}),
c = "mcl_chests:" .. d.canonical_basename .. "_small", c = concat({"mcl_chests:", d.canonical_basename, "_small"}),
},
left = {
a = "mcl_chests:" .. basename .. "_left",
c = "mcl_chests:" .. d.canonical_basename .. "_left",
},
right = {
a = "mcl_chests:" .. basename .. "_right",
c = "mcl_chests:" .. d.canonical_basename .. "_right",
},
} }
if d.double then
names.left = {
a = concat({"mcl_chests:", basename, "_left"}),
c = concat({"mcl_chests:", d.canonical_basename, "_left"}),
}
names.right = {
a = concat({"mcl_chests:", basename, "_right"}),
c = concat({"mcl_chests:", d.canonical_basename, "_right"}),
}
names.left.r = names.right.a names.left.r = names.right.a
names.right.r = names.left.a
names.left.cr = names.right.c names.left.cr = names.right.c
names.right.r = names.left.a
names.right.cr = names.left.c names.right.cr = names.left.c
end
local small_textures = d.tiles.small local small_textures = d.tiles.small
local double_textures = d.tiles.double local double_textures = d.tiles.double
-- Construct groups -- Construct groups
local groups_inv = table_merge({ deco_block = 1 }, d.groups) local groups_inv = table_merge(t_groups_inv, d.groups)
local groups_small = table_merge(groups_inv, { local groups_small = table_merge(groups_inv, t_groups_small)
container = 2, local groups_left = table_merge(groups_small, t_groups_left)
deco_block = 1, local groups_right = table_merge(groups_small, t_groups_right)
chest_entity = 1,
not_in_creative_inventory = 1
}, d.groups)
local groups_left = table_merge(groups_small, {
double_chest = 1
}, d.groups)
local groups_right = table_merge(groups_small, {
-- In a double chest, the entity is assigned to the left side, but not the right one.
chest_entity = 0,
double_chest = 2
}, d.groups)
@ -631,12 +729,9 @@ function mcl_chests.register_chest(basename, d)
_doc_items_usagehelp = d.usagehelp, _doc_items_usagehelp = d.usagehelp,
_doc_items_hidden = d.hidden, _doc_items_hidden = d.hidden,
drawtype = "nodebox", drawtype = "nodebox",
node_box = { node_box = nodebox_small,
type = "fixed", tiles = dummy_tiles,
fixed = { -0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375 }, use_texture_alpha = "blend",
},
tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = "clip",
_chest_entity_textures = small_textures, _chest_entity_textures = small_textures,
_chest_entity_sound = d.sounds[2], _chest_entity_sound = d.sounds[2],
_chest_entity_mesh = "mcl_chests_chest", _chest_entity_mesh = "mcl_chests_chest",
@ -663,7 +758,7 @@ function mcl_chests.register_chest(basename, d)
-- END OF WORKAROUND -- -- END OF WORKAROUND --
local inv = meta:get_inventory() local inv = meta:get_inventory()
inv:set_size("main", 9 * 3) inv:set_size("main", small_h * small_w)
--[[ The "input" list is *another* workaround (hahahaha!) around the fact that Minetest --[[ The "input" list is *another* workaround (hahahaha!) around the fact that Minetest
does not support listrings to put items into an alternative list if the first one does not support listrings to put items into an alternative list if the first one
@ -677,15 +772,15 @@ function mcl_chests.register_chest(basename, d)
-- END OF LISTRING WORKAROUND -- END OF LISTRING WORKAROUND
-- Combine into a double chest if neighbouring another small chest -- Combine into a double chest if neighbouring another small chest
if minetest.get_node(get_double_container_neighbor_pos(pos, param2, "right")).name == if d.double and minetest.get_node(get_double_container_neighbor_pos(pos, param2, "right"))
names.small.a then .name == names.small.a then
minetest.swap_node(pos, { name = names.right.a, param2 = param2 }) minetest.swap_node(pos, { name = names.right.a, param2 = param2 })
local p = get_double_container_neighbor_pos(pos, param2, "right") local p = get_double_container_neighbor_pos(pos, param2, "right")
minetest.swap_node(p, { name = names.left.a, param2 = param2 }) minetest.swap_node(p, { name = names.left.a, param2 = param2 })
create_entity(p, names.left.a, double_textures, param2, true, d.sounds[2], create_entity(p, names.left.a, double_textures, param2, true, d.sounds[2],
"mcl_chests_chest", "chest") "mcl_chests_chest", "chest")
elseif minetest.get_node(get_double_container_neighbor_pos(pos, param2, "left")).name == elseif d.double and minetest.get_node(get_double_container_neighbor_pos(pos, param2, "left"))
names.small.a then .name == names.small.a then
minetest.swap_node(pos, { name = names.left.a, param2 = param2 }) minetest.swap_node(pos, { name = names.left.a, param2 = param2 })
create_entity(pos, names.left.a, double_textures, param2, true, d.sounds[2], create_entity(pos, names.left.a, double_textures, param2, true, d.sounds[2],
"mcl_chests_chest", "chest") "mcl_chests_chest", "chest")
@ -726,22 +821,7 @@ function mcl_chests.register_chest(basename, d)
minetest.show_formspec(clicker:get_player_name(), minetest.show_formspec(clicker:get_player_name(),
sf("mcl_chests:%s_%s_%s_%s", d.canonical_basename, pos.x, pos.y, pos.z), sf("mcl_chests:%s_%s_%s_%s", d.canonical_basename, pos.x, pos.y, pos.z),
table.concat({ d.inv.fs.small(name, pos)
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,0.75;9,3;]", pos.x, pos.y, pos.z),
"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;]",
sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
"listring[current_player;main]",
})
) )
if d.on_rightclick then if d.on_rightclick then
@ -759,14 +839,12 @@ function mcl_chests.register_chest(basename, d)
on_rotate = simple_rotate, on_rotate = simple_rotate,
}) })
if d.double then
minetest.register_node(names.left.a, { minetest.register_node(names.left.a, {
drawtype = "nodebox", drawtype = "nodebox",
node_box = { node_box = nodebox_left,
type = "fixed", tiles = dummy_tiles,
fixed = { -0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375 }, use_texture_alpha = "blend",
},
tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = "clip",
_chest_entity_textures = double_textures, _chest_entity_textures = double_textures,
_chest_entity_sound = d.sounds[2], _chest_entity_sound = d.sounds[2],
_chest_entity_mesh = "mcl_chests_chest", _chest_entity_mesh = "mcl_chests_chest",
@ -817,32 +895,7 @@ function mcl_chests.register_chest(basename, d)
minetest.show_formspec(clicker:get_player_name(), minetest.show_formspec(clicker:get_player_name(),
sf("mcl_chests:%s_%s_%s_%s", d.canonical_basename, pos.x, pos.y, pos.z), sf("mcl_chests:%s_%s_%s_%s", d.canonical_basename, pos.x, pos.y, pos.z),
table.concat({ d.inv.fs.double(name, pos, pos_other)
"formspec_version[4]",
"size[11.75,14.15]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,0.75;9,3;]", pos.x, pos.y, pos.z),
mcl_formspec.get_itemslot_bg_v4(0.375, 4.5, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,4.5;9,3;]", pos_other.x, pos_other.y, pos_other.z),
"label[0.375,8.45;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 8.825, 9, 3),
"list[current_player;main;0.375,8.825;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 12.775, 9, 1),
"list[current_player;main;0.375,12.775;9,1;]",
--BEGIN OF LISTRING WORKAROUND
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;input]", pos.x, pos.y, pos.z),
--END OF LISTRING WORKAROUND
"listring[current_player;main]" ..
sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;main]", pos_other.x, pos_other.y, pos_other.z),
})
) )
if d.on_rightclick_left then if d.on_rightclick_left then
@ -862,12 +915,9 @@ function mcl_chests.register_chest(basename, d)
drawtype = "nodebox", drawtype = "nodebox",
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
node_box = { node_box = nodebox_right,
type = "fixed", tiles = dummy_tiles,
fixed = { -0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375 }, use_texture_alpha = "blend",
},
tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = "clip",
groups = groups_right, groups = groups_right,
drop = d.drop, drop = d.drop,
is_ground_content = false, is_ground_content = false,
@ -912,40 +962,15 @@ function mcl_chests.register_chest(basename, d)
minetest.show_formspec(clicker:get_player_name(), minetest.show_formspec(clicker:get_player_name(),
sf("mcl_chests:%s_%s_%s_%s", d.canonical_basename, pos.x, pos.y, pos.z), sf("mcl_chests:%s_%s_%s_%s", d.canonical_basename, pos.x, pos.y, pos.z),
table.concat({ d.inv.fs.double(name, pos_other, pos)
"formspec_version[4]",
"size[11.75,14.15]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,0.75;9,3;]", pos_other.x, pos_other.y, pos_other.z),
mcl_formspec.get_itemslot_bg_v4(0.375, 4.5, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,4.5;9,3;]", pos.x, pos.y, pos.z),
"label[0.375,8.45;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 8.825, 9, 3),
"list[current_player;main;0.375,8.825;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 12.775, 9, 1),
"list[current_player;main;0.375,12.775;9,1;]",
--BEGIN OF LISTRING WORKAROUND
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;input]", pos.x, pos.y, pos.z),
--END OF LISTRING WORKAROUND
"listring[current_player;main]" ..
sf("listring[nodemeta:%s,%s,%s;main]", pos_other.x, pos_other.y, pos_other.z),
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
})
) )
if d.on_rightclick_right then if d.on_rightclick_right then
d.on_rightclick_right(pos, node, clicker) d.on_rightclick_right(pos, node, clicker)
end end
player_chest_open(clicker, pos_other, names.left.a, double_textures, node.param2, true, d.sounds[2], player_chest_open(clicker, pos_other, names.left.a, double_textures, node.param2, true,
"mcl_chests_chest") d.sounds[2], "mcl_chests_chest")
end, end,
mesecons = d.mesecons, mesecons = d.mesecons,
on_rotate = no_rotate, on_rotate = no_rotate,
@ -957,6 +982,7 @@ function mcl_chests.register_chest(basename, d)
doc.add_entry_alias("nodes", names.small.a, "nodes", names.left.a) doc.add_entry_alias("nodes", names.small.a, "nodes", names.left.a)
doc.add_entry_alias("nodes", names.small.a, "nodes", names.right.a) doc.add_entry_alias("nodes", names.small.a, "nodes", names.right.a)
end end
end
end end
-- Returns false if itemstack is a shulker box -- Returns false if itemstack is a shulker box

@ -34,6 +34,7 @@ mcl_chests.register_chest("stone_chest", {
}, },
hardness = 4.0, hardness = 4.0,
hidden = false, hidden = false,
double = false,
-- It bites! -- It bites!
on_rightclick = function(pos, node, clicker) on_rightclick = function(pos, node, clicker)
mcl_util.deal_damage(clicker, 2) mcl_util.deal_damage(clicker, 2)

@ -39,7 +39,7 @@ dofile(modpath .. "/api.lua")
dofile(modpath .. "/chests.lua") dofile(modpath .. "/chests.lua")
dofile(modpath .. "/ender.lua") dofile(modpath .. "/ender.lua")
dofile(modpath .. "/shulkers.lua") dofile(modpath .. "/shulkers.lua")
--dofile(modpath .. "/example.lua") dofile(modpath .. "/example.lua")