Rewrite Itemframes

This commit is contained in:
cora 2024-01-16 19:42:47 +01:00 committed by the-real-herowl
parent 38486d057c
commit 5e4f9c9d4f
3 changed files with 216 additions and 944 deletions

View file

@ -1,27 +1,226 @@
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
mcl_itemframes = {}
mcl_itemframes.registered_nodes = {}
mcl_itemframes.registered_itemframes = {}
local S = minetest.get_translator(minetest.get_current_modname())
-- mcl_itemframes API
dofile(modpath .. "/item_frames_API.lua")
--[[ TODO: implement stubs for these entities and remove/replace them
minetest.register_entity("mcl_itemframes:map", map_item_base)
minetest.register_entity("mcl_itemframes:glow_item", frame_item_base)
minetest.register_entity("mcl_itemframes:glow_map", map_item_base)
--]]
-- actual api initialization.
mcl_itemframes.create_base_definitions()
local fbox = {type = "fixed", fixed = {-6/16, -1/2, -6/16, 7/16, -7/16, 6/16}}
-- necessary to maintain compatibility amongst older versions.
mcl_itemframes.backwards_compatibility()
local base_props = {
visual = "wielditem",
visual_size = { x = 0.3, y = 0.3 },
physical = false,
pointable = false,
textures = { "blank.png" },
}
-- Define the standard frames.
mcl_itemframes.create_custom_frame("false", "item_frame", false,
"mcl_itemframes_item_frame.png", mcl_colors.WHITE, S("Can hold an item."),
S("Item Frame"), "")
mcl_itemframes.create_custom_frame("false", "glow_item_frame", true,
"mcl_itemframes_glow_item_frame.png", mcl_colors.WHITE, S("Can hold an item and glows."),
S("Glowing Item Frame"), "")
local map_props = {
visual = "upright_sprite",
visual_size = { x = 1, y = 1 },
collide_with_objects = false,
textures = { "blank.png" },
}
mcl_itemframes.tpl_node = {
drawtype = "nodebox",
is_ground_content = false,
node_box = fbox,
selection_box = fbox,
collision_box = fbox,
use_texture_alpha = "opaque",
paramtype = "light",
paramtype2 = "wallmounted",
sunlight_propagates = true,
sounds = mcl_sounds.node_sound_defaults(),
node_placement_prediction = "",
_mcl_hardness = 0.5,
_mcl_blast_resistance = 0.5,
}
mcl_itemframes.tpl_entity = {
initial_properties = base_props,
}
local function find_entity(pos)
for _,o in pairs(minetest.get_objects_inside_radius(pos, 0.45)) do
local l = o:get_luaentity()
if l and l.name == "mcl_itemframes:item" then
return l
end
end
end
local function find_or_create_entity(pos)
local l = find_entity(pos)
if not l then
l = minetest.add_entity(pos, "mcl_itemframes:item"):get_luaentity()
end
return l
end
local function remove_entity(pos)
local l = find_entity(pos)
if l then
l.object:remove()
end
end
local function drop_item(pos, itemstring)
if itemstring and itemstring ~= "" then
local stack = ItemStack(itemstring)
if minetest.registered_items[stack:get_name()] then
minetest.add_item(pos, stack)
end
end
end
local function get_map_id(itemstack)
local map_id = itemstack:get_meta():get_string("mcl_maps:id")
if map_id == "" then map_id = nil end
return map_id
end
local function update_entity(pos, itemstack)
if not itemstack then
local mstring = minetest.get_meta(pos):get_string("item")
if mstring ~= "" then
itemstack = ItemStack(mstring)
else
remove_entity(pos)
return
end
end
local itemstring = itemstack:get_name()
local l = find_or_create_entity(pos)
if not itemstring or itemstring == "" then
remove_entity(pos)
return
end
l:set_item(itemstack, pos)
return l
end
function mcl_itemframes.tpl_node.on_rightclick(pos, node, clicker, pstack, pointed_thing)
local itemstack = pstack:take_item()
local m = minetest.get_meta(pos)
drop_item(pos, m:get_string("item"))
m:set_string("item", itemstack:to_string())
update_entity(pos, itemstack)
if not minetest.is_creative_enabled(clicker:get_player_name()) then
return pstack
end
end
function mcl_itemframes.tpl_node.after_dig_node(pos, oldnode, oldmetadata, digger)
if oldmetadata and oldmetadata.fields and oldmetadata.fields.item then
drop_item(pos, oldmetadata.fields.item)
end
remove_entity(pos)
end
function mcl_itemframes.tpl_entity:set_item(itemstack, pos)
self._itemframe_pos = pos
self._item = itemstack:get_name()
self._stack = itemstack
self._map_id = get_map_id(itemstack)
local dir = minetest.wallmounted_to_dir(minetest.get_node(pos).param2)
self.object:set_pos(vector.add(self._itemframe_pos, dir * 0.42))
self.object:set_rotation(vector.dir_to_rotation(dir))
if self._map_id then
mcl_maps.load_map(self._map_id, function(texture)
if self.object and self.object:get_pos() then
self.object:set_properties(table.merge(map_props, { textures = { texture }}))
end
end)
return
end
self.object:set_properties(table.merge(base_props, { wield_item = self._item}))
end
function mcl_itemframes.tpl_entity:get_staticdata()
local s = { item = self._item, itemframe_pos = self._itemframe_pos, itemstack = self._itemstack, map_id = self._map_id }
s.props = self.object:get_properties()
return minetest.serialize(s)
end
function mcl_itemframes.tpl_entity:on_activate(staticdata, dtime_s)
local s = minetest.deserialize(staticdata)
if s then
self._itemframe_pos = s.itemframe_pos
self._itemstack = s.itemstack
self._item = s.item
self._map_id = s.map_id
update_entity(self._itemframe_pos, ItemStack(self._itemstack))
return
end
end
function mcl_itemframes.tpl_entity:on_step(dtime)
self._timer = (self._timer and self._timer - dtime) or 1
if self._timer > 0 then return end
self._timer = 1
if minetest.get_item_group(minetest.get_node(self._itemframe_pos).name, "itemframe") <= 0 then
self.object:remove()
return
end
if minetest.get_item_group(self._item, "clock") > 0 then
self:set_item("mcl_clock:clock_"..mcl_clock.get_clock_frame())
end
end
function mcl_itemframes.register_itemframe(name, def)
if not def.node then return end
local nodename = "mcl_itemframes:"..name
table.insert(mcl_itemframes.registered_nodes, nodename)
mcl_itemframes.registered_itemframes[name] = def
minetest.register_node(":"..nodename, table.merge(mcl_itemframes.tpl_node, def.node, {
_mcl_itemframe = name,
groups = table.merge({ dig_immediate = 3, deco_block = 1, dig_by_piston = 1, handy = 1, axey = 1, itemframe = 1 }, def.node.groups),
}))
end
minetest.register_entity("mcl_itemframes:item", mcl_itemframes.tpl_entity)
mcl_itemframes.register_itemframe("frame", {
node = {
description = S("Item Frame"),
_tt_help = S("Can hold an item"),
_doc_items_longdesc = S("Item frames are decorative blocks in which items can be placed."),
_doc_items_usagehelp = S("Just place any item on the item frame. Use the item frame again to retrieve the item."),
tiles = { "mcl_itemframes_item_frame.png" },
inventory_image = "mcl_itemframes_item_frame.png",
wield_image = "mcl_itemframes_item_frame.png",
},
})
mcl_itemframes.register_itemframe("glow_frame", {
node = {
description = S("Glow Item Frame"),
_tt_help = S("Can hold an item and glows"),
_doc_items_longdesc = S("Item frames are decorative blocks in which items can be placed."),
_doc_items_usagehelp = S("Just place any item on the item frame. Use the item frame again to retrieve the item."),
tiles = { "mcl_itemframes_glow_item_frame.png" },
inventory_image = "mcl_itemframes_glow_item_frame.png",
wield_image = "mcl_itemframes_glow_item_frame.png",
},
object_properties = { glow = 15 },
})
minetest.register_lbm({
label = "Respawn item frame item entities",
name = "mcl_itemframes:respawn_entities",
nodenames = { "group:itemframe" },
run_at_every_load = true,
action = function(pos,_)
update_entity(pos)
end
})
-- Register the base frame's recipes.
-- was going to make it a specialized function, but minetest refuses to play nice.
minetest.register_craft({
output = "mcl_itemframes:item_frame",
recipe = {
@ -36,5 +235,3 @@ minetest.register_craft({
output = 'mcl_itemframes:glow_item_frame',
recipe = { 'mcl_mobitems:glow_ink_sac', 'mcl_itemframes:item_frame' },
})
mcl_itemframes.custom_register_lbm()

View file

@ -1,889 +0,0 @@
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by michieal.
--- DateTime: 10/26/22 1:16 AM
---
mcl_itemframes = {}
mcl_itemframes.item_frame_base = {}
mcl_itemframes.glow_frame_base = {}
mcl_itemframes.frames_registered = {}
mcl_itemframes.frames_registered.glowing = {}
mcl_itemframes.frames_registered.standard = {}
-- Set to true to get all of the DEBUG messages.
mcl_itemframes.DEBUG = false
if mcl_itemframes.DEBUG then
minetest.log("action", "[mcl_itemframes] initialized.")
end
local S = minetest.get_translator(minetest.get_current_modname())
local table = table
local pairs = pairs
if mcl_itemframes.DEBUG then
minetest.log("action", "[mcl_itemframes] API initialized.")
end
local VISUAL_SIZE = 0.3
local facedir = {}
local pi = math.pi
local glow_amount = 6 -- LIGHT_MAX is 15, but the items aren't supposed to be a light source.
local frame_item_base = {}
local map_item_base = {}
local TIMER_INTERVAL = 40.0
-- Time to Fleckenstein! (it just sounds cool lol)
--- self: the object to roll.
local function update_roll(self, pos)
-- get the entity's metadata.
local meta = minetest.get_meta(pos)
-- using an integer, as it's the number of 45 degree turns. ie, 0 to 7
local current_roll = meta:get_int("roll", 0)
local new_roll = current_roll + 1
if new_roll == 8 then
new_roll = 0
end
meta:set_int("roll", new_roll)
local new_roll_deg = new_roll * 45
-- * `get_rotation()`: returns the rotation, a vector (radians)
local rot = self:get_rotation()
local Radians = 0
-- Radians = Degrees * (pi / 180) degrees to radian formula
-- Radian quick chart
-- One full revolution is equal to 2π rad (or) 360°.
-- 1° = 0.017453 radians and 1 rad = 57.2958°.
-- To convert an angle from degrees to radians, we multiply it by π/180°.
-- To convert an angle from radians to degrees, we multiply it by 180°/π.
Radians = new_roll_deg * (pi / 180)
rot.z = Radians
self:set_rotation(rot)
end
--- self: the object to roll.
--- faceDeg: 0-7, inclusive.
local function set_roll(self, faceDeg)
-- get the entity's metadata.
local meta = minetest.get_meta(self:get_pos())
-- using an integer, as it's the number of 45 degree turns. ie, 0 to 7
local new_roll = faceDeg
if new_roll >= 8 then
new_roll = 7
end
if new_roll <= 0 then
new_roll = 0
end
meta:set_int("roll", new_roll)
local new_roll_deg = new_roll * 45
-- * `get_rotation()`: returns the rotation, a vector (radians)
local rot = self:get_rotation()
local Radians = 0
-- Radians = Degrees * (pi / 180) degrees to radian formula
-- Radian quick chart
-- One full revolution is equal to 2π rad (or) 360°.
-- 1° = 0.017453 radians and 1 rad = 57.2958°.
-- To convert an angle from degrees to radians, we multiply it by π/180°.
-- To convert an angle from radians to degrees, we multiply it by 180°/π.
Radians = new_roll_deg * (pi / 180)
rot.z = Radians
self:set_rotation(rot)
end
local function update_map_texture (self, staticdata)
self.id = staticdata
local result = true
result = mcl_maps.load_map(self.id, function(texture)
-- will not crash even if self.object is invalid by now
-- update... quite possibly will screw up with each version of Luanti. >.<
if not texture then
minetest.log("error", "Failed to load the map texture using mcl_maps.")
end
self.object:set_properties({ textures = { texture } })
end)
if result ~= nil and result == false then
minetest.log("error", "[mcl_itemframes] Error setting up Map Item.")
end
end
local remove_item_entity = function(pos, node)
local name_found = false
local found_name_to_use = ""
for k, v in pairs(mcl_itemframes.frames_registered.glowing) do
if node.name == v then
name_found = true
found_name_to_use = v
break
end
end
-- try to cut down on excess looping, if possible.
if name_found == false then
for k, v in pairs(mcl_itemframes.frames_registered.standard) do
if node.name == v then
name_found = true
found_name_to_use = v
break
end
end
end
if mcl_itemframes.DEBUG then
minetest.log("action", "mcl_itemframes] remove_item_entity: " .. found_name_to_use .. "'s displayed item.")
end
-- node.name == "mcl_itemframes:item_frame" or node.name == "mcl_itemframes:glow_item_frame" or
if node.name == found_name_to_use then
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 0.5)) do
local entity = obj:get_luaentity()
if entity then
-- remove old entities
if entity.name == "mcl_itemframes:item" or entity.name == "mcl_itemframes:glow_item" or entity.name == "mcl_itemframes:map" or entity.name == "mcl_itemframes:glow_map" then
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 (node.name == found_name_to_use) then
minetest.add_item(pos, item)
end
meta:set_string("infotext", "")
end
obj:remove()
end
if entity.name == found_name_to_use .. "_item" or entity.name == found_name_to_use .. "_map" then
if mcl_itemframes.DEBUG then
minetest.log("action", "mcl_itemframes] remove_item_entity: " .. entity.name .. "-- the item.")
end
obj:remove()
end
end
end
end
end
mcl_itemframes.update_item_entity = function(pos, node, param2)
if mcl_itemframes.DEBUG then
minetest.log("action", "[mcl_itemframes] Update_Generic_Item:\nPosition: " .. dump(pos) .. "\nNode: " .. dump(node))
end
remove_item_entity(pos, node)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local item = inv:get_stack("main", 1)
local name_found = false
local found_name_to_use = ""
local has_glow = false
for k, v in pairs(mcl_itemframes.frames_registered.glowing) do
if node.name == v then
name_found = true
has_glow = true
found_name_to_use = v
break
end
end
-- try to cut down on excess looping, if possible.
if name_found == false then
for k, v in pairs(mcl_itemframes.frames_registered.standard) do
if node.name == v then
name_found = true
has_glow = false
found_name_to_use = v
break
end
end
end
if name_found == false then
minetest.log("error", "[mcl_itemframes] Update_Generic_Item:\nFailed to find registered node:\nNode name - " .. node.name)
minetest.log("error", "[mcl_itemframes] Update_Generic_Item:\nRegistry definition:" .. dump(mcl_itemframes.frames_registered))
return
end
if not item:is_empty() then
-- update existing items placed.
if not param2 then
param2 = node.param2
end
local pos_adj = facedir[param2]
if node.name == found_name_to_use then
pos.x = pos.x + pos_adj.x * 6.5 / 16
pos.y = pos.y + pos_adj.y * 6.5 / 16
pos.z = pos.z + pos_adj.z * 6.5 / 16
if mcl_itemframes.DEBUG then
minetest.log("[mcl_itemframes] Update_Generic_Item:\nFound Name in Registry: " .. found_name_to_use)
end
end
local yaw = pi * 2 - param2 * pi / 2
local map_id = item:get_meta():get_string("mcl_maps:id")
local map_id_entity = {}
local map_id_lua = {}
local timer = minetest.get_node_timer(pos)
if map_id == "" then
-- handle regular items placed into custom frame.
if mcl_itemframes.DEBUG then
minetest.log("action", "[mcl_itemframes] Update_Generic_Item:\nAdding entity: " .. node.name .. "_item")
end
if node.name == found_name_to_use then
map_id_entity = minetest.add_entity(pos, node.name .. "_item")
else
local debug_string = "[mcl_itemframes] Update_Generic_Item:\nCouldn't find node name in registry: "
minetest.log("error", debug_string .. found_name_to_use "\nregistry: " .. dump(mcl_itemframes.frames_registered))
return
end
map_id_lua = map_id_entity:get_luaentity()
map_id_lua._nodename = node.name
local itemname = item:get_name()
if itemname == "" or itemname == nil then
map_id_lua._texture = "blank.png"
map_id_lua._scale = 1
-- set up glow, as this is the default/initial clause on placement.
if has_glow then
map_id_lua.glow = glow_amount
end
-- if there's nothing to display, then kill the timer.
if timer:is_started() == true then
timer:stop()
end
else
map_id_lua._texture = itemname
local def = minetest.registered_items[itemname]
map_id_lua._scale = def and def.wield_scale and def.wield_scale.x or 1
-- fix for /ClearObjects
if minetest.get_item_group(itemname, "clock") == 0 then
-- Do timer related stuff - but only if there is something to display... and it's not a clock.
if timer:is_started() == false then
timer:start(TIMER_INTERVAL)
else
timer:stop()
timer:start(TIMER_INTERVAL)
end
end
end
if mcl_itemframes.DEBUG then
minetest.log("action", "[mcl_itemframes] Update_Generic_Item: item's name: " .. itemname)
end
map_id_lua:_update_texture()
if node.name == found_name_to_use then
map_id_entity:set_yaw(yaw)
else
minetest.log("error", "[mcl_itemframes] Update_Generic_Item: Failed to set Display Item's yaw. " .. node.name)
end
else
-- handle map items placed into custom frame.
if mcl_itemframes.DEBUG then
minetest.log("action", "[mcl_itemframes] Update_Generic_Item: Placing map in a " .. found_name_to_use .. " frame.")
end
if node.name == found_name_to_use then
map_id_entity = minetest.add_entity(pos, found_name_to_use .. "_map", map_id)
map_id_entity:set_yaw(yaw)
else
minetest.log("error", "[mcl_itemframes] Update_Generic_Item: Failed to set Map Item in " .. found_name_to_use .. "'s frame.")
end
-- give maps a refresh timer.
if timer:is_started() == false then
timer:start(TIMER_INTERVAL)
else
timer:stop()
timer:start(TIMER_INTERVAL)
end
end
-- finally, set the rotation (roll) of the displayed object.
local roll = meta:get_int("roll", 0)
set_roll(map_id_entity, roll)
end
end
function mcl_itemframes.drop_generic_item(pos, node, meta, clicker)
local name_found = false
local found_name_to_use = ""
for k, v in pairs(mcl_itemframes.frames_registered.glowing) do
if node.name == v then
name_found = true
found_name_to_use = v
break
end
end
-- try to cut down on excess looping, if possible.
if name_found == false then
for k, v in pairs(mcl_itemframes.frames_registered.standard) do
if node.name == v then
name_found = true
found_name_to_use = v
break
end
end
end
local cname = ""
if clicker and clicker:is_player() then
cname = clicker:get_player_name()
end
if not minetest.is_creative_enabled(cname) then
if (node.name == found_name_to_use) then
local inv = meta:get_inventory()
local item = inv:get_stack("main", 1)
if not item:is_empty() then
minetest.add_item(pos, item)
end
end
end
meta:set_string("infotext", "")
remove_item_entity(pos, node)
end
--- reworked to set up the base item definitions.
function mcl_itemframes.create_base_item_entity()
if mcl_itemframes.DEBUG then
minetest.log("action", "[mcl_itemframes] create_item_entity.")
end
--"mcl_itemframes:item",
frame_item_base = {
hp_max = 1,
visual = "wielditem",
visual_size = { x = VISUAL_SIZE, y = VISUAL_SIZE },
physical = false,
pointable = false,
textures = { "blank.png" },
_texture = "blank.png",
_scale = 1,
groups = { immortal = 1, },
on_activate = function(self, staticdata)
if staticdata and staticdata ~= "" then
local data = staticdata:split(";")
if data and data[1] and data[2] then
self._nodename = data[1]
self._texture = data[2]
if data[3] then
self._scale = data[3]
else
self._scale = 1
end
end
end
if self._texture then
self.object:set_properties({
textures = { self._texture },
visual_size = { x = VISUAL_SIZE / self._scale, y = VISUAL_SIZE / self._scale },
})
end
end,
get_staticdata = function(self)
if self._nodename and self._texture then
local ret = self._nodename .. ";" .. self._texture
if self._scale then
ret = ret .. ";" .. self._scale
end
return ret
end
return ""
end,
on_punch = function() return true end,
_update_texture = function(self)
if self._texture then
self.object:set_properties({
textures = { self._texture },
visual_size = { x = VISUAL_SIZE / self._scale, y = VISUAL_SIZE / self._scale },
})
end
end,
}
-- "mcl_itemframes:map",
map_item_base = {
initial_properties = {
visual = "upright_sprite",
visual_size = { x = 1, y = 1 },
pointable = false,
physical = false,
collide_with_objects = false,
textures = { "blank.png" },
},
on_activate = function(self, staticdata)
if mcl_itemframes.DEBUG then
minetest.log("action", "[mcl_itemframes] map_item:on_activate.")
end
update_map_texture(self, staticdata)
end,
get_staticdata = function(self)
return self.id
end,
}
end
function mcl_itemframes.create_custom_items(name, has_glow)
local custom_frame_item = table.copy(frame_item_base)
local custom_frame_map_item = table.copy(map_item_base)
if has_glow then
custom_frame_map_item.glow = glow_amount
custom_frame_item.glow = glow_amount
if mcl_itemframes.DEBUG then
minetest.log("action", "\n[mcl_itemframes] create_custom_item_entity: glow name: " .. name .. "_item")
minetest.log("action", "[mcl_itemframes] create_custom_item_entity: glow name: " .. name .. "_map\n")
end
else
if mcl_itemframes.DEBUG then
minetest.log("action", "\n[mcl_itemframes] create_custom_item_entity: name: " .. name .. "_item")
minetest.log("action", "[mcl_itemframes] create_custom_item_entity: name: " .. name .. "_map\n")
end
end
minetest.register_entity(":" .. name .. "_item", custom_frame_item)
minetest.register_entity(":" .. name .. "_map", custom_frame_map_item)
end
function mcl_itemframes.update_frame_registry(modname, name, has_glow)
local mod_name_pass = false
if modname ~= "" and modname ~= "false" then
if minetest.get_modpath(modname) then
mod_name_pass = true
end
if mod_name_pass == false then
return
end
end
local frame = name -- should only be called within the create_frames functions.
if has_glow == true then
table.insert(mcl_itemframes.frames_registered.glowing, frame)
else
table.insert(mcl_itemframes.frames_registered.standard, frame)
end
end
--- name: The name used to distinguish the item frame. Prepends "mcl_itemframes:" to the name. Example usage:
--- "glow_item_frame" creates a node named ":mcl_itemframes:glow_item_frame".
function mcl_itemframes.create_custom_frame(modname, name, has_glow, tiles, color, ttframe, description, inv_wield_image)
local mod_name_pass = false
if modname ~= "" and modname ~= "false" then
if minetest.get_modpath(modname) then
mod_name_pass = true
end
if mod_name_pass == false then
return
end
end
if name == nil then
name = ""
end
if name == "" then
minetest.log("error", "attempted to create an item frame WITHOUT a name!")
return
end
if has_glow == nil or has_glow == "" then
has_glow = false
end
if tiles == nil or tiles == "" then
minetest.log("error", "No textures passed to Create_Custom_Frame!! Exiting frame creation.")
return
end
local working_name = "mcl_itemframes:" .. name
if mcl_itemframes.DEBUG then
minetest.log("action", "[mcl_itemframes] create_custom_frame: " .. working_name)
minetest.log("action", "[mcl_itemframes] create_custom_frame - calling create_custom_items " .. working_name)
end
-- make any special frame items.
mcl_itemframes.create_custom_items(working_name, has_glow)
local custom_itemframe_definition = {}
if has_glow == false then
custom_itemframe_definition = table.copy(mcl_itemframes.item_frame_base)
else
custom_itemframe_definition = table.copy(mcl_itemframes.glow_frame_base)
end
if inv_wield_image ~= nil and inv_wield_image ~= "" then
custom_itemframe_definition.glow_frame_base.inventory_image = { "(" .. inv_wield_image .. "^[multiply:" .. color .. ")" }
custom_itemframe_definition.glow_frame_base.wield_image = { "(" .. inv_wield_image .. "^[multiply:" .. color .. ")" }
end
custom_itemframe_definition.tiles = { "(" .. tiles .. "^[multiply:" .. color .. ")" }
custom_itemframe_definition._tt_help = ttframe
custom_itemframe_definition.description = description
minetest.register_node(":" .. working_name, custom_itemframe_definition)
mcl_itemframes.update_frame_registry(modname, working_name, has_glow)
-- register Doc entry
if minetest.get_modpath("doc") then
doc.add_entry_alias("nodes", "mcl_itemframes:item_frame", "nodes", working_name)
end
end
function mcl_itemframes.custom_register_lbm()
local registered_frame_nodenames = {}
for i = 0, #mcl_itemframes.frames_registered.glowing do
table.insert(registered_frame_nodenames, mcl_itemframes.frames_registered.glowing[i])
end
for i = 0, #mcl_itemframes.frames_registered.standard do
table.insert(registered_frame_nodenames, mcl_itemframes.frames_registered.standard[i])
end
minetest.register_lbm({
label = "Respawn item frame item entities",
name = "mcl_itemframes:respawn_entities",
nodenames = registered_frame_nodenames,
run_at_every_load = true,
action = function(pos, node)
mcl_itemframes.update_item_entity(pos, node)
end,
})
end
local function register_frame_achievements()
awards.register_achievement("mcl_itemframes:glowframe", {
title = S("Glow and Behold!"),
description = S("Craft a glow item frame."),
icon = "mcl_itemframes_glow_item_frame.png",
trigger = {
type = "craft",
item = "mcl_itemframes:glow_item_frame",
target = 1
},
type = "Advancement",
group = "Overworld",
})
end
function mcl_itemframes.create_base_definitions()
if mcl_itemframes.DEBUG then
minetest.log("action", "[mcl_itemframes] create_base_definitions.")
end
-- set up the facedir information.
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 }
mcl_itemframes.item_frame_base = {
description = S("Item Frame"),
name = "mcl_itemframes:item_frame",
_tt_help = S("Can hold an item."),
_doc_items_longdesc = S("Item frames are decorative blocks in which items can be placed."),
_doc_items_usagehelp = S("Just place any item on the item frame. Use the item frame again to retrieve the item."),
drawtype = "mesh",
is_ground_content = false,
mesh = "mcl_itemframes_itemframe1facedir.obj",
selection_box = { type = "fixed", fixed = { -6 / 16, -6 / 16, 7 / 16, 6 / 16, 6 / 16, 0.5 } },
collision_box = { type = "fixed", fixed = { -6 / 16, -6 / 16, 7 / 16, 6 / 16, 6 / 16, 0.5 } },
tiles = { "mcl_itemframes_item_frame_back.png", "mcl_itemframes_item_frame_back.png", "mcl_itemframes_item_frame_back.png", "mcl_itemframes_item_frame_back.png", "default_wood.png", "mcl_itemframes_item_frame_back.png" },
inventory_image = "mcl_itemframes_item_frame.png",
wield_image = "mcl_itemframes_item_frame.png",
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
groups = { dig_immediate = 3, deco_block = 1, dig_by_piston = 1, container = 1, supported_node_facedir = 1 },
sounds = mcl_sounds.node_sound_defaults(),
node_placement_prediction = "",
on_timer = function(pos)
local inv = minetest.get_meta(pos):get_inventory()
local stack = inv:get_stack("main", 1)
local itemname = stack:get_name()
local node = {}
if minetest.get_item_group(itemname, "clock") > 0 then
local new_name = "mcl_clock:clock_" .. (mcl_worlds.clock_works(pos) and mcl_clock.old_time or mcl_clock.random_frame)
if itemname ~= new_name then
stack:set_name(new_name)
inv:set_stack("main", 1, stack)
node = minetest.get_node(pos)
mcl_itemframes.update_item_entity(pos, node, node.param2)
end
minetest.get_node_timer(pos):start(1.0)
else
node = minetest.get_node(pos)
mcl_itemframes.update_item_entity(pos, node, node.param2)
end
end,
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local dir = vector.subtract(pointed_thing.under, pointed_thing.above)
local wdir = minetest.dir_to_wallmounted(dir)
-- remove bottom and top of objects.
if wdir == 0 or wdir == 1 then
return itemstack
end
-- Use pointed node's on_rightclick function first, if present
local node = minetest.get_node(pointed_thing.under)
if placer and not placer:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
end
end
return minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(vector.direction(pointed_thing.above, pointed_thing.under)))
end,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size("main", 1)
end,
on_rightclick = function(pos, node, clicker, itemstack)
if not itemstack then
return
end
local pname = clicker:get_player_name()
if minetest.is_protected(pos, pname) then
minetest.record_protection_violation(pos, pname)
return
end
local meta = minetest.get_meta(pos)
mcl_itemframes.drop_generic_item(pos, node, meta, clicker)
local inv = meta:get_inventory()
if itemstack:is_empty() then
remove_item_entity(pos, node)
meta:set_string("infotext", "")
inv:set_stack("main", 1, "")
return itemstack
end
local put_itemstack = ItemStack(itemstack)
put_itemstack:set_count(1)
local itemname = put_itemstack:get_name()
if minetest.get_item_group(itemname, "compass") > 0 then
put_itemstack:set_name(mcl_compass.get_compass_itemname(pos, minetest.dir_to_yaw(minetest.facedir_to_dir(node.param2)), put_itemstack))
end
if minetest.get_item_group(itemname, "clock") > 0 then
minetest.get_node_timer(pos):start(1.0)
end
inv:set_stack("main", 1, put_itemstack)
mcl_itemframes.update_item_entity(pos, node)
-- Add node infotext when item has been named
local imeta = itemstack:get_meta()
local iname = imeta:get_string("name")
if iname then
meta:set_string("infotext", iname)
end
if not minetest.is_creative_enabled(clicker:get_player_name()) then
itemstack:take_item()
end
return itemstack
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
local name = player:get_player_name()
if minetest.is_protected(pos, name) then
minetest.record_protection_violation(pos, name)
return 0
else
return count
end
end,
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 stack:get_count()
end
end,
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
else
return stack:get_count()
end
end,
on_destruct = function(pos)
local meta = minetest.get_meta(pos)
local node = minetest.get_node(pos)
mcl_itemframes.drop_generic_item(pos, node, meta)
end,
on_rotate = function(pos, node, user, mode, param2)
--local meta = minetest.get_meta(pos)
local node = minetest.get_node(pos)
local objs = nil
local name_found = false
local found_name_to_use = ""
name_found = false
found_name_to_use = ""
for k, v in pairs(mcl_itemframes.frames_registered.glowing) do
if node.name == v then
name_found = true
found_name_to_use = v
break
end
end
-- try to cut down on excess looping, if possible.
if name_found == false then
for k, v in pairs(mcl_itemframes.frames_registered.standard) do
if node.name == v then
name_found = true
found_name_to_use = v
break
end
end
end
if node.name == found_name_to_use then
objs = minetest.get_objects_inside_radius(pos, 0.5)
else
return -- short circuit if it's somehow not the right thing.
end
if objs then
if mode == screwdriver.ROTATE_FACE or mode == screwdriver.ROTATE_AXIS then
for _, obj in ipairs(objs) do
if obj and obj:get_luaentity() then
local obj_name = obj:get_luaentity().name
if obj_name == found_name_to_use .. "_item" then
if mode == screwdriver.ROTATE_AXIS then
update_roll(obj, pos)
end
break
end
end
end
return false
end
end
end,
}
-- make the base items for the base frames.
mcl_itemframes.create_base_item_entity()
-- minetest.register_node("mcl_itemframes:item_frame", mcl_itemframes.item_frame_base)
-- make glow frame from the base item_frame.
mcl_itemframes.glow_frame_base = table.copy(mcl_itemframes.item_frame_base)
mcl_itemframes.glow_frame_base.description = S("Glowing Item Frame")
mcl_itemframes.glow_frame_base._tt_help = S("Can hold an item and glows.")
mcl_itemframes.glow_frame_base.longdesc = S("Glowing item frames are decorative blocks in which items can be placed and made to glow.")
mcl_itemframes.glow_frame_base.tiles = { "mcl_itemframes_glow_item_frame.png" }
mcl_itemframes.glow_frame_base.inventory_image = "mcl_itemframes_glow_item_frame.png"
mcl_itemframes.glow_frame_base.wield_image = "mcl_itemframes_glow_item_frame.png"
mcl_itemframes.glow_frame_base.mesh = "mcl_itemframes_glow_item_frame.obj"
mcl_itemframes.glow_frame_base.glow = 1 --make the glow frames have some glow at night, but not enough to be a light source.
-- set up the achievement for glow frames.
register_frame_achievements()
end
-- for compatibility:
function mcl_itemframes.backwards_compatibility ()
minetest.register_lbm({
label = "Update legacy item frames",
name = "mcl_itemframes:update_legacy_item_frames",
nodenames = { "itemframes:frame" },
action = function(pos, node)
-- Swap legacy node, then respawn entity
node.name = "mcl_itemframes:item_frame"
local meta = minetest.get_meta(pos)
local item = meta:get_string("item")
minetest.swap_node(pos, node)
if item ~= "" then
local itemstack = ItemStack(minetest.deserialize(meta:get_string("itemdata")))
local inv = meta:get_inventory()
inv:set_size("main", 1)
if not itemstack:is_empty() then
inv:set_stack("main", 1, itemstack)
end
end
mcl_itemframes.update_item_entity(pos, node)
end,
})
minetest.register_alias("itemframes:frame", "mcl_itemframes:item_frame")
-- adds backwards compatibility
minetest.register_alias("mcl_itemframes:item", "mcl_itemframes:item_frame_item")
minetest.register_alias("mcl_itemframes:map", "mcl_itemframes:item_frame_map")
minetest.register_alias("mcl_itemframes:glow_item", "mcl_itemframes:glow_item_frame_item")
minetest.register_alias("mcl_itemframes:glow_map", "mcl_itemframes:glow_item_frame_map")
minetest.register_entity("mcl_itemframes:item", frame_item_base)
minetest.register_entity("mcl_itemframes:map", map_item_base)
minetest.register_entity("mcl_itemframes:glow_item", frame_item_base)
minetest.register_entity("mcl_itemframes:glow_map", map_item_base)
end

View file

@ -1,36 +0,0 @@
The item frames use case is a very specific one, but... in the event that there is need for a new item frame then that
is where this api will shine.
As long as the api has been initialized (which it does in its own init.lua) then you really only need to call one
function. That function being mcl_itemframes.create_custom_frame(modname, name, has_glow, tiles, color, ttframe,
description, inv_wield_image). Note: unlike the Signs API, this API does not automatically create the recipe for you.
Here's an explanation of create_custom_frame and an example of using it.
This function is responsible for creating each frame, and handling the creation of its underlying entities.
Parameters:
* modname: Used to make sure that a specific module is installed before running the code contained within. Set to "" or
false, if there's not a mod to check for.
* name: The name used to distinguish the item frame. Prepends "mcl_itemframes:" to the name. Example usage:
"glow_item_frame" creates a node named "mcl_itemframes:glow_item_frame".
* has_glow: Does the frame cause the item within to glow? true / false.
* tiles: The image files used for the item frame's object texturing.
* color: Colorizes the frame / wield / inventory image to a specific color. Use White (#FFFFFF) to ignore.
* ttframe: The tooltip to show for the frame.
* description: The frame's description.
* inv_wield_image: Optionally the image to use as the inventory and the wield image. Colorized. set to "" or nil to use
the default frame / glow frame images. Note: must be set if you want the inventory / wield image to be colored.
example:
-- Register the Glow Frame
mcl_itemframes.create_custom_frame("false", "glow_item_frame", true,
"mcl_itemframes_glow_item_frame.png", mcl_colors.WHITE, "Glowing Item Frame",
"Can hold an item and glows.","")
-- Register the Glow Frame's recipe
minetest.register_craft({
type = "shapeless",
output = 'mcl_itemframes:glow_item_frame',
recipe = { 'mcl_mobitems:glow_ink_sac', 'mcl_itemframes:item_frame' },
})