2020-02-18 16:00:02 +01:00
local S = minetest.get_translator ( " mcl_armor_stand " )
2019-03-08 00:51:45 +01:00
2017-01-06 04:23:11 +01:00
local elements = { " head " , " torso " , " legs " , " feet " }
local function get_stand_object ( pos )
local object = nil
local objects = minetest.get_objects_inside_radius ( pos , 0.5 ) or { }
for _ , obj in pairs ( objects ) do
local ent = obj : get_luaentity ( )
if ent then
2020-02-18 16:00:02 +01:00
if ent.name == " mcl_armor_stand:armor_entity " then
2017-01-06 04:23:11 +01:00
-- Remove duplicates
if object then
obj : remove ( )
else
object = obj
end
end
end
end
return object
end
local function update_entity ( pos )
local node = minetest.get_node ( pos )
local object = get_stand_object ( pos )
if object then
2020-02-18 16:00:02 +01:00
if not string.find ( node.name , " mcl_armor_stand: " ) then
2017-01-06 04:23:11 +01:00
object : remove ( )
return
end
else
2020-02-18 16:00:02 +01:00
object = minetest.add_entity ( pos , " mcl_armor_stand:armor_entity " )
2017-01-06 04:23:11 +01:00
end
if object then
2020-02-17 17:46:25 +01:00
local texture = " blank.png "
2017-01-06 04:23:11 +01:00
local textures = { }
local meta = minetest.get_meta ( pos )
local inv = meta : get_inventory ( )
local yaw = 0
if inv then
for _ , element in pairs ( elements ) do
local stack = inv : get_stack ( " armor_ " .. element , 1 )
if stack : get_count ( ) == 1 then
local item = stack : get_name ( ) or " "
2020-02-18 15:44:54 +01:00
if minetest.registered_aliases [ item ] then
item = minetest.registered_aliases [ item ]
end
2017-01-06 04:23:11 +01:00
local def = stack : get_definition ( ) or { }
local groups = def.groups or { }
if groups [ " armor_ " .. element ] then
local texture = def.texture or item : gsub ( " %: " , " _ " )
table.insert ( textures , texture .. " .png " )
end
end
end
end
if # textures > 0 then
texture = table.concat ( textures , " ^ " )
end
if node.param2 then
local rot = node.param2 % 4
if rot == 1 then
yaw = 3 * math.pi / 2
elseif rot == 2 then
yaw = math.pi
elseif rot == 3 then
yaw = math.pi / 2
end
end
2019-03-06 04:38:57 +01:00
object : set_yaw ( yaw )
2017-01-06 04:23:11 +01:00
object : set_properties ( { textures = { texture } } )
end
end
2017-06-11 14:16:22 +02:00
-- Drop all armor of the armor stand on the ground
local drop_armor = function ( pos )
local meta = minetest.get_meta ( pos )
local inv = meta : get_inventory ( )
for _ , element in pairs ( elements ) do
local stack = inv : get_stack ( " armor_ " .. element , 1 )
if not stack : is_empty ( ) then
local p = { x = pos.x + math.random ( 0 , 10 ) / 10 - 0.5 , y = pos.y , z = pos.z + math.random ( 0 , 10 ) / 10 - 0.5 }
minetest.add_item ( p , stack )
end
end
end
2019-03-09 07:01:12 +01:00
-- TODO: The armor stand should be an entity
2020-02-18 16:00:02 +01:00
minetest.register_node ( " mcl_armor_stand:armor_stand " , {
2019-03-08 00:51:45 +01:00
description = S ( " Armor Stand " ) ,
2020-03-08 03:18:47 +01:00
_tt_help = S ( " Displays pieces of armor " ) ,
2019-03-08 00:51:45 +01:00
_doc_items_longdesc = S ( " An armor stand is a decorative object which can display different pieces of armor. Anything which players can wear as armor can also be put on an armor stand. " ) ,
2019-03-16 00:07:44 +01:00
_doc_items_usagehelp = S ( " Just place an armor item on the armor stand. To take the top piece of armor from the armor stand, select your hand and use the place key on the armor stand. " ) ,
2017-01-06 04:23:11 +01:00
drawtype = " mesh " ,
mesh = " 3d_armor_stand.obj " ,
2017-01-06 04:41:48 +01:00
inventory_image = " 3 d_armor_stand_item.png " ,
2017-06-10 15:18:48 +02:00
wield_image = " 3d_armor_stand_item.png " ,
2017-06-11 14:21:52 +02:00
tiles = { " default_wood.png " , " mcl_stairs_stone_slab_top.png " } ,
2017-01-06 04:23:11 +01:00
paramtype = " light " ,
paramtype2 = " facedir " ,
walkable = false ,
2017-05-30 17:18:19 +02:00
is_ground_content = false ,
2017-01-16 23:34:40 +01:00
stack_max = 16 ,
2017-01-06 04:23:11 +01:00
selection_box = {
type = " fixed " ,
fixed = { - 0.5 , - 0.5 , - 0.5 , 0.5 , 1.4 , 0.5 }
} ,
2019-03-09 07:01:12 +01:00
-- TODO: This should be breakable by 2 quick punches
2019-03-09 08:40:52 +01:00
groups = { handy = 1 , deco_block = 1 , dig_by_piston = 1 , attached_node = 1 } ,
2017-02-27 18:32:35 +01:00
_mcl_hardness = 2 ,
2017-02-11 18:46:23 +01:00
sounds = mcl_sounds.node_sound_wood_defaults ( ) ,
2017-01-06 04:23:11 +01:00
on_construct = function ( pos )
local meta = minetest.get_meta ( pos )
local inv = meta : get_inventory ( )
for _ , element in pairs ( elements ) do
inv : set_size ( " armor_ " .. element , 1 )
end
end ,
2017-06-11 14:16:22 +02:00
-- Drop all armor on the ground when it got destroyed
on_destruct = drop_armor ,
2017-06-11 15:31:14 +02:00
-- Put piece of armor on armor stand, or take one away
2017-02-19 02:09:49 +01:00
on_rightclick = function ( pos , node , clicker , itemstack , pointed_thing )
2019-02-08 21:59:01 +01:00
local protname = clicker : get_player_name ( )
if minetest.is_protected ( pos , protname ) then
minetest.record_protection_violation ( pos , protname )
2019-02-08 22:23:26 +01:00
return itemstack
2019-02-08 21:59:01 +01:00
end
2019-02-18 23:55:18 +01:00
local inv = minetest.get_inventory ( { type = " node " , pos = pos } )
if not inv then
return itemstack
end
2017-02-19 02:09:49 +01:00
-- Check if player wields armor
local name = itemstack : get_name ( )
local list
for e = 1 , # elements do
local g = minetest.get_item_group ( name , " armor_ " .. elements [ e ] )
if g ~= nil and g ~= 0 then
list = " armor_ " .. elements [ e ]
break
end
end
-- If player wields armor, put it on armor stand
local wielditem = clicker : get_wielded_item ( )
if list then
2017-06-11 15:31:14 +02:00
-- ... but only if the slot is free
2017-11-03 00:01:15 +01:00
local single_item = ItemStack ( itemstack )
single_item : set_count ( 1 )
2017-06-11 15:31:14 +02:00
if inv : is_empty ( list ) then
inv : add_item ( list , single_item )
2020-02-18 22:33:58 +01:00
armor : play_equip_sound ( single_item , nil , pos )
2017-02-19 02:09:49 +01:00
update_entity ( pos )
itemstack : take_item ( )
2019-02-08 22:23:26 +01:00
return itemstack
2017-02-19 02:09:49 +01:00
end
2017-06-11 21:08:19 +02:00
end
-- Take armor from stand if player has a free hand or wields the same armor type (if stackable)
for e = 1 , # elements do
local stand_armor = inv : get_stack ( " armor_ " .. elements [ e ] , 1 )
if not stand_armor : is_empty ( ) then
local pinv = clicker : get_inventory ( )
local taken = false
-- Empty hand
if wielditem : get_name ( ) == " " then
2017-02-19 02:09:49 +01:00
pinv : set_stack ( " main " , clicker : get_wield_index ( ) , stand_armor )
2017-06-11 21:08:19 +02:00
taken = true
-- Stackable armor type (if not already full). This is the case for e.g. mob heads.
-- This is done purely for convenience.
elseif ( wielditem : get_name ( ) == stand_armor : get_name ( ) and wielditem : get_count ( ) < wielditem : get_stack_max ( ) ) then
wielditem : set_count ( wielditem : get_count ( ) + 1 )
pinv : set_stack ( " main " , clicker : get_wield_index ( ) , wielditem )
taken = true
end
if taken then
2020-02-18 22:33:58 +01:00
armor : play_equip_sound ( stand_armor , nil , pos , true )
2017-02-19 02:09:49 +01:00
stand_armor : take_item ( )
inv : set_stack ( " armor_ " .. elements [ e ] , 1 , stand_armor )
end
2019-02-18 23:55:18 +01:00
update_entity ( pos )
2017-06-11 21:08:19 +02:00
return clicker : get_wielded_item ( )
2017-02-19 02:09:49 +01:00
end
end
2019-02-18 23:55:18 +01:00
update_entity ( pos )
2017-02-19 02:09:49 +01:00
return itemstack
end ,
2017-01-06 04:23:11 +01:00
after_place_node = function ( pos )
2020-02-18 16:00:02 +01:00
minetest.add_entity ( pos , " mcl_armor_stand:armor_entity " )
2017-01-06 04:23:11 +01:00
end ,
2019-02-08 21:59:01 +01:00
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
end
2017-01-06 04:23:11 +01:00
local def = stack : get_definition ( ) or { }
local groups = def.groups or { }
if groups [ listname ] then
return 1
end
return 0
end ,
2019-02-08 21:59:01 +01:00
allow_metadata_inventory_move = function ( )
2017-01-06 04:23:11 +01:00
return 0
end ,
on_metadata_inventory_put = function ( pos )
update_entity ( pos )
end ,
on_metadata_inventory_take = function ( pos )
update_entity ( pos )
end ,
after_destruct = function ( pos )
update_entity ( pos )
end ,
2021-01-06 12:48:39 +01:00
on_blast = function ( pos , _ , do_drop )
2017-01-06 04:23:11 +01:00
local object = get_stand_object ( pos )
if object then
object : remove ( )
end
minetest.after ( 1 , function ( pos )
update_entity ( pos )
end , pos )
2021-01-06 12:48:39 +01:00
minetest.remove_node ( pos )
if do_drop then
minetest.add_item ( pos , " mcl_armor_stand:armor_stand " )
end
2017-01-06 04:23:11 +01:00
end ,
2019-12-09 19:41:10 +01:00
on_rotate = function ( pos , node , user , mode )
if mode == screwdriver.ROTATE_FACE then
node.param2 = ( node.param2 + 1 ) % 4
minetest.swap_node ( pos , node )
update_entity ( pos )
return true
end
return false
end ,
2017-01-06 04:23:11 +01:00
} )
2020-02-18 16:00:02 +01:00
minetest.register_entity ( " mcl_armor_stand:armor_entity " , {
2017-01-06 04:23:11 +01:00
physical = true ,
visual = " mesh " ,
mesh = " 3d_armor_entity.obj " ,
visual_size = { x = 1 , y = 1 } ,
2017-03-21 04:01:32 +01:00
collisionbox = { - 0.1 , - 0.4 , - 0.1 , 0.1 , 1.3 , 0.1 } ,
2019-03-07 03:53:06 +01:00
pointable = false ,
2020-02-17 17:46:25 +01:00
textures = { " blank.png " } ,
2017-01-06 04:23:11 +01:00
pos = nil ,
timer = 0 ,
on_activate = function ( self )
2019-02-01 06:33:07 +01:00
local pos = self.object : get_pos ( )
2017-02-14 20:22:34 +01:00
self.object : set_armor_groups ( { immortal = 1 } )
2017-01-06 04:23:11 +01:00
if pos then
self.pos = vector.round ( pos )
update_entity ( pos )
end
end ,
on_step = function ( self , dtime )
if not self.pos then
return
end
self.timer = self.timer + dtime
if self.timer > 1 then
self.timer = 0
2019-02-01 06:33:07 +01:00
local pos = self.object : get_pos ( )
2017-01-06 04:23:11 +01:00
if pos then
if vector.equals ( vector.round ( pos ) , self.pos ) then
return
end
end
update_entity ( self.pos )
self.object : remove ( )
end
end ,
} )
2019-02-18 23:55:18 +01:00
-- FIXME: Armor helper entity can get destroyed by /clearobjects
minetest.register_lbm ( {
label = " Respawn armor stand entities " ,
2020-02-18 16:00:02 +01:00
name = " mcl_armor_stand:respawn_entities " ,
nodenames = { " mcl_armor_stand:armor_stand " } ,
2019-02-18 23:55:18 +01:00
run_at_every_load = true ,
action = function ( pos , node )
update_entity ( pos , node )
end ,
} )
2017-01-06 04:23:11 +01:00
minetest.register_craft ( {
2020-02-18 16:00:02 +01:00
output = " mcl_armor_stand:armor_stand " ,
2017-01-06 04:23:11 +01:00
recipe = {
2017-01-31 23:32:56 +01:00
{ " mcl_core:stick " , " mcl_core:stick " , " mcl_core:stick " } ,
{ " " , " mcl_core:stick " , " " } ,
2017-06-05 18:40:56 +02:00
{ " mcl_core:stick " , " mcl_stairs:slab_stone " , " mcl_core:stick " } ,
2017-01-06 04:23:11 +01:00
}
} )
2020-02-18 16:13:37 +01:00
-- Legacy handling
2020-02-18 16:00:02 +01:00
minetest.register_alias ( " 3d_armor_stand:armor_stand " , " mcl_armor_stand:armor_stand " )
2020-02-18 16:13:37 +01:00
minetest.register_entity ( " :3d_armor_stand:armor_entity " , {
on_activate = function ( self )
minetest.log ( " action " , " [mcl_armor_stand] Removing legacy entity: 3d_armor_stand:armor_entity " )
self.object : remove ( )
end ,
static_save = false ,
} )