itemshelf/api.lua

327 lines
10 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 = def.groups or {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,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
else
return count
end
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
else
return stack:get_count()
end
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
else
return stack:get_count()
end
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,
})