Epic/mods/mesebox/init.lua

434 lines
12 KiB
Lua

-- Mesebox
local mesebox = {}
mesebox.open_meseboxs = {}
mesebox.variants = {
white = "White Mesebox",
black = "Black Mesebox",
red = "Red Mesebox",
blue = "Blue Mesebox",
green = "Green Mesebox",
yellow = "Yellow Mesebox",
orange = "Orange Mesebox",
violet = "Violet Mesebox",
}
local pipeworks_enabled = minetest.get_modpath("pipeworks") ~= nil
function mesebox.get_mesebox_formspec(pos)
local meta = minetest.get_meta(pos)
local spos = pos.x .. "," .. pos.y .. "," .. pos.z
local alias = meta:get_string("alias") and meta:get_string("alias") or meta:get_string("description")
local formspec = "size[8,8.5]" ..
"field[0.3,0.1;4,1;alias;;" .. alias .. "]"..
"button_exit[4,-0.2;2,1;save;Update Name]"..
"list[nodemeta:" .. spos .. ";main;0,0.8;8,3;]" ..
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#fff", "Inventory")).."]"..
"list[current_player;main;0,4.5;8,1;]"..
default.get_hotbar_bg(0,4.5,8,1)..
"list[current_player;main;0,5.7;8,3;8]"..
default.get_hotbar_bg(0,5.7,8,3)..
"listring[nodemeta:" .. spos .. ";main]" ..
"listring[current_player;main]"
return formspec
end
function mesebox.mesebox_lid_close(pn)
local mesebox_open_info = mesebox.open_meseboxs[pn]
local pos = mesebox_open_info.pos
local sound = mesebox_open_info.sound
local swap = mesebox_open_info.swap
mesebox.open_meseboxs[pn] = nil
for k, v in pairs(mesebox.open_meseboxs) do
if v.pos.x == pos.x and v.pos.y == pos.y and v.pos.z == pos.z then
return true
end
end
local node = minetest.get_node(pos)
minetest.after(0.2, minetest.swap_node, pos, { name = swap,
param2 = node.param2 })
minetest.sound_play(sound, {gain = 0.3, pos = pos,
max_hear_distance = 10}, true)
end
function mesebox.can_open(pos)
local dirs = {}
dirs.n = {x = pos.x, y = pos.y, z = pos.z+1}
dirs.s = {x = pos.x, y = pos.y, z = pos.z-1}
dirs.w = {x = pos.x-1, y = pos.y, z = pos.z}
dirs.e = {x = pos.x+1, y = pos.y, z = pos.z}
local blocked = 0
for _,dir in pairs(dirs) do
local def = minetest.registered_nodes[minetest.get_node(dir).name]
-- allow ladders, signs, wallmounted things and torches to not obstruct
if def and (def.drawtype == "airlike" or
def.drawtype == "signlike" or
def.drawtype == "torchlike" or
(def.drawtype == "nodebox" and def.paramtype2 == "wallmounted")) then
else
blocked = blocked +1
end
end
return blocked < 4
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "mesebox:mesebox" then
return
end
if not player or not fields.quit then
return
end
local pn = player:get_player_name()
if not mesebox.open_meseboxs[pn] then
return
end
if fields.alias and fields.alias ~= "" then
local mesebox_open_info = mesebox.open_meseboxs[pn]
local pos = mesebox_open_info.pos
local meta = minetest.get_meta(pos)
meta:set_string("alias", fields.alias)
mesebox.update_ratio(meta)
mesebox.update_infotext(meta)
end
mesebox.mesebox_lid_close(pn)
return true
end)
minetest.register_on_leaveplayer(function(player)
local pn = player:get_player_name()
if mesebox.open_meseboxs[pn] then
mesebox.mesebox_lid_close(pn)
end
end)
function mesebox.update_ratio(meta)
-- update ratio
local inv = meta:get_inventory()
local size = 24
local count = 0
for i = 1, size do
if not inv:get_stack("main", i):is_empty() then count = count + 1 end
end
meta:set_string("ratio", "["..count.."/"..size.."]")
end
function mesebox.update_infotext(meta)
-- update infotext
meta:set_string("infotext", meta:get_string("alias") .. " " .. meta:get_string("ratio"))
end
function mesebox.register_mesebox(name, color, desc)
local def = {}
def.description = desc
def.paramtype = "light"
def.paramtype2 = "facedir"
def.is_ground_content = false
def.sunlight_propagates = false
def.groups = { choppy = 2, oddly_breakable_by_hand = 3, tubedevice = 1,
tubedevice_receiver = 1, mesebox = 1 }
def.sounds = default.node_sound_wood_defaults()
def.sound_open = "mesebox_open"
def.sound_close = "mesebox_close"
def.stack_max = 1
def.drop = ""
-- Called every time the item is placed in the world, before 'after_place_node'.
def.on_construct = function(pos)
-- Nothing to do here, everything is initialized in
-- 'after_place_node'
end
def.on_rightclick = function(pos, node, clicker)
-- XXX: The Scanner is currently blocking from opening so don't do this for now.
-- if not mesebox.can_open(pos) then
-- return
-- end
minetest.sound_play(def.sound_open, {gain = 0.5, pos = pos,
max_hear_distance = 10}, true)
minetest.swap_node(pos, { name = name .. "_open",
param2 = node.param2 })
minetest.after(0.2, minetest.show_formspec,
clicker:get_player_name(),
"mesebox:mesebox", mesebox.get_mesebox_formspec(pos))
mesebox.open_meseboxs[clicker:get_player_name()] = {
pos = pos, sound = def.sound_close, swap = name
}
end
def.on_blast = function(pos)
local drops = {}
mesebox.get_inventory_drops(pos, "main", drops)
drops[#drops+1] = name
minetest.remove_node(pos)
return drops
end
def.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
local group = minetest.get_item_group(stack:get_name(), "mesebox")
if group == 0 or group == nil then
return stack:get_count()
else
return 0
end
end
def.allow_metadata_inventory_take = 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
else
return 99
end
end
def.on_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos)
mesebox.update_ratio(meta)
mesebox.update_infotext(meta)
end
def.on_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos)
mesebox.update_ratio(meta)
mesebox.update_infotext(meta)
end
def.tube = {
insert_object = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:add_item("main", stack)
end,
can_insert = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if meta:get_int("splitstacks") == 1 then
stack = stack:peek_item(1)
end
return inv:room_for_item("main", stack)
end,
input_inventory = "main",
connect_sides = {left = 1, right = 1, front = 1, back = 1, bottom = 1, top = 1}
}
local def_opened = table.copy(def)
local def_closed = table.copy(def)
local pipes = ""
-- XXX: Was gonna use alternative textures for pipeworks but trying a single
-- more discrete design instead that indicates that pipes are supported.
-- if pipeworks_enabled then
-- pipes = "_pipes"
-- end
def_opened.tiles = {
-- top, bottom, side, side, side, side
color.."_mesebox_top"..pipes..".png",
color.."_mesebox_top"..pipes..".png",
color.."_mesebox_side_open.png",
color.."_mesebox_side_open.png",
color.."_mesebox_side_open.png",
color.."_mesebox_side_open.png",
}
def_closed.tiles = {
-- top, bottom, side, side, side, side
color.."_mesebox_top"..pipes..".png",
color.."_mesebox_top"..pipes..".png",
color.."_mesebox_side"..pipes..".png",
color.."_mesebox_side"..pipes..".png",
color.."_mesebox_side"..pipes..".png",
color.."_mesebox_side"..pipes..".png",
}
def_opened.drop = name
def_opened.groups.not_in_creative_inventory = 1
def_opened.groups.not_in_craft_guide = 1
def_opened.can_dig = function()
return false
end
def_opened.on_blast = function() end
def_closed.after_place_node = function(pos, placer, itemstack, pointed_thing)
local nmeta = minetest.get_meta(pos)
local ninv = nmeta:get_inventory()
local imeta = itemstack:get_meta()
-- Need to re-construct the Node's inventory each time it's placed.
ninv:set_size("main", 8*3)
local data_str = imeta:get_string("data")
if data_str == "" then
-- This Mesebox is placed for the first time, set valid defaults.
nmeta:set_string("alias", desc)
nmeta:set_string("ratio", "[0/24]")
else
local data = minetest.deserialize(data_str)
-- Move inventory from ItemStack to Node.
ninv:set_list("main", data.items)
-- Copy internal variables.
for k,v in pairs(data.fields) do
nmeta:set_string(k,v)
end
end
mesebox.update_infotext(nmeta)
if pipeworks_enabled then
pipeworks.after_place(pos)
end
if minetest.settings:get_bool("creative_mode") then
if not ninv:is_empty("main") then
return nil
else
return itemstack
end
else
return nil
end
end
def_closed.after_dig_node = function(pos, oldnode, oldmetatbl, digger)
-- NOTE: oldmeta is in table format
if not digger then
return
end
local inv = oldmetatbl.inventory.main
-- These can be nil if the mesebox we're picking up is an older version.
-- Default to reasonable values instead of crashing.
if not oldmetatbl.fields or not oldmetatbl.fields.ratio or not oldmetatbl.fields.alias then
oldmetatbl.fields = {
ratio = "",
alias = desc,
}
end
local ratio = oldmetatbl.fields.ratio
local alias = oldmetatbl.fields.alias
-- Move items from the Node to the ItemStack.
local items = {}
for i,v in ipairs(inv) do
items[i] = v:to_string()
end
-- Copy our internal state variables.
local fields = {}
for k,v in pairs(oldmetatbl.fields) do
fields[k] = v
end
local data = {
items = items,
fields = fields,
}
local istack = ItemStack("mesebox:"..color.."_mesebox")
local imeta = istack:get_meta()
imeta:set_string("description", alias.." "..ratio)
-- Serialize and store the Node's inventory and internal variables
-- in the ItemStack's metadata so it can be retrieved later when
-- it is again placed in the world.
imeta:set_string("data", minetest.serialize(data))
local dinv = digger:get_inventory()
if dinv:room_for_item("main", istack) then
dinv:add_item("main", istack)
else
minetest.add_item(pos, istack)
end
if pipeworks_enabled then
pipeworks.after_dig(pos)
end
end
minetest.register_node(name, def_closed)
minetest.register_node(name .. "_open", def_opened)
end
for color, desc in pairs(mesebox.variants) do
local name = "mesebox:" .. color .. "_mesebox"
mesebox.register_mesebox(name, color, desc)
minetest.register_craft({
type = "shapeless",
output = "mesebox:"..color.."_mesebox",
recipe = { "group:mesebox", "dye:"..color }
})
end
minetest.register_craft({
output = "mesebox:yellow_mesebox 1",
recipe = {
{ "default:mese", "furniture:lock", "default:mese" },
{ "group:wood", "default:mese", "group:wood" },
{ "default:mese", "furniture:hinge", "default:mese" },
}
})
hopper:add_container({
{"top", "group:mesebox", "main"},
{"bottom", "group:mesebox", "main"},
})
-- Keep inventory of mesebox when changing color by crafting
minetest.register_on_craft(
function(itemstack, player, old_craft_grid, craft_inv)
local new = itemstack:get_name()
if minetest.get_item_group(itemstack:get_name(), "mesebox") ~= 1 then
return
end
-- Search for an existing Mesebox in the crafting grid and store in 'old'.
local old
for i = 1, #old_craft_grid do
local item = old_craft_grid[i]:get_name()
if minetest.get_item_group(item, "mesebox") == 1 then
old = old_craft_grid[i]
break
end
end
if old then
-- Crafting Mesebox with dye
local ometa = old:get_meta()
local imeta = itemstack:get_meta()
local data = minetest.deserialize(ometa:get_string("data"))
if data then
-- Update name with name from new Mesebox and transfer table.
local new_desc = itemstack:get_description()
data.fields.alias = new_desc
ometa:set_string("data", minetest.serialize(data))
imeta:from_table(ometa:to_table())
imeta:set_string("description", new_desc.." "..data.fields.ratio)
else
-- No 'data' means this Mesebox has never been placed.
-- We set defaults in 'after_place_node' when the Mesebox is placed
-- into the world for the first time so leave as is here.
imeta:from_table(ometa:to_table())
end
else
-- Couldn't find existing Mesebox in the crafting grid which
-- means we're crafting a new one.
-- We set defaults in 'after_place_node' when the Mesebox is placed
-- into the world for the first time so leave as is here.
end
return itemstack
end
)