Partially fix bad player counting of trapped chest
[MineClone/MineClone2.git] / mods / ITEMS / mcl_chests / init.lua
bloba34dc5bbd7e503c8c59ff1527fdb52d1c32553d3
1 local no_rotate, simple_rotate
2 if minetest.get_modpath("screwdriver") then
3 no_rotate = screwdriver.disallow
4 simple_rotate = screwdriver.rotate_simple
5 end
7 -- This is a helper function to register both chests and trapped chests. Trapped chests will make use of the additional parameters
8 local register_chest = function(basename, desc, longdesc, usagehelp, tiles_table, hidden, mesecons, on_rightclick_addendum, on_rightclick_addendum_left, on_rightclick_addendum_right, drop, formspec_basename)
10 if not drop then
11 drop = "mcl_chests:"..basename
12 else
13 drop = "mcl_chests:"..drop
14 end
15 if not formspec_basename then
16 formspec_basename = basename
17 end
19 minetest.register_node("mcl_chests:"..basename, {
20 description = desc,
21 _doc_items_longdesc = longdesc,
22 _doc_items_usagehelp = usagehelp,
23 _doc_items_hidden = hidden,
24 tiles = tiles_table.small,
25 paramtype2 = "facedir",
26 stack_max = 64,
27 drop = drop,
28 groups = {handy=1,axey=1, container=2, deco_block=1, material_wood=1},
29 is_ground_content = false,
30 sounds = mcl_sounds.node_sound_wood_defaults(),
31 on_construct = function(pos)
32 local param2 = minetest.get_node(pos).param2
33 local meta = minetest.get_meta(pos)
34 --[[ This is a workaround for Minetest issue 5894
35 <https://github.com/minetest/minetest/issues/5894>.
36 Apparently if we don't do this, double chests initially don't work when
37 placed at chunk borders, and some chests randomly don't work after
38 placing. ]]
39 -- FIXME: Remove this workaround when the bug has been fixed.
40 -- BEGIN OF WORKAROUND --
41 meta:set_string("workaround", "ignore_me")
42 meta:set_string("workaround", nil) -- Done to keep metadata clean
43 -- END OF WORKAROUND --
44 local inv = meta:get_inventory()
45 inv:set_size("main", 9*3)
46 --[[ The "input" list is *another* workaround (hahahaha!) around the fact that Minetest
47 does not support listrings to put items into an alternative list if the first one
48 happens to be full. See <https://github.com/minetest/minetest/issues/5343>.
49 This list is a hidden input-only list and immediately puts items into the appropriate chest.
50 It is only used for listrings and hoppers. This workaround is not that bad because it only
51 requires a simple “inventory allows” check for large chests.]]
52 -- FIXME: Refactor the listrings as soon Minetest supports alternative listrings
53 -- BEGIN OF LISTRING WORKAROUND
54 inv:set_size("input", 1)
55 -- END OF LISTRING WORKAROUND
56 if minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "right")).name == "mcl_chests:"..basename then
57 minetest.swap_node(pos, {name="mcl_chests:"..basename.."_right",param2=param2})
58 local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right")
59 minetest.swap_node(p, { name = "mcl_chests:"..basename.."_left", param2 = param2 })
60 elseif minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "left")).name == "mcl_chests:"..basename then
61 minetest.swap_node(pos, {name="mcl_chests:"..basename.."_left",param2=param2})
62 local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left")
63 minetest.swap_node(p, { name = "mcl_chests:"..basename.."_right", param2 = param2 })
64 end
65 end,
66 after_dig_node = function(pos, oldnode, oldmetadata, digger)
67 local meta = minetest.get_meta(pos)
68 local meta2 = meta
69 meta:from_table(oldmetadata)
70 local inv = meta:get_inventory()
71 for i=1,inv:get_size("main") do
72 local stack = inv:get_stack("main", i)
73 if not stack:is_empty() then
74 local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
75 minetest.add_item(p, stack)
76 end
77 end
78 meta:from_table(meta2:to_table())
79 end,
80 on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
81 minetest.log("action", player:get_player_name()..
82 " moves stuff in chest at "..minetest.pos_to_string(pos))
83 end,
84 on_metadata_inventory_put = function(pos, listname, index, stack, player)
85 minetest.log("action", player:get_player_name()..
86 " moves stuff to chest at "..minetest.pos_to_string(pos))
87 -- BEGIN OF LISTRING WORKAROUND
88 if listname == "input" then
89 local inv = minetest.get_inventory({type="node", pos=pos})
90 inv:add_item("main", stack)
91 end
92 -- END OF LISTRING WORKAROUND
93 end,
94 on_metadata_inventory_take = function(pos, listname, index, stack, player)
95 minetest.log("action", player:get_player_name()..
96 " takes stuff from chest at "..minetest.pos_to_string(pos))
97 end,
98 _mcl_blast_resistance = 2.5,
99 _mcl_hardness = 2.5,
101 on_rightclick = function(pos, node, clicker)
102 minetest.show_formspec(clicker:get_player_name(),
103 "mcl_chests:"..formspec_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z,
104 "size[9,8.75]"..
105 mcl_vars.inventory_header..
106 "background[-0.19,-0.25;9.41,10.48;mcl_chests_inventory_chest.png]"..
107 "image[0,-0.2;5,0.75;mcl_chests_fnt_chest.png]"..
108 "list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]"..
109 "list[current_player;main;0,4.5;9,3;9]"..
110 "list[current_player;main;0,7.74;9,1;]"..
111 "listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main]"..
112 "listring[current_player;main]")
114 if on_rightclick_addendum then
115 on_rightclick_addendum(pos, node, clicker)
117 end,
119 on_destruct = function(pos)
120 local players = minetest.get_connected_players()
121 for p=1, #players do
122 minetest.close_formspec(players[p]:get_player_name(), "mcl_chests:"..formspec_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z)
124 end,
125 mesecons = mesecons,
126 on_rotate = simple_rotate,
129 minetest.register_node("mcl_chests:"..basename.."_left", {
130 tiles = tiles_table.left,
131 paramtype2 = "facedir",
132 groups = {handy=1,axey=1, container=5,not_in_creative_inventory=1, material_wood=1},
133 drop = drop,
134 is_ground_content = false,
135 sounds = mcl_sounds.node_sound_wood_defaults(),
136 on_destruct = function(pos)
137 local n = minetest.get_node(pos)
138 if n.name == "mcl_chests:"..basename then
139 return
142 local players = minetest.get_connected_players()
143 for p=1, #players do
144 minetest.close_formspec(players[p]:get_player_name(), "mcl_chests:"..formspec_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z)
147 local param2 = n.param2
148 local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left")
149 if not p or minetest.get_node(p).name ~= "mcl_chests:"..basename.."_right" then
150 return
152 minetest.swap_node(p, { name = "mcl_chests:"..basename, param2 = param2 })
153 end,
154 after_dig_node = function(pos, oldnode, oldmetadata, digger)
155 local meta = minetest.get_meta(pos)
156 local meta2 = meta
157 meta:from_table(oldmetadata)
158 local inv = meta:get_inventory()
159 for i=1,inv:get_size("main") do
160 local stack = inv:get_stack("main", i)
161 if not stack:is_empty() then
162 local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
163 minetest.add_item(p, stack)
166 meta:from_table(meta2:to_table())
167 end,
168 -- BEGIN OF LISTRING WORKAROUND
169 allow_metadata_inventory_put = function(pos, listname, index, stack, player)
170 if listname == "input" then
171 local inv = minetest.get_inventory({type="node", pos=pos})
172 if inv:room_for_item("main", stack) then
173 return -1
174 else
175 local other_pos = mcl_util.get_double_container_neighbor_pos(pos, minetest.get_node(pos).param2, "left")
176 local other_inv = minetest.get_inventory({type="node", pos=other_pos})
177 if other_inv:room_for_item("main", stack) then
178 return -1
179 else
180 return 0
183 else
184 return stack:get_count()
186 end,
187 -- END OF LISTRING WORKAROUND
188 on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
189 minetest.log("action", player:get_player_name()..
190 " moves stuff in chest at "..minetest.pos_to_string(pos))
191 end,
192 on_metadata_inventory_put = function(pos, listname, index, stack, player)
193 minetest.log("action", player:get_player_name()..
194 " moves stuff to chest at "..minetest.pos_to_string(pos))
195 -- BEGIN OF LISTRING WORKAROUND
196 if listname == "input" then
197 local inv = minetest.get_inventory({type="node", pos=pos})
198 local leftover = inv:add_item("main", stack)
199 if not leftover:is_empty() then
200 local other_pos = mcl_util.get_double_container_neighbor_pos(pos, minetest.get_node(pos).param2, "left")
201 local other_inv = minetest.get_inventory({type="node", pos=other_pos})
202 other_inv:add_item("main", leftover)
205 -- END OF LISTRING WORKAROUND
206 end,
207 on_metadata_inventory_take = function(pos, listname, index, stack, player)
208 minetest.log("action", player:get_player_name()..
209 " takes stuff from chest at "..minetest.pos_to_string(pos))
210 end,
211 _mcl_blast_resistance = 2.5,
212 _mcl_hardness = 2.5,
214 on_rightclick = function(pos, node, clicker)
215 local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
217 minetest.show_formspec(clicker:get_player_name(),
218 "mcl_chests:"..formspec_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z,
219 "size[9,11.5]"..
220 "background[-0.19,-0.25;9.41,12.5;mcl_chests_inventory_chest_large.png]"..
221 mcl_vars.inventory_header..
222 "list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]"..
223 "list[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main;0,3.5;9,3;]"..
224 "list[current_player;main;0,7.5;9,3;9]"..
225 "list[current_player;main;0,10.75;9,1;]"..
226 -- BEGIN OF LISTRING WORKAROUND
227 "listring[current_player;main]"..
228 "listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";input]"..
229 -- END OF LISTRING WORKAROUND
230 "listring[current_player;main]"..
231 "listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main]"..
232 "listring[current_player;main]"..
233 "listring[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main]")
235 if on_rightclick_addendum_left then
236 on_rightclick_addendum_left(pos, node, clicker)
238 end,
239 mesecons = mesecons,
240 on_rotate = no_rotate,
243 minetest.register_node("mcl_chests:"..basename.."_right", {
244 tiles = tiles_table.right,
245 paramtype2 = "facedir",
246 groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1},
247 drop = drop,
248 is_ground_content = false,
249 sounds = mcl_sounds.node_sound_wood_defaults(),
250 on_destruct = function(pos)
251 local n = minetest.get_node(pos)
252 if n.name == "mcl_chests:"..basename then
253 return
256 local players = minetest.get_connected_players()
257 for p=1, #players do
258 minetest.close_formspec(players[p]:get_player_name(), "mcl_chests:"..formspec_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z)
261 local param2 = n.param2
262 local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right")
263 if not p or minetest.get_node(p).name ~= "mcl_chests:"..basename.."_left" then
264 return
266 minetest.swap_node(p, { name = "mcl_chests:"..basename, param2 = param2 })
267 end,
268 after_dig_node = function(pos, oldnode, oldmetadata, digger)
269 local meta = minetest.get_meta(pos)
270 local meta2 = meta
271 meta:from_table(oldmetadata)
272 local inv = meta:get_inventory()
273 for i=1,inv:get_size("main") do
274 local stack = inv:get_stack("main", i)
275 if not stack:is_empty() then
276 local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
277 minetest.add_item(p, stack)
280 meta:from_table(meta2:to_table())
281 end,
282 -- BEGIN OF LISTRING WORKAROUND
283 allow_metadata_inventory_put = function(pos, listname, index, stack, player)
284 if listname == "input" then
285 local other_pos = mcl_util.get_double_container_neighbor_pos(pos, minetest.get_node(pos).param2, "right")
286 local other_inv = minetest.get_inventory({type="node", pos=other_pos})
287 if other_inv:room_for_item("main", stack) then
288 return -1
289 else
290 local inv = minetest.get_inventory({type="node", pos=pos})
291 if inv:room_for_item("main", stack) then
292 return -1
293 else
294 return 0
297 else
298 return stack:get_count()
300 end,
301 -- END OF LISTRING WORKAROUND
302 on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
303 minetest.log("action", player:get_player_name()..
304 " moves stuff in chest at "..minetest.pos_to_string(pos))
305 end,
306 on_metadata_inventory_put = function(pos, listname, index, stack, player)
307 minetest.log("action", player:get_player_name()..
308 " moves stuff to chest at "..minetest.pos_to_string(pos))
309 -- BEGIN OF LISTRING WORKAROUND
310 if listname == "input" then
311 local other_pos = mcl_util.get_double_container_neighbor_pos(pos, minetest.get_node(pos).param2, "right")
312 local other_inv = minetest.get_inventory({type="node", pos=other_pos})
313 local leftover = other_inv:add_item("main", stack)
314 if not leftover:is_empty() then
315 local inv = minetest.get_inventory({type="node", pos=pos})
316 inv:add_item("main", leftover)
319 -- END OF LISTRING WORKAROUND
320 end,
321 on_metadata_inventory_take = function(pos, listname, index, stack, player)
322 minetest.log("action", player:get_player_name()..
323 " takes stuff from chest at "..minetest.pos_to_string(pos))
324 end,
325 _mcl_blast_resistance = 2.5,
326 _mcl_hardness = 2.5,
328 on_rightclick = function(pos, node, clicker)
329 local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
331 minetest.show_formspec(clicker:get_player_name(),
332 "mcl_chests:"..formspec_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z,
334 "size[9,11.5]"..
335 "background[-0.19,-0.25;9.41,12.5;mcl_chests_inventory_chest_large.png]"..
336 mcl_vars.inventory_header..
337 "list[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main;0,0.5;9,3;]"..
338 "list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,3.5;9,3;]"..
339 "list[current_player;main;0,7.5;9,3;9]"..
340 "list[current_player;main;0,10.75;9,1;]"..
341 -- BEGIN OF LISTRING WORKAROUND
342 "listring[current_player;main]"..
343 "listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";input]"..
344 -- END OF LISTRING WORKAROUND
345 "listring[current_player;main]"..
346 "listring[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main]"..
347 "listring[current_player;main]"..
348 "listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main]")
350 if on_rightclick_addendum_right then
351 on_rightclick_addendum_right(pos, node, clicker)
353 end,
354 mesecons = mesecons,
355 on_rotate = no_rotate,
358 if minetest.get_modpath("doc") then
359 doc.add_entry_alias("nodes", "mcl_chests:"..basename, "nodes", "mcl_chests:"..basename.."_left")
360 doc.add_entry_alias("nodes", "mcl_chests:"..basename, "nodes", "mcl_chests:"..basename.."_right")
365 register_chest("chest",
366 "Chest",
367 "Chests are containers which provide 27 inventory slots. Chests can be turned into large chests with double the capacity by placing two chests next to each other.",
368 "To acccess the inventory of a chest or large chest, rightclick it. When broken, the items of the chest will drop out.",
370 small = {"default_chest_top.png", "mcl_chests_chest_bottom.png",
371 "mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
372 "mcl_chests_chest_back.png", "default_chest_front.png"},
373 left = {"default_chest_top_big.png", "default_chest_top_big.png",
374 "mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
375 "default_chest_side_big.png^[transformFX", "default_chest_front_big.png"},
376 right = {"default_chest_top_big.png^[transformFX", "default_chest_top_big.png^[transformFX",
377 "mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
378 "default_chest_side_big.png", "default_chest_front_big.png^[transformFX"},
380 false
383 local trapped_chest_mesecons_rules = mesecon.rules.pplate
385 local traptiles = {
386 small = {"mcl_chests_chest_trapped_top.png", "mcl_chests_chest_trapped_bottom.png",
387 "mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
388 "mcl_chests_chest_trapped_back.png", "mcl_chests_chest_trapped_front.png"},
389 left = {"mcl_chests_chest_trapped_top_big.png", "mcl_chests_chest_trapped_top_big.png",
390 "mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
391 "mcl_chests_chest_trapped_side_big.png^[transformFX", "mcl_chests_chest_trapped_front_big.png"},
392 right = {"mcl_chests_chest_trapped_top_big.png^[transformFX", "mcl_chests_chest_trapped_top_big.png^[transformFX",
393 "mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
394 "mcl_chests_chest_trapped_side_big.png", "mcl_chests_chest_trapped_front_big.png^[transformFX"},
397 register_chest("trapped_chest",
398 "Trapped Chest",
399 "A trapped chest is a container which provides 27 inventory slots. It looks identical to a regular chest, but when it is opened, it sends a redstone signal to its adjacent blocks. Trapped chests can be turned into large trapped chests with double the capacity by placing two trapped chests next to each other.",
400 "To acccess the inventory of a trapped chest or a large trapped chest, rightclick it. When broken, the items will drop out.",
401 traptiles,
402 nil,
403 {receptor = {
404 state = mesecon.state.off,
405 rules = trapped_chest_mesecons_rules,
407 function(pos, node, clicker)
408 local meta = minetest.get_meta(pos)
409 meta:set_int("players", 1)
410 minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on", param2 = node.param2})
411 mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
412 end,
413 function(pos, node, clicker)
414 local meta = minetest.get_meta(pos)
415 meta:set_int("players", 1)
417 minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on_left", param2 = node.param2})
418 mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
420 local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
421 minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_on_right", param2 = node.param2})
422 mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules)
423 end,
424 function(pos, node, clicker)
425 local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
427 -- Save number of players in left part of the chest only
428 local meta = minetest.get_meta(pos_other)
429 meta:set_int("players", 1)
431 minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on_right", param2 = node.param2})
432 mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
434 minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_on_left", param2 = node.param2})
435 mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules)
439 register_chest("trapped_chest_on",
440 nil, nil, nil, traptiles, true,
441 {receptor = {
442 state = mesecon.state.on,
443 rules = trapped_chest_mesecons_rules,
445 function(pos, node, clicker)
446 local meta = minetest.get_meta(pos)
447 local players = meta:get_int("players")
448 players = players + 1
449 meta:set_int("players", players)
450 end,
451 function(pos, node, clicker)
452 local meta = minetest.get_meta(pos)
453 local players = meta:get_int("players")
454 players = players + 1
455 meta:set_int("players", players)
456 end,
457 function(pos, node, clicker)
458 local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
459 local meta = minetest.get_meta(pos_other)
460 local players = meta:get_int("players")
461 players = players + 1
462 meta:set_int("players", players)
463 end,
464 "trapped_chest",
465 "trapped_chest"
468 -- Disable trapped chest when it has been closed
469 minetest.register_on_player_receive_fields(function(player, formname, fields)
470 if formname:find("mcl_chests:trapped_chest_") == 1 then
471 if fields.quit then
472 local x, y, z = formname:match("mcl_chests:trapped_chest_(.-)_(.-)_(.*)")
473 local pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)}
474 if not pos or not pos.x or not pos.y or not pos.z then return end
475 local node = minetest.get_node(pos)
476 local meta, players, pos_other
477 if node.name == "mcl_chests:trapped_chest_on" or node.name == "mcl_chests:trapped_chest_on_left" then
478 meta = minetest.get_meta(pos)
479 players = meta:get_int("players")
480 players = players - 1
481 elseif node.name == "mcl_chests:trapped_chest_on_right" then
482 pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
483 meta = minetest.get_meta(pos_other)
484 players = meta:get_int("players")
485 players = players - 1
488 if node.name == "mcl_chests:trapped_chest_on" then
489 if players <= 0 then
490 meta:set_int("players", 0)
491 minetest.swap_node(pos, {name="mcl_chests:trapped_chest", param2 = node.param2})
492 mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
493 else
494 meta:set_int("players", players)
496 elseif node.name == "mcl_chests:trapped_chest_on_left" then
497 if players <= 0 then
498 meta:set_int("players", 0)
499 minetest.swap_node(pos, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
500 mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
502 pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
503 minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_right", param2 = node.param2})
504 mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules)
505 else
506 meta:set_int("players", players)
508 elseif node.name == "mcl_chests:trapped_chest_on_right" then
509 if players <= 0 then
510 meta:set_int("players", 0)
511 minetest.swap_node(pos, {name="mcl_chests:trapped_chest_right", param2 = node.param2})
512 mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
514 minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
515 mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules)
516 else
517 meta:set_int("players", players)
522 end)
524 minetest.register_craft({
525 output = 'mcl_chests:chest',
526 recipe = {
527 {'group:wood', 'group:wood', 'group:wood'},
528 {'group:wood', '', 'group:wood'},
529 {'group:wood', 'group:wood', 'group:wood'},
533 minetest.register_craft({
534 type = 'fuel',
535 recipe = 'mcl_chests:chest',
536 burntime = 15
539 minetest.register_craft({
540 type = 'fuel',
541 recipe = 'mcl_chests:trapped_chest',
542 burntime = 15
545 minetest.register_node("mcl_chests:ender_chest", {
546 description = "Ender Chest",
547 _doc_items_longdesc = "Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests worldwide. Each player will only see their own items, but not the items of other players.",
548 _doc_items_usagehelp = "Rightclick the ender chest to access your personal interdimensional inventory.",
549 tiles = {"mcl_chests_ender_chest_top.png", "mcl_chests_ender_chest_bottom.png",
550 "mcl_chests_ender_chest_right.png", "mcl_chests_ender_chest_left.png",
551 "mcl_chests_ender_chest_back.png", "mcl_chests_ender_chest_front.png"},
552 -- Note: The “container” group is missing here because the ender chest does not
553 -- have an inventory on its own
554 groups = {pickaxey=1, deco_block=1, material_stone=1},
555 is_ground_content = false,
556 paramtype = "light",
557 light_source = 7,
558 paramtype2 = "facedir",
559 sounds = mcl_sounds.node_sound_stone_defaults(),
560 drop = "mcl_core:obsidian 8",
561 on_construct = function(pos)
562 local meta = minetest.get_meta(pos)
563 meta:set_string("formspec",
564 "size[9,8.75]"..
565 mcl_vars.inventory_header..
566 "background[-0.19,-0.25;9.41,10.48;mcl_chests_inventory_chest.png]"..
567 "image[0,-0.2;5,0.75;mcl_chests_fnt_ender_chest.png]"..
568 "list[current_player;enderchest;0,0.5;9,3;]"..
569 "list[current_player;main;0,4.5;9,3;9]"..
570 "list[current_player;main;0,7.74;9,1;]"..
571 "listring[current_player;enderchest]"..
572 "listring[current_player;main]")
573 end,
574 _mcl_blast_resistance = 3000,
575 _mcl_hardness = 22.5,
576 on_rotate = simple_rotate,
579 minetest.register_on_joinplayer(function(player)
580 local inv = player:get_inventory()
581 inv:set_size("enderchest", 9*3)
582 end)
584 minetest.register_craft({
585 output = 'mcl_chests:ender_chest',
586 recipe = {
587 {'mcl_core:obsidian', 'mcl_core:obsidian', 'mcl_core:obsidian'},
588 {'mcl_core:obsidian', 'mcl_end:ender_eye', 'mcl_core:obsidian'},
589 {'mcl_core:obsidian', 'mcl_core:obsidian', 'mcl_core:obsidian'},
593 -- Shulker boxes
594 local boxtypes = {
595 white = "White Shulker Box",
596 grey = "Light Grey Shulker Box",
597 orange = "Orange Shulker Box",
598 cyan = "Cyan Shulker Box",
599 magenta = "Magenta Shulker Box",
600 violet = "Purple Shulker Box",
601 lightblue = "Light Blue Shulker Box",
602 blue = "Blue Shulker Box",
603 yellow = "Yellow Shulker Box",
604 brown = "Brown Shulker Box",
605 green = "Lime Shulker Box",
606 dark_green = "Green Shulker Box",
607 pink = "Pink Shulker Box",
608 red = "Red Shulker Box",
609 dark_grey = "Grey Shulker Box",
610 black = "Black Shulker Box",
613 local shulker_mob_textures = {
614 white = "mobs_mc_shulker_white.png",
615 grey = "mobs_mc_shulker_silver.png",
616 orange = "mobs_mc_shulker_orange.png",
617 cyan = "mobs_mc_shulker_cyan.png",
618 magenta = "mobs_mc_shulker_magenta.png",
619 violet = "mobs_mc_shulker_purple.png",
620 lightblue = "mobs_mc_shulker_light_blue.png",
621 blue = "mobs_mc_shulker_blue.png",
622 yellow = "mobs_mc_shulker_yellow.png",
623 brown = "mobs_mc_shulker_brown.png",
624 green = "mobs_mc_shulker_lime.png",
625 dark_green = "mobs_mc_shulker_green.png",
626 pink = "mobs_mc_shulker_pink.png",
627 red = "mobs_mc_shulker_red.png",
628 dark_grey = "mobs_mc_shulker_gray.png",
629 black = "mobs_mc_shulker_black.png",
632 for color, desc in pairs(boxtypes) do
633 local mob_texture = shulker_mob_textures[color]
634 minetest.register_node("mcl_chests:"..color.."_shulker_box", {
635 description = desc,
636 _doc_items_longdesc = "A shulker box is a portable container which provides 27 inventory slots for any item except shulker boxes. Shulker boxes keep their inventory when broken, so shulker boxes as well as their contents can be taken as a single item. Shulker boxes come in many different colors.",
637 _doc_items_usagehelp = "To access the inventory of a shulker box, place and right-click it. To take a shulker box and its contents with you, just break and collect it, the items will not fall out. Place the shulker box again to be able to retrieve its contents.",
638 tiles = {
639 "mcl_chests_"..color.."_shulker_box_top.png", -- top
640 "[combine:16x16:-32,-28="..mob_texture, -- bottom
641 "[combine:16x16:0,-36="..mob_texture..":0,-16="..mob_texture, -- side
642 "[combine:16x16:-32,-36="..mob_texture..":-32,-16="..mob_texture, -- side
643 "[combine:16x16:-16,-36="..mob_texture..":-16,-16="..mob_texture, -- side
644 "[combine:16x16:-48,-36="..mob_texture..":-48,-16="..mob_texture, -- side
646 groups = {handy=1,pickaxey=1, container=3, deco_block=1, dig_by_piston=1, shulker_box=1},
647 is_ground_content = false,
648 sounds = mcl_sounds.node_sound_stone_defaults(),
649 stack_max = 1,
650 drop = "",
651 paramtype = "light",
652 sunlight_propagates = true,
653 paramtype2 = "facedir",
654 -- TODO: Make shulker boxes rotatable
655 -- This doesn't work, it just destroys the inventory:
656 -- on_place = minetest.rotate_node,
657 on_construct = function(pos)
658 local meta = minetest.get_meta(pos)
659 meta:set_string("formspec",
660 "size[9,8.75]"..
661 mcl_vars.inventory_header..
662 "background[-0.19,-0.25;9.41,10.48;mcl_chests_inventory_chest.png]"..
663 "image[0,-0.2;5,0.75;mcl_chests_fnt_shulker_box.png]"..
664 "list[current_name;main;0,0.5;9,3;]"..
665 "list[current_player;main;0,4.5;9,3;9]"..
666 "list[current_player;main;0,7.74;9,1;]"..
667 "listring[current_name;main]"..
668 "listring[current_player;main]")
669 local inv = meta:get_inventory()
670 inv:set_size("main", 9*3)
671 end,
672 after_place_node = function(pos, placer, itemstack, pointed_thing)
673 local nmeta = minetest.get_meta(pos)
674 local ninv = nmeta:get_inventory()
675 local imeta = itemstack:get_metadata()
676 local iinv_main = minetest.deserialize(imeta)
677 ninv:set_list("main", iinv_main)
678 ninv:set_size("main", 9*3)
679 if minetest.settings:get_bool("creative_mode") then
680 if not ninv:is_empty("main") then
681 return nil
682 else
683 return itemstack
685 else
686 return nil
688 end,
689 on_destruct = function(pos)
690 local meta = minetest.get_meta(pos)
691 local inv = meta:get_inventory()
692 local items = {}
693 for i=1, inv:get_size("main") do
694 local stack = inv:get_stack("main", i)
695 items[i] = stack:to_string()
697 local data = minetest.serialize(items)
698 local boxitem = ItemStack("mcl_chests:"..color.."_shulker_box")
699 boxitem:set_metadata(data)
701 if minetest.settings:get_bool("creative_mode") then
702 if not inv:is_empty("main") then
703 minetest.add_item(pos, boxitem)
705 else
706 minetest.add_item(pos, boxitem)
708 end,
709 allow_metadata_inventory_put = function(pos, listname, index, stack, player)
710 -- Do not allow to place shulker boxes into shulker boxes
711 local group = minetest.get_item_group(stack:get_name(), "shulker_box")
712 if group == 0 or group == nil then
713 return stack:get_count()
714 else
715 return 0
717 end,
718 _mcl_blast_resistance = 30,
719 _mcl_hardness = 6,
722 minetest.register_craft({
723 type = "shapeless",
724 output = 'mcl_chests:'..color..'_shulker_box',
725 recipe = { 'group:shulker_box', 'mcl_dye:'..color }
729 minetest.register_craft({
730 output = 'mcl_chests:violet_shulker_box',
731 recipe = {
732 {'mcl_mobitems:shulker_shell'},
733 {'mcl_chests:chest'},
734 {'mcl_mobitems:shulker_shell'},