mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2024-11-22 10:31:06 +01:00
Integrate armor stand
This commit is contained in:
parent
f0d7715080
commit
4f0bb444fe
3 changed files with 85 additions and 206 deletions
|
@ -422,10 +422,13 @@ end
|
||||||
function mcl_util.call_on_rightclick(itemstack, player, pointed_thing)
|
function mcl_util.call_on_rightclick(itemstack, player, pointed_thing)
|
||||||
-- Call on_rightclick if the pointed node defines it
|
-- Call on_rightclick if the pointed node defines it
|
||||||
if pointed_thing and pointed_thing.type == "node" then
|
if pointed_thing and pointed_thing.type == "node" then
|
||||||
local node = minetest.get_node(pointed_thing.under)
|
local pos = pointed_thing.under
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
if player and not player:get_player_control().sneak then
|
if player and not player:get_player_control().sneak then
|
||||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
local nodedef = minetest.registered_nodes[node.name]
|
||||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack
|
local on_rightclick = nodedef and nodedef.on_rightclick
|
||||||
|
if on_rightclick then
|
||||||
|
return on_rightclick(pos, node, player, itemstack, pointed_thing) or itemstack
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,16 +36,30 @@ function mcl_armor.on_unequip(itemstack, obj)
|
||||||
mcl_armor.update(obj)
|
mcl_armor.update(obj)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_armor.equip(itemstack, obj)
|
function mcl_armor.equip(itemstack, obj, swap)
|
||||||
local def = itemstack:get_definition()
|
local def = itemstack:get_definition()
|
||||||
|
|
||||||
|
if not def then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
local element = mcl_armor.elements[def._mcl_armor_element or ""]
|
local element = mcl_armor.elements[def._mcl_armor_element or ""]
|
||||||
local inv = mcl_util.get_inventory(obj)
|
local inv = mcl_util.get_inventory(obj)
|
||||||
|
|
||||||
if element and inv then
|
if element and inv then
|
||||||
if inv:get_stack("armor", element.index):is_empty() then
|
local old_stack = inv:get_stack("armor", element.index)
|
||||||
local equipping_item = itemstack:take_item()
|
local new_stack
|
||||||
inv:set_stack("armor", element.index, equipping_item)
|
|
||||||
mcl_armor.on_equip(equipping_item, obj)
|
if swap then
|
||||||
|
new_stack = itemstack
|
||||||
|
itemstack = old_stack
|
||||||
|
else
|
||||||
|
new_stack = itemstack:take_item()
|
||||||
|
end
|
||||||
|
|
||||||
|
if swap or old_stack:is_empty() then
|
||||||
|
inv:set_stack("armor", element.index, new_stack)
|
||||||
|
mcl_armor.on_equip(new_stack, obj)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,60 +1,41 @@
|
||||||
local S = minetest.get_translator("mcl_armor_stand")
|
local S = minetest.get_translator("mcl_armor_stand")
|
||||||
|
|
||||||
local elements = {"head", "torso", "legs", "feet"}
|
-- Spawn a stand entity
|
||||||
|
local function spawn_stand_entity(pos, node)
|
||||||
local function get_stand_object(pos)
|
local luaentity = minetest.add_entity(pos, "mcl_armor_stand:armor_entity"):get_luaentity()
|
||||||
local object = nil
|
luaentity:update_rotation(node or minetest.get_node(pos))
|
||||||
local objects = minetest.get_objects_inside_radius(pos, 0.5) or {}
|
return luaentity
|
||||||
for _, obj in pairs(objects) do
|
|
||||||
local ent = obj:get_luaentity()
|
|
||||||
if ent then
|
|
||||||
if ent.name == "mcl_armor_stand:armor_entity" then
|
|
||||||
-- Remove duplicates
|
|
||||||
if object then
|
|
||||||
obj:remove()
|
|
||||||
else
|
|
||||||
object = obj
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return object
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function update_entity(pos, node)
|
-- Find a stand entity or spawn one
|
||||||
local node = node or minetest.get_node(pos)
|
local function get_stand_entity(pos, node)
|
||||||
local object = get_stand_object(pos)
|
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 0)) do
|
||||||
if object then
|
local luaentity = obj:get_luaentity()
|
||||||
if not string.find(node.name, "mcl_armor_stand:") then
|
if luaentity and luaentity.name == "mcl_armor_stand:armor_entity" then
|
||||||
object:remove()
|
return luaentity
|
||||||
return
|
|
||||||
end
|
end
|
||||||
else
|
|
||||||
object = minetest.add_entity(pos, "mcl_armor_stand:armor_entity")
|
|
||||||
end
|
end
|
||||||
if object then
|
return spawn_stand_entity(pos, node)
|
||||||
local yaw = 0
|
end
|
||||||
if node.param2 then
|
|
||||||
local rot = node.param2 % 4
|
-- Migrate the old inventory format
|
||||||
if rot == 1 then
|
local function migrate_inventory(inv)
|
||||||
yaw = 3 * math.pi / 2
|
inv:set_size("armor", 5)
|
||||||
elseif rot == 2 then
|
local lists = inv:get_lists()
|
||||||
yaw = math.pi
|
for name, element in pairs(mcl_armor.elements) do
|
||||||
elseif rot == 3 then
|
local listname = "armor_" .. name
|
||||||
yaw = math.pi / 2
|
local list = lists[listname]
|
||||||
end
|
if list then
|
||||||
|
inv:set_stack("armor", element.index, list[1])
|
||||||
|
inv:set_size(listname, 0)
|
||||||
end
|
end
|
||||||
object:set_yaw(yaw)
|
|
||||||
mcl_armor.update(object)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Drop all armor of the armor stand on the ground
|
-- Drop all armor on the ground when it got destroyed
|
||||||
local drop_armor = function(pos)
|
local function drop_inventory(pos)
|
||||||
local meta = minetest.get_meta(pos)
|
local inv = minetest.get_meta(pos):get_inventory()
|
||||||
local inv = meta:get_inventory()
|
for _, stack in pairs(inv:get_list("armor")) do
|
||||||
for _, element in pairs(elements) do
|
|
||||||
local stack = inv:get_stack("armor_"..element, 1)
|
|
||||||
if not stack:is_empty() then
|
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}
|
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)
|
minetest.add_item(p, stack)
|
||||||
|
@ -87,136 +68,27 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
|
||||||
_mcl_hardness = 2,
|
_mcl_hardness = 2,
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
on_construct = function(pos)
|
on_construct = function(pos)
|
||||||
local meta = minetest.get_meta(pos)
|
spawn_stand_entity(pos)
|
||||||
local inv = meta:get_inventory()
|
end,
|
||||||
for _, element in pairs(elements) do
|
on_destruct = function(pos)
|
||||||
inv:set_size("armor_"..element, 1)
|
drop_inventory(pos)
|
||||||
end
|
|
||||||
end,
|
end,
|
||||||
-- Drop all armor on the ground when it got destroyed
|
|
||||||
on_destruct = drop_armor,
|
|
||||||
-- Put piece of armor on armor stand, or take one away
|
|
||||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||||
|
print(pos, node, clicker, itemstack, pointed_thing)
|
||||||
local protname = clicker:get_player_name()
|
local protname = clicker:get_player_name()
|
||||||
|
|
||||||
if minetest.is_protected(pos, protname) then
|
if minetest.is_protected(pos, protname) then
|
||||||
minetest.record_protection_violation(pos, protname)
|
minetest.record_protection_violation(pos, protname)
|
||||||
return itemstack
|
return itemstack
|
||||||
end
|
end
|
||||||
|
|
||||||
local inv = minetest.get_inventory({type = "node", pos = pos})
|
return mcl_armor.equip(itemstack, get_stand_entity(pos, node).object, true)
|
||||||
if not inv then
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 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
|
|
||||||
-- ... but only if the slot is free
|
|
||||||
local single_item = ItemStack(itemstack)
|
|
||||||
single_item:set_count(1)
|
|
||||||
if inv:is_empty(list) then
|
|
||||||
inv:add_item(list, single_item)
|
|
||||||
mcl_armor.play_equip_sound(single_item, nil, pos)
|
|
||||||
update_entity(pos)
|
|
||||||
itemstack:take_item()
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
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
|
|
||||||
pinv:set_stack("main", clicker:get_wield_index(), stand_armor)
|
|
||||||
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
|
|
||||||
mcl_armor.play_equip_sound(stand_armor, nil, pos, true)
|
|
||||||
stand_armor:take_item()
|
|
||||||
inv:set_stack("armor_" .. elements[e], 1, stand_armor)
|
|
||||||
end
|
|
||||||
update_entity(pos)
|
|
||||||
return clicker:get_wielded_item()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
update_entity(pos)
|
|
||||||
return itemstack
|
|
||||||
end,
|
|
||||||
after_place_node = function(pos)
|
|
||||||
minetest.add_entity(pos, "mcl_armor_stand:armor_entity")
|
|
||||||
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
|
|
||||||
end
|
|
||||||
local def = stack:get_definition() or {}
|
|
||||||
local groups = def.groups or {}
|
|
||||||
if groups[listname] then
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
return 0
|
|
||||||
end,
|
|
||||||
allow_metadata_inventory_move = function()
|
|
||||||
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, _, do_drop)
|
|
||||||
local object = get_stand_object(pos)
|
|
||||||
if object then
|
|
||||||
object:remove()
|
|
||||||
end
|
|
||||||
minetest.after(1, function(pos)
|
|
||||||
update_entity(pos)
|
|
||||||
end, pos)
|
|
||||||
minetest.remove_node(pos)
|
|
||||||
if do_drop then
|
|
||||||
minetest.add_item(pos, "mcl_armor_stand:armor_stand")
|
|
||||||
end
|
|
||||||
end,
|
end,
|
||||||
on_rotate = function(pos, node, user, mode)
|
on_rotate = function(pos, node, user, mode)
|
||||||
if mode == screwdriver.ROTATE_FACE then
|
if mode == screwdriver.ROTATE_FACE then
|
||||||
node.param2 = (node.param2 + 1) % 4
|
node.param2 = (node.param2 + 1) % 4
|
||||||
minetest.swap_node(pos, node)
|
minetest.swap_node(pos, node)
|
||||||
update_entity(pos)
|
get_stand_entity(pos, node):update_rotation(node)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
|
@ -224,52 +96,43 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_entity("mcl_armor_stand:armor_entity", {
|
minetest.register_entity("mcl_armor_stand:armor_entity", {
|
||||||
physical = true,
|
initial_properties = {
|
||||||
visual = "mesh",
|
physical = true,
|
||||||
mesh = "3d_armor_entity.obj",
|
visual = "mesh",
|
||||||
visual_size = {x=1, y=1},
|
mesh = "3d_armor_entity.obj",
|
||||||
collisionbox = {-0.1,-0.4,-0.1, 0.1,1.3,0.1},
|
visual_size = {x=1, y=1},
|
||||||
pointable = false,
|
collisionbox = {-0.1,-0.4,-0.1, 0.1,1.3,0.1},
|
||||||
textures = {"blank.png"},
|
pointable = false,
|
||||||
pos = nil,
|
textures = {"blank.png"},
|
||||||
timer = 0,
|
timer = 0,
|
||||||
on_activate = function(self, staticdata)
|
static_save = false,
|
||||||
self.object:set_armor_groups({immortal=1})
|
},
|
||||||
local pos = self.object:get_pos()
|
on_activate = function(self)
|
||||||
self.pos = vector.round(pos)
|
self.object:set_armor_groups({immortal = 1})
|
||||||
self.inventory = minetest.get_meta(pos):get_inventory()
|
self.node_pos = vector.round(self.object:get_pos())
|
||||||
update_entity(pos)
|
self.inventory = minetest.get_meta(self.node_pos):get_inventory()
|
||||||
|
migrate_inventory(self.inventory)
|
||||||
|
end,
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
if minetest.get_node(self.node_pos).name ~= "mcl_armor_stand:armor_stand" then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
update_armor = function(self, info)
|
update_armor = function(self, info)
|
||||||
self.object:set_properties({textures = {info.texture}})
|
self.object:set_properties({textures = {info.texture}})
|
||||||
end,
|
end,
|
||||||
on_step = function(self, dtime)
|
update_rotation = function(self, node)
|
||||||
if not self.pos then
|
self.object:set_yaw(minetest.dir_to_yaw(minetest.facedir_to_dir(node.param2)))
|
||||||
return
|
|
||||||
end
|
|
||||||
self.timer = self.timer + dtime
|
|
||||||
if self.timer > 1 then
|
|
||||||
self.timer = 0
|
|
||||||
local pos = self.object:get_pos()
|
|
||||||
if pos then
|
|
||||||
if vector.equals(vector.round(pos), self.pos) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
update_entity(self.pos)
|
|
||||||
self.object:remove()
|
|
||||||
end
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- FIXME: Armor helper entity can get destroyed by /clearobjects
|
|
||||||
minetest.register_lbm({
|
minetest.register_lbm({
|
||||||
label = "Respawn armor stand entities",
|
label = "Respawn armor stand entities",
|
||||||
name = "mcl_armor_stand:respawn_entities",
|
name = "mcl_armor_stand:respawn_entities",
|
||||||
nodenames = {"mcl_armor_stand:armor_stand"},
|
nodenames = {"mcl_armor_stand:armor_stand"},
|
||||||
run_at_every_load = true,
|
run_at_every_load = true,
|
||||||
action = function(pos, node)
|
action = function(pos, node)
|
||||||
update_entity(pos, node)
|
spawn_stand_entity(pos, node)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -282,7 +145,6 @@ minetest.register_craft({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
-- Legacy handling
|
-- Legacy handling
|
||||||
minetest.register_alias("3d_armor_stand:armor_stand", "mcl_armor_stand:armor_stand")
|
minetest.register_alias("3d_armor_stand:armor_stand", "mcl_armor_stand:armor_stand")
|
||||||
minetest.register_entity(":3d_armor_stand:armor_entity", {
|
minetest.register_entity(":3d_armor_stand:armor_entity", {
|
||||||
|
|
Loading…
Reference in a new issue