2017-01-06 05:23:11 +02: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
if ent.name == " 3d_armor_stand:armor_entity " then
-- 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
if not string.find ( node.name , " 3d_armor_stand: " ) then
object : remove ( )
return
end
else
object = minetest.add_entity ( pos , " 3d_armor_stand:armor_entity " )
end
if object then
local texture = " 3d_armor_trans.png "
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 " "
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
object : setyaw ( yaw )
object : set_properties ( { textures = { texture } } )
end
end
2017-06-11 15:16:22 +03: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
2017-12-05 15:09:39 +02:00
local on_rotate
if minetest.get_modpath ( " screwdriver " ) then
on_rotate = screwdriver.disallow
end
2017-02-27 19:32:35 +02:00
-- FIXME: The armor stand should be an entity
2017-01-06 05:23:11 +02:00
minetest.register_node ( " 3d_armor_stand:armor_stand " , {
2017-01-06 05:29:38 +02:00
description = " Armor Stand " ,
2017-06-11 23:06:07 +03:00
_doc_items_longdesc = " 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. " ,
2017-03-11 17:42:23 +02:00
_doc_items_usagehelp = " Hold an armor item in your hand and rightclick the armor stand to put it on the armor stand. To take a piece of armor from the armor stand, select your hand and rightclick the armor stand. You'll retrieve the first armor item from above. " ,
2017-01-06 05:23:11 +02:00
drawtype = " mesh " ,
mesh = " 3d_armor_stand.obj " ,
2017-01-06 05:41:48 +02:00
inventory_image = " 3d_armor_stand_item.png " ,
2017-06-10 16:18:48 +03:00
wield_image = " 3d_armor_stand_item.png " ,
2017-06-11 15:21:52 +03:00
tiles = { " default_wood.png " , " mcl_stairs_stone_slab_top.png " } ,
2017-01-06 05:23:11 +02:00
paramtype = " light " ,
paramtype2 = " facedir " ,
walkable = false ,
2017-05-30 18:18:19 +03:00
is_ground_content = false ,
2017-01-17 00:34:40 +02:00
stack_max = 16 ,
2017-01-06 05:23:11 +02:00
selection_box = {
type = " fixed " ,
fixed = { - 0.5 , - 0.5 , - 0.5 , 0.5 , 1.4 , 0.5 }
} ,
2017-02-27 19:32:35 +02:00
-- FIXME: This should be breakable by 2 quick punches
groups = { handy = 1 , deco_block = 1 } ,
_mcl_hardness = 2 ,
2017-02-11 19:46:23 +02:00
sounds = mcl_sounds.node_sound_wood_defaults ( ) ,
2017-01-06 05:23:11 +02: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 15:16:22 +03:00
-- Drop all armor on the ground when it got destroyed
on_destruct = drop_armor ,
2017-06-11 16:31:14 +03:00
-- Put piece of armor on armor stand, or take one away
2017-02-19 03:09:49 +02:00
on_rightclick = function ( pos , node , clicker , itemstack , pointed_thing )
2019-02-08 22:59:01 +02:00
local protname = clicker : get_player_name ( )
if minetest.is_protected ( pos , protname ) then
minetest.record_protection_violation ( pos , protname )
2019-02-08 23:23:26 +02:00
return itemstack
2019-02-08 22:59:01 +02:00
end
2019-02-19 00:55:18 +02:00
local inv = minetest.get_inventory ( { type = " node " , pos = pos } )
if not inv then
return itemstack
end
2017-02-19 03:09:49 +02: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 16:31:14 +03:00
-- ... but only if the slot is free
2017-11-03 01:01:15 +02:00
local single_item = ItemStack ( itemstack )
single_item : set_count ( 1 )
2017-06-11 16:31:14 +03:00
if inv : is_empty ( list ) then
inv : add_item ( list , single_item )
2017-02-19 03:09:49 +02:00
update_entity ( pos )
itemstack : take_item ( )
2019-02-08 23:23:26 +02:00
return itemstack
2017-02-19 03:09:49 +02:00
end
2017-06-11 22:08:19 +03: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 03:09:49 +02:00
pinv : set_stack ( " main " , clicker : get_wield_index ( ) , stand_armor )
2017-06-11 22:08:19 +03: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
2017-02-19 03:09:49 +02:00
stand_armor : take_item ( )
inv : set_stack ( " armor_ " .. elements [ e ] , 1 , stand_armor )
end
2019-02-19 00:55:18 +02:00
update_entity ( pos )
2017-06-11 22:08:19 +03:00
return clicker : get_wielded_item ( )
2017-02-19 03:09:49 +02:00
end
end
2019-02-19 00:55:18 +02:00
update_entity ( pos )
2017-02-19 03:09:49 +02:00
return itemstack
end ,
2017-01-06 05:23:11 +02:00
after_place_node = function ( pos )
minetest.add_entity ( pos , " 3d_armor_stand:armor_entity " )
end ,
2019-02-08 22:59:01 +02: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 05:23:11 +02: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 22:59:01 +02:00
allow_metadata_inventory_move = function ( )
2017-01-06 05:23:11 +02: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 ,
on_blast = function ( pos )
local object = get_stand_object ( pos )
if object then
object : remove ( )
end
minetest.after ( 1 , function ( pos )
update_entity ( pos )
end , pos )
end ,
2017-12-05 15:09:39 +02:00
on_rotate = on_rotate ,
2017-01-06 05:23:11 +02:00
} )
minetest.register_entity ( " 3d_armor_stand:armor_entity " , {
physical = true ,
visual = " mesh " ,
mesh = " 3d_armor_entity.obj " ,
visual_size = { x = 1 , y = 1 } ,
2017-03-21 05:01:32 +02:00
collisionbox = { - 0.1 , - 0.4 , - 0.1 , 0.1 , 1.3 , 0.1 } ,
2017-01-06 05:23:11 +02:00
textures = { " 3d_armor_trans.png " } ,
pos = nil ,
timer = 0 ,
on_activate = function ( self )
2019-02-01 07:33:07 +02:00
local pos = self.object : get_pos ( )
2017-02-14 21:22:34 +02:00
self.object : set_armor_groups ( { immortal = 1 } )
2017-01-06 05:23:11 +02: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 07:33:07 +02:00
local pos = self.object : get_pos ( )
2017-01-06 05:23:11 +02: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-19 00:55:18 +02:00
-- FIXME: Armor helper entity can get destroyed by /clearobjects
minetest.register_lbm ( {
label = " Respawn armor stand entities " ,
name = " 3d_armor_stand:respawn_entities " ,
nodenames = { " 3d_armor_stand:armor_stand " } ,
run_at_every_load = true ,
action = function ( pos , node )
update_entity ( pos , node )
end ,
} )
2017-03-21 05:03:33 +02:00
if minetest.get_modpath ( " doc_identifier " ) ~= nil then
doc.sub . identifier.register_object ( " 3d_armor_stand:armor_entity " , " nodes " , " 3d_armor_stand:armor_stand " )
end
2017-01-06 05:23:11 +02:00
minetest.register_craft ( {
output = " 3d_armor_stand:armor_stand " ,
recipe = {
2017-02-01 00:32:56 +02:00
{ " mcl_core:stick " , " mcl_core:stick " , " mcl_core:stick " } ,
{ " " , " mcl_core:stick " , " " } ,
2017-06-05 19:40:56 +03:00
{ " mcl_core:stick " , " mcl_stairs:slab_stone " , " mcl_core:stick " } ,
2017-01-06 05:23:11 +02:00
}
} )