VoxeLibre/mods/ITEMS/mcl_chests/shulkers.lua
seventeenthShulker 0408f9c3d8 Update hardness and blast res for value not matching the wiki
- Notably, smooth sandstone (and red) is much more durable than other sandstone variants
- Ender chest isn't actually more explosion resistant than obsidian, hmm
2024-08-18 04:47:12 +02:00

358 lines
11 KiB
Lua

local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
local C = minetest.colorize
-- Shulker boxes
local boxtypes = {
white = S("White Shulker Box"),
grey = S("Light Grey Shulker Box"),
orange = S("Orange Shulker Box"),
cyan = S("Cyan Shulker Box"),
magenta = S("Magenta Shulker Box"),
violet = S("Purple Shulker Box"),
lightblue = S("Light Blue Shulker Box"),
blue = S("Blue Shulker Box"),
yellow = S("Yellow Shulker Box"),
brown = S("Brown Shulker Box"),
green = S("Lime Shulker Box"),
dark_green = S("Green Shulker Box"),
pink = S("Pink Shulker Box"),
red = S("Red Shulker Box"),
dark_grey = S("Grey Shulker Box"),
black = S("Black Shulker Box"),
}
local shulker_mob_textures = {
white = "mobs_mc_shulker_white.png",
grey = "mobs_mc_shulker_silver.png",
orange = "mobs_mc_shulker_orange.png",
cyan = "mobs_mc_shulker_cyan.png",
magenta = "mobs_mc_shulker_magenta.png",
violet = "mobs_mc_shulker_purple.png",
lightblue = "mobs_mc_shulker_light_blue.png",
blue = "mobs_mc_shulker_blue.png",
yellow = "mobs_mc_shulker_yellow.png",
brown = "mobs_mc_shulker_brown.png",
green = "mobs_mc_shulker_lime.png",
dark_green = "mobs_mc_shulker_green.png",
pink = "mobs_mc_shulker_pink.png",
red = "mobs_mc_shulker_red.png",
dark_grey = "mobs_mc_shulker_gray.png",
black = "mobs_mc_shulker_black.png",
}
local canonical_shulker_color = "violet"
local normal_canonical_name = "mcl_chests:" .. canonical_shulker_color .. "_shulker_box"
local small_canonical_name = normal_canonical_name .. "_small"
--WARNING: after formspec v4 update, old shulker boxes will need to be placed again to get the new formspec
local function formspec_shulker_box(name)
if not name or name == "" then
name = S("Shulker Box")
end
return table.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),
"list[context;main;0.375,0.75;9,3;]",
"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[context;main]",
"listring[current_player;main]",
})
end
local function set_shulkerbox_meta(nmeta, imeta)
local name = imeta:get_string("name")
nmeta:set_string("description", imeta:get_string("description"))
nmeta:set_string("name", name)
nmeta:set_string("formspec", formspec_shulker_box(name))
end
for color, desc in pairs(boxtypes) do
local mob_texture = shulker_mob_textures[color]
local is_canonical = color == canonical_shulker_color
local longdesc, usagehelp, create_entry, entry_name
if doc then
if is_canonical then
longdesc = S(
"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."
)
usagehelp = S(
"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."
)
entry_name = S("Shulker Box")
else
create_entry = false
end
end
local normal_name = "mcl_chests:" .. color .. "_shulker_box"
local small_name = normal_name .. "_small"
minetest.register_node(normal_name, {
description = desc,
_tt_help = S("27 inventory slots") .. "\n" .. S("Can be carried around with its contents"),
_doc_items_create_entry = create_entry,
_doc_items_entry_name = entry_name,
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp,
tiles = { mob_texture },
use_texture_alpha = "opaque",
drawtype = "mesh",
mesh = "mcl_chests_shulker.b3d",
groups = {
handy = 1,
pickaxey = 1,
container = 2,
deco_block = 1,
dig_by_piston = 1,
shulker_box = 1,
old_shulker_box_node = 1
},
is_ground_content = false,
sounds = mcl_sounds.node_sound_stone_defaults(),
stack_max = 1,
drop = "",
paramtype = "light",
paramtype2 = "facedir",
on_construct = function(pos)
local node = minetest.get_node(pos)
node.name = small_name
minetest.set_node(pos, node)
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
local nmeta = minetest.get_meta(pos)
local imeta = itemstack:get_meta()
-- Convert old itemstacks to not use get_metadata()
if not imeta:contains("inv") and
(itemstack:get_metadata() ~= "") then
imeta:set_string("inv", itemstack:get_metadata())
itemstack:set_metadata("") -- clear
end
local iinv_main = minetest.deserialize(imeta:get_string("inv"))
local ninv = nmeta:get_inventory()
ninv:set_list("main", iinv_main)
ninv:set_size("main", 9 * 3)
set_shulkerbox_meta(nmeta, imeta)
if minetest.is_creative_enabled(placer:get_player_name()) then
if not ninv:is_empty("main") then
return nil
else
return itemstack
end
else
return nil
end
end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
-- Place shulker box as node
if minetest.registered_nodes[dropnode.name].buildable_to then
minetest.set_node(droppos, { name = small_name, param2 = minetest.dir_to_facedir(dropdir) })
local ninv = minetest.get_inventory({ type = "node", pos = droppos })
local imeta = stack:get_meta()
local iinv_main = minetest.deserialize(imeta:get_string("inv"))
ninv:set_list("main", iinv_main)
ninv:set_size("main", 9 * 3)
set_shulkerbox_meta(minetest.get_meta(droppos), imeta)
stack:take_item()
end
return stack
end,
})
minetest.register_node(small_name, {
description = desc,
_tt_help = S("27 inventory slots") .. "\n" .. S("Can be carried around with its contents"),
_doc_items_create_entry = create_entry,
_doc_items_entry_name = entry_name,
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = { -0.48, -0.5, -0.48, 0.48, 0.489, 0.48 },
},
tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = "clip",
_chest_entity_textures = { mob_texture },
_chest_entity_sound = "mcl_chests_shulker",
_chest_entity_mesh = "mcl_chests_shulker",
_chest_entity_animation_type = "shulker",
groups = {
handy = 1,
pickaxey = 1,
container = 2,
deco_block = 1,
dig_by_piston = 1,
shulker_box = 1,
chest_entity = 1,
not_in_creative_inventory = 1
},
is_ground_content = false,
sounds = mcl_sounds.node_sound_stone_defaults(),
stack_max = 1,
drop = "",
paramtype = "light",
paramtype2 = "facedir",
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", formspec_shulker_box(nil))
local inv = meta:get_inventory()
inv:set_size("main", 9 * 3)
mcl_chests.create_entity(pos, small_name, { mob_texture }, minetest.get_node(pos).param2, false,
"mcl_chests_shulker", "mcl_chests_shulker", "shulker")
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
local nmeta = minetest.get_meta(pos)
local imeta = itemstack:get_meta()
-- Convert old itemstacks to not use get_metadata()
if not imeta:contains("inv") and
(itemstack:get_metadata() ~= "") then
imeta:set_string("inv", itemstack:get_metadata())
itemstack:set_metadata("") -- clear
end
local iinv_main = minetest.deserialize(imeta:get_string("inv"))
local ninv = nmeta:get_inventory()
ninv:set_list("main", iinv_main)
ninv:set_size("main", 9 * 3)
set_shulkerbox_meta(nmeta, imeta)
if minetest.is_creative_enabled(placer:get_player_name()) then
if not ninv:is_empty("main") then
return nil
else
return itemstack
end
else
return nil
end
end,
on_rightclick = function(pos, node, clicker)
mcl_chests.player_chest_open(clicker, pos, small_name, { mob_texture }, node.param2, false,
"mcl_chests_shulker", "mcl_chests_shulker", true)
end,
on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then
mcl_chests.player_chest_close(sender)
end
end,
on_destruct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local items = {}
for i = 1, inv:get_size("main") do
local stack = inv:get_stack("main", i)
items[i] = stack:to_string()
end
local data = minetest.serialize(items)
local boxitem = ItemStack("mcl_chests:" .. color .. "_shulker_box")
local boxitem_meta = boxitem:get_meta()
boxitem_meta:set_string("description", meta:get_string("description"))
boxitem_meta:set_string("name", meta:get_string("name"))
boxitem_meta:set_string("inv", data)
if minetest.is_creative_enabled("") then
if not inv:is_empty("main") then
minetest.add_item(pos, boxitem)
end
else
minetest.add_item(pos, boxitem)
end
end,
allow_metadata_inventory_move = mcl_chests.protection_check_move,
allow_metadata_inventory_take = mcl_chests.protection_check_put_take,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local name = player:get_player_name()
if minetest.is_protected(pos, name) then
minetest.record_protection_violation(pos, name)
return 0
end
-- Do not allow to place shulker boxes into shulker boxes
local group = minetest.get_item_group(stack:get_name(), "shulker_box")
if group == 0 or group == nil then
return stack:get_count()
else
return 0
end
end,
on_rotate = mcl_chests.simple_rotate,
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv, "main",
mcl_util.select_stack(hop_inv, hop_list, inv, "main", mcl_chests.is_not_shulker_box, 1)
end,
})
if doc and not is_canonical then
doc.add_entry_alias("nodes", normal_canonical_name, "nodes", normal_name)
doc.add_entry_alias("nodes", small_canonical_name, "nodes", small_name)
end
minetest.register_craft({
type = "shapeless",
output = normal_name,
recipe = { "group:shulker_box", "mcl_dye:" .. color },
})
end
minetest.register_craft({
output = "mcl_chests:violet_shulker_box",
recipe = {
{ "mcl_mobitems:shulker_shell" },
{ "mcl_chests:chest" },
{ "mcl_mobitems:shulker_shell" },
},
})
-- Save metadata of shulker box when used in crafting
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
if minetest.get_item_group(itemstack:get_name(), "shulker_box") ~= 1 then return end
local original
for i = 1, #old_craft_grid do
local item = old_craft_grid[i]:get_name()
if minetest.get_item_group(item, "shulker_box") == 1 then
original = old_craft_grid[i]
break
end
end
if original then
local ometa = original:get_meta():to_table()
local nmeta = itemstack:get_meta()
nmeta:from_table(ometa)
return itemstack
end
end)
minetest.register_lbm({
label = "Update shulker box formspecs (0.72.0)",
name = "mcl_chests:update_shulker_box_formspecs_0_72_0",
nodenames = { "group:shulker_box" },
run_at_every_load = false,
action = function(pos, node)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", formspec_shulker_box(meta:get_string("name")))
end,
})