296 lines
9.5 KiB
Lua
296 lines
9.5 KiB
Lua
-- Item shelf for generic objects
|
|
-- Inventory overlay and blast code taken from vessels mod in MTG
|
|
-- All other code by Zorman2000
|
|
|
|
local function get_shelf_formspec(inv_size)
|
|
return "size[8,7]"..
|
|
default.gui_bg..
|
|
default.gui_bg_img..
|
|
default.gui_slots..
|
|
|
|
"list[context;main;"..(math.abs((inv_size / 2) - 8) / 2)..",0.25;"..(inv_size / 2)..",2;]"..
|
|
"list[current_player;main;0,2.75;8,1;]"..
|
|
"list[current_player;main;0,4;8,3;8]"..
|
|
"listring[context;main]"..
|
|
"listring[current_player;main]"
|
|
end
|
|
|
|
local temp_texture
|
|
local temp_size
|
|
|
|
local function get_obj_dir(param2)
|
|
return ((param2 + 1) % 4)
|
|
end
|
|
|
|
local function update_shelf(pos)
|
|
-- Remove all objects
|
|
local objs = minetest.get_objects_inside_radius(pos, 0.75)
|
|
for _,obj in pairs(objs) do
|
|
obj:remove()
|
|
end
|
|
|
|
local node = minetest.get_node(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
-- Calculate directions
|
|
local node_dir = minetest.facedir_to_dir(((node.param2 + 2) % 4))
|
|
local obj_dir = minetest.facedir_to_dir(get_obj_dir(node.param2))
|
|
-- Get maximum number of shown items (4 or 6)
|
|
local max_shown_items = minetest.get_item_group(node.name, "itemshelf_shown_items")
|
|
-- Get custom displacement properties
|
|
local depth_displacement = meta:get_float("itemshelf:depth_displacement")
|
|
local vertical_displacement = meta:get_float("itemshelf:vertical_displacement")
|
|
if depth_displacement == 0 then
|
|
depth_displacement = 0.25
|
|
end
|
|
if vertical_displacement == 0 then
|
|
vertical_displacement = 0.2375
|
|
end
|
|
minetest.log("displacements: "..dump(depth_displacement)..", "..dump(vertical_displacement))
|
|
-- Calculate the horizontal displacement. This one is hardcoded so that either 4 or 6
|
|
-- items are properly displayed.
|
|
local horizontal_displacement = 0.715
|
|
if max_shown_items == 6 then
|
|
horizontal_displacement = 0.555
|
|
end
|
|
|
|
-- Calculate initial position for entities
|
|
-- local start_pos = {
|
|
-- x=pos.x - (0.25 * obj_dir.x) - (node_dir.x * 0.25),
|
|
-- y=pos.y + 0.25,
|
|
-- z=pos.z - (0.25 * obj_dir.z) - (node_dir.z * 0.25)
|
|
-- }
|
|
-- How the below works: Following is a top view of a node
|
|
-- | +z (N) 0
|
|
-- |
|
|
-- ------------------------
|
|
-- | | |
|
|
-- | | |
|
|
-- | | |
|
|
-- -x (W) 3 | | (0,0) | +x (E) 1
|
|
-- -------------|-----------+----------|--------------
|
|
-- | | |
|
|
-- | | |
|
|
-- | | |
|
|
-- | | |
|
|
-- ------------------------
|
|
-- |
|
|
-- | -z (S) 2
|
|
|
|
-- From the picture above, your front could be at either -z, -z, x or z.
|
|
-- To get the entity closer to the front, you need to add a certain amount
|
|
-- (e.g. 0.25) to the x and z coordinates, and then multiply these by the
|
|
-- the node direction (which is a vector pointing outwards of the node face).
|
|
-- Therefore, start_pos is:
|
|
local start_pos = {
|
|
x=pos.x - (obj_dir.x * horizontal_displacement) + (node_dir.x * depth_displacement),
|
|
y=pos.y + vertical_displacement,
|
|
z=pos.z - (obj_dir.z * horizontal_displacement) + (node_dir.z * depth_displacement)
|
|
}
|
|
|
|
-- Calculate amount of objects in the inventory
|
|
local inv = minetest.get_meta(pos):get_inventory()
|
|
local list = inv:get_list("main")
|
|
local obj_count = 0
|
|
for key, itemstack in pairs(list) do
|
|
if not itemstack:is_empty() then
|
|
obj_count = obj_count + 1
|
|
end
|
|
end
|
|
minetest.log("Found "..dump(obj_count).." items on shelf inventory")
|
|
if obj_count > 0 then
|
|
local shown_items = math.min(#list, max_shown_items)
|
|
for i = 1, shown_items do
|
|
local offset = i
|
|
if i > (shown_items / 2) then
|
|
offset = i - (shown_items / 2)
|
|
end
|
|
if i == ((shown_items / 2) + 1) then
|
|
start_pos.y = start_pos.y - 0.5125
|
|
end
|
|
local item_displacement = 0.475
|
|
if shown_items == 6 then
|
|
item_displacement = 0.2775
|
|
end
|
|
local obj_pos = {
|
|
x=start_pos.x + (item_displacement * offset * obj_dir.x), --- (node_dir.z * overhead * 0.25),
|
|
y=start_pos.y,
|
|
z=start_pos.z + (item_displacement * offset * obj_dir.z) --- (node_dir.x * overhead * 0.25)
|
|
}
|
|
|
|
if not list[i]:is_empty() then
|
|
minetest.log("Adding item entity at "..minetest.pos_to_string(obj_pos))
|
|
temp_texture = list[i]:get_name()
|
|
temp_size = 0.8/max_shown_items
|
|
--minetest.log("Size: "..dump(temp_size))
|
|
local ent = minetest.add_entity(obj_pos, "itemshelf:item")
|
|
ent:set_properties({
|
|
wield_item = temp_texture,
|
|
visual_size = {x = 0.8/max_shown_items, y = 0.8/max_shown_items}
|
|
})
|
|
ent:set_yaw(minetest.dir_to_yaw(minetest.facedir_to_dir(node.param2)))
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
itemshelf = {}
|
|
|
|
-- Definable properties:
|
|
-- - description
|
|
-- - textures (if drawtype is nodebox)
|
|
-- - nodebox (like default minetest.register_node def)
|
|
-- - mesh (like default minetest.register_node def)
|
|
-- - item capacity (how many items will fit into the shelf, use even numbers, max 16)
|
|
-- - shown_items (how many items to show, will always show first (shown_items/2) items of each row, max 6)
|
|
-- - `half-depth`: if set to true, will use different nodebox. Do not use with `depth_offset`
|
|
-- - `vertical_offset`: starting position vertical displacement from the center of the node
|
|
-- - `depth_offset`: starting position depth displacement from the center of the node
|
|
function itemshelf.register_shelf(name, def)
|
|
-- Determine drawtype
|
|
local drawtype = "nodebox"
|
|
if def.mesh then
|
|
drawtype = "mesh"
|
|
end
|
|
|
|
minetest.register_node("itemshelf:"..name, {
|
|
description = def.description,
|
|
tiles = def.textures,
|
|
paramtype = "light",
|
|
paramtype2 = "facedir",
|
|
drawtype = drawtype,
|
|
node_box = def.nodebox,
|
|
mesh = def.mesh,
|
|
groups = {choppy = 2, itemshelf = 1, itemshelf_shown_items = def.shown_items or 4},
|
|
on_construct = function(pos)
|
|
-- Initialize inventory
|
|
local meta = minetest.get_meta(pos)
|
|
local inv = meta:get_inventory()
|
|
inv:set_size("main", def.capacity or 4)
|
|
-- Initialize formspec
|
|
meta:set_string("formspec", get_shelf_formspec(def.capacity or 4))
|
|
-- If given half_depth, initialize the displacement
|
|
if def.half_depth == true then
|
|
meta:set_float("itemshelf:depth_displacement", -0.1475)
|
|
end
|
|
-- Initialize custom displacements if defined
|
|
if def.vertical_offset then
|
|
meta:set_float("itemshelf:vertical_displacement", def.vertical_offset)
|
|
end
|
|
if def.depth_offset then
|
|
meta:set_float("itemshelf:depth_displacement", def.depth_offset)
|
|
end
|
|
end,
|
|
-- allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
|
-- if minetest.get_item_group(stack:get_name(), "music_disc") ~= 0 then
|
|
-- return stack:get_count()
|
|
-- end
|
|
-- return 0
|
|
-- end,
|
|
on_metadata_inventory_put = update_shelf,
|
|
on_metadata_inventory_take = update_shelf,
|
|
on_dig = function(pos, node, digger)
|
|
-- Clear any object disc
|
|
local objs = minetest.get_objects_inside_radius(pos, 0.7)
|
|
for _,obj in pairs(objs) do
|
|
obj:remove()
|
|
end
|
|
-- Pop-up items
|
|
minetest.add_item(pos, node.name)
|
|
local meta = minetest.get_meta(pos)
|
|
local list = meta:get_inventory():get_list("main")
|
|
for _,item in pairs(list) do
|
|
local drop_pos = {
|
|
x=math.random(pos.x - 0.5, pos.x + 0.5),
|
|
y=pos.y,
|
|
z=math.random(pos.z - 0.5, pos.z + 0.5)}
|
|
minetest.add_item(pos, item:to_string())
|
|
end
|
|
-- Remove node
|
|
minetest.remove_node(pos)
|
|
end,
|
|
on_blast = function(pos)
|
|
minetest.add_item(pos, minetest.get_node(pos).name)
|
|
local meta = minetest.get_meta(pos)
|
|
local list = meta:get_inventory():get_list("main")
|
|
for _,item in pairs(list) do
|
|
local drop_pos = {
|
|
x=math.random(pos.x - 0.5, pos.x + 0.5),
|
|
y=pos.y,
|
|
z=math.random(pos.z - 0.5, pos.z + 0.5)}
|
|
minetest.add_item(pos, item:to_string())
|
|
end
|
|
-- Remove node
|
|
minetest.remove_node(pos)
|
|
return nil
|
|
end,
|
|
-- Screwdriver support
|
|
on_rotate = function(pos, node, user, mode, new_param2) --{name = node.name, param1 = node.param1, param2 = node.param2}, user, mode, new_param2)
|
|
-- Rotate
|
|
node.param2 = new_param2
|
|
minetest.swap_node(pos, node)
|
|
update_shelf(pos)
|
|
-- Disable rotation by screwdriver
|
|
return false
|
|
end,
|
|
})
|
|
end
|
|
|
|
-- Entity for shelf
|
|
minetest.register_entity("itemshelf:item", {
|
|
hp_max = 1,
|
|
visual = "wielditem",
|
|
visual_size = {x = 0.20, y = 0.20},
|
|
collisionbox = {0,0,0, 0,0,0},
|
|
physical = false,
|
|
on_activate = function(self, staticdata)
|
|
-- Staticdata
|
|
local data = {}
|
|
if staticdata ~= nil and staticdata ~= "" then
|
|
local cols = string.split(staticdata, "|")
|
|
data["itemstring"] = cols[1]
|
|
data["visualsize"] = tonumber(cols[2])
|
|
end
|
|
|
|
-- Texture
|
|
if temp_texture ~= nil then
|
|
-- Set texture from temp
|
|
self.itemstring = temp_texture
|
|
temp_texture = nil
|
|
elseif staticdata ~= nil and staticdata ~= "" then
|
|
-- Set texture from static data
|
|
self.itemstring = data.itemstring
|
|
end
|
|
-- Set texture if available
|
|
if self.itemstring ~= nil then
|
|
self.wield_item = self.itemstring
|
|
end
|
|
|
|
-- Visual size
|
|
if temp_size ~= nil then
|
|
self.visualsize = temp_size
|
|
temp_size = nil
|
|
elseif staticdata ~= nil and staticdata ~= "" then
|
|
self.visualsize = data.visualsize
|
|
end
|
|
-- Set visual size if available
|
|
if self.visualsize ~= nil then
|
|
self.visual_size = {x=self.visualsize, y=self.visualsize}
|
|
end
|
|
|
|
-- Set object properties
|
|
self.object:set_properties(self)
|
|
|
|
end,
|
|
get_staticdata = function(self)
|
|
local result = ""
|
|
if self.itemstring ~= nil then
|
|
result = self.itemstring.."|"
|
|
end
|
|
if self.visualsize ~= nil then
|
|
result = result..self.visualsize
|
|
end
|
|
return result
|
|
end,
|
|
})
|