Add item frame and item showcase

master
Wuzzy 2022-07-17 12:56:31 +02:00
parent 23c305a1d9
commit 9857afa0c0
11 changed files with 380 additions and 0 deletions

View File

@ -116,6 +116,7 @@ This is the list of all groups used for nodes. Note: If no number/rating is spec
* `lush_leaves`: Any non-dry leaves
* `spikes`: Spikes
* `item_showcase`: Item showcase
* `plantable_dry`: You can plant farming plants on it and this node is considered to be dry
* `plantable_sandy`: You can plant farming plants on it and this node is considered to be made out of sand

10
mods/rp_itemshow/API.md Normal file
View File

@ -0,0 +1,10 @@
Usually, items are placed properly on the item frame or item showcase and look correctly.
However, sometimes these might appear too big or are offset too far away from the node.
So there are two optional node fields recognize which you can use to tweak the appearance
of the entity when placed:
* `_rp_itemshow_scale`: Number. Set the scale of the entity in the itemshow node directly.
Use this when the entity visual would be too big.
* `_rp_itemshow_offset`: Vector. Offset the entity sideways and up/down. X and Z MUST be equal.
You usually need this if the entity appears "behind" the item frame.

354
mods/rp_itemshow/init.lua Normal file
View File

@ -0,0 +1,354 @@
local S = minetest.get_translator("rp_itemshow")
local BASE_ITEM_SIZE = 1/3
local ROTATE_SPEED = 1 -- speed at which the entity rotates
local DEFAULT_ROTATE_DIR = -1 -- clockwise
-- Clockwise because dropped item rotate counter-clockwise,
-- so the 'itemshow' entities rotate the other way by
-- default
local FACEDIR = {}
FACEDIR[0] = {x = 0, y = 0, z = 1}
FACEDIR[1] = {x = 1, y = 0, z = 0}
FACEDIR[2] = {x = 0, y = 0, z = -1}
FACEDIR[3] = {x = -1, y = 0, z = 0}
-- functions
local remove_item = function(pos, node, dry_run)
local objs = nil
local objects_found = false
if node.name == "rp_itemshow:frame" or
minetest.get_item_group(node.name, "item_showcase") == 1 then
objs = minetest.get_objects_inside_radius(pos, 0.5)
end
if objs then
for _, obj in ipairs(objs) do
if obj and obj:get_luaentity() then
local ent = obj:get_luaentity()
local name = ent.name
local nodename = ent._nodename
if name == "rp_itemshow:item" and nodename == node.name then
objects_found = true
if dry_run then
return objects_found
else
obj:remove()
end
end
end
end
end
return objects_found
end
local update_item = function(pos, node, check_item)
local objects_found = remove_item(pos, node, check_item)
if check_item and objects_found then
return
end
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local stack = inv:get_stack("main", 1)
if not stack:is_empty() then
if node.name == "rp_itemshow:frame" then
local posad = FACEDIR[node.param2]
if not posad then return end
local def = minetest.registered_items[stack:get_name()]
local offset = def._rp_itemshow_offset or vector.new(0,0,0)
pos.x = pos.x + posad.x * 6.5 / 16 + posad.x * offset.x
pos.y = pos.y + posad.y * 6.5 / 16 + offset.y
pos.z = pos.z + posad.z * 6.5 / 16 + posad.z * offset.z
elseif minetest.get_item_group(node.name, "item_showcase") == 1 then
-- no pos change, put in center of node
end
local e = minetest.add_entity(pos,"rp_itemshow:item")
if e then
local lua = e:get_luaentity()
if lua then
local dir = DEFAULT_ROTATE_DIR
if node.param2 == 1 then
dir = -dir
end
lua:_configure(stack:get_name(), node.name, dir)
end
end
if e and node.name == "rp_itemshow:frame" then
local yaw = math.pi * 2 - node.param2 * math.pi / 2
e:set_yaw(yaw)
end
end
end
local drop_item = function(pos, node, creative)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local item = inv:get_stack("main", 1)
if not item:is_empty() then
if creative then
-- Don't drop item
elseif node.name == "rp_itemshow:frame" then
minetest.add_item(pos, item)
elseif minetest.get_item_group(node.name, "item_showcase") == 1 then
minetest.add_item({x=pos.x, y=pos.y+0.75, z=pos.z}, item)
end
inv:set_stack("main", 1, "")
end
remove_item(pos, node)
end
local on_rightclick = function(pos, node, clicker, itemstack)
if not itemstack then return end
local name = clicker:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, "protection_bypass") then
minetest.record_protection_violation(pos, name)
return itemstack
end
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local creative = minetest.is_creative_enabled(name)
if not inv:get_stack("main", 1):is_empty() then
drop_item(pos, node, creative)
else
inv:set_stack("main", 1, itemstack)
update_item(pos, node)
if not creative then
itemstack:take_item()
end
return itemstack
end
end
-- Entity for displayed item
minetest.register_entity("rp_itemshow:item",{
hp_max = 1,
visual = "wielditem",
is_visible = false,
visual_size = {x = BASE_ITEM_SIZE, y = BASE_ITEM_SIZE },
pointable = false,
physical = false,
-- Extra fields used:
-- * _nodename: Name of node this displayed item belongs to
-- * _item: Itemstring of displayed item
-- * _rotate_dir: Direction of entity rotation (for showcase)
_configure = function(self, item, nodename, rotate_dir)
local props = { is_visible = true }
if item then
self._item = item
props.wield_item = self._item
end
if nodename then
self._nodename = nodename
end
if rotate_dir then
self._rotate_dir = rotate_dir
end
if self._nodename and self._nodename ~= "" then
if minetest.get_item_group(self._nodename, "item_showcase") == 1 then
if not self._rotate_dir then
self._rotate_dir = DEFAULT_ROTATE_DIR
end
props.automatic_rotate = ROTATE_SPEED * self._rotate_dir
end
end
if self._item then
local def = minetest.registered_items[self._item]
if def then
local v
if def._rp_itemshow_scale then
v = def._rp_itemshow_scale
else
v = 1
if def.wield_scale then
v = v / def.wield_scale.x
end
end
if v then
v = v * BASE_ITEM_SIZE
props.visual_size = { x = v, y = v }
end
end
end
self.object:set_properties(props)
end,
on_activate = function(self, staticdata)
self.object:set_armor_groups({immortal=1})
local nodename, item, rotate_dir
if staticdata ~= nil and staticdata ~= "" then
local data = staticdata:split(';')
if data and data[1] and data[2] then
nodename = data[1]
item = data[2]
end
if data and data[3] then
rotate_dir = tonumber(data[3]) or DEFAULT_ROTATE_DIR
end
end
if item and item ~= "" then
self:_configure(item, nodename, rotate_dir)
end
end,
get_staticdata = function(self)
if self._nodename ~= nil and self._item ~= nil then
local data = self._nodename .. ';' .. self._item
if self._rotate_dir ~= nil then
data = data .. ";" .. self._rotate_dir
end
return data
end
return ""
end,
})
-- nodes
minetest.register_node("rp_itemshow:frame",{
description = S("Item Frame"),
_tt_help = S("You can show off an item here"),
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {-7/16, -7/16, 7/16, 7/16, 7/16, 0.5}
},
tiles = {
"rp_itemshow_frame.png",
"rp_itemshow_frame.png",
"rp_itemshow_frame.png",
"rp_itemshow_frame.png",
"rp_itemshow_frame_back.png",
"rp_itemshow_frame.png",
},
inventory_image = "rp_itemshow_frame_inventory.png",
wield_image = "rp_itemshow_frame_inventory.png",
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
groups = {choppy = 2, dig_immediate = 2},
sounds = rp_sounds.node_sound_defaults(),
is_ground_content = false,
on_rotate = function(pos, node, user, mode, new_param2)
if mode == screwdriver.ROTATE_AXIS then
return false
elseif mode == screwdriver.ROTATE_FACE then
local newnode = table.copy(node)
newnode.param2 = new_param2
update_item(pos, newnode)
return
end
end,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", S("Item Frame"))
local inv = meta:get_inventory()
inv:set_size("main", 1)
end,
on_rightclick = on_rightclick,
on_destruct = function(pos)
drop_item(pos, minetest.get_node(pos), minetest.is_creative_enabled(""))
end,
on_punch = function(pos, node, puncher)
update_item(pos, node, true)
end,
})
local function on_place_node_callbacks(place_to, newnode, placer, oldnode, itemstack, pointed_thing)
-- Run script hook
for _, callback in ipairs(minetest.registered_on_placenodes) do
-- Deepcopy pos, node and pointed_thing because callback can modify them
local place_to_copy = {x = place_to.x, y = place_to.y, z = place_to.z}
local newnode_copy =
{name = newnode.name, param1 = newnode.param1, param2 = newnode.param2}
local oldnode_copy =
{name = oldnode.name, param1 = oldnode.param1, param2 = oldnode.param2}
local pointed_thing_copy = {
type = pointed_thing.type,
above = vector.new(pointed_thing.above),
under = vector.new(pointed_thing.under),
ref = pointed_thing.ref,
}
callback(place_to_copy, newnode_copy, placer,
oldnode_copy, itemstack, pointed_thing_copy)
end
end
-- Item Showcase
minetest.register_node("rp_itemshow:showcase", {
description = S("Item Showcase"),
_tt_help = S("You can show off an item here"),
drawtype = "glasslike",
tiles = {"rp_itemshow_showcase.png"},
use_texture_alpha = "clip",
paramtype = "light",
groups = { item_showcase = 1, cracky = 3, oddly_breakable_by_hand = 2 },
sounds = rp_sounds.node_sound_glass_defaults(),
is_ground_content = false,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", S("Item Showcase"))
local inv = meta:get_inventory()
inv:set_size("main", 1)
end,
on_destruct = function(pos)
drop_item(pos, minetest.get_node(pos), minetest.is_creative_enabled(""))
end,
on_rightclick = on_rightclick,
on_punch = function(pos, node, puncher)
update_item(pos, node, true)
end,
})
-- automatically restore entities lost from frames/showcases
-- due to /clearobjects or similar
minetest.register_lbm({
name = "rp_itemshow:respawn_entities",
label = "Respawn entities of item frames and item showcases",
nodenames = {"rp_itemshow:frame", "group:item_showcase"},
run_at_every_load = true,
action = function(pos, node)
local num
if node.name == "rp_itemshow:frame" then
num = #minetest.get_objects_inside_radius(pos, 0.5)
elseif minetest.get_item_group(node.name, "item_showcase") == 1 then
pos.y = pos.y + 1
num = #minetest.get_objects_inside_radius(pos, 0.5)
pos.y = pos.y - 1
end
if num > 0 then
return
end
update_item(pos, node)
end
})
-- crafts
crafting.register_craft({
output = "rp_itemshow:frame",
items = { "rp_default:stick 8", "rp_default:paper", "rp_default:fiber 3" },
})
crafting.register_craft({
output = "rp_itemshow:showcase",
items = { "rp_default:glass", "rp_default:ingot_copper 4" },
})

View File

@ -0,0 +1,4 @@
# textdomain: rp_itemshow
Item Frame=Gegenstandsrahmen
You can show off an item here=Hier können Sie einen Gegenstand präsentieren
Item Showcase=Gegenstandsvitrine

View File

@ -0,0 +1,4 @@
# textdomain: rp_itemshow
Item Frame=
You can show off an item here=
Item Showcase=

View File

@ -0,0 +1,3 @@
name = rp_itemshow
description = Item frames and item showcases
depends = rp_sounds, rp_default

View File

@ -0,0 +1,4 @@
Itemshow mod
Use the 'place' key to add or remove an item from a item frame or item showcase.
Punch the block to force update if items do not appear.

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B