mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2024-12-23 08:29:34 +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)
|
||||
-- Call on_rightclick if the pointed node defines it
|
||||
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 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, user, itemstack) or itemstack
|
||||
local nodedef = minetest.registered_nodes[node.name]
|
||||
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
|
||||
|
|
|
@ -36,16 +36,30 @@ function mcl_armor.on_unequip(itemstack, obj)
|
|||
mcl_armor.update(obj)
|
||||
end
|
||||
|
||||
function mcl_armor.equip(itemstack, obj)
|
||||
function mcl_armor.equip(itemstack, obj, swap)
|
||||
local def = itemstack:get_definition()
|
||||
|
||||
if not def then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local element = mcl_armor.elements[def._mcl_armor_element or ""]
|
||||
local inv = mcl_util.get_inventory(obj)
|
||||
|
||||
if element and inv then
|
||||
if inv:get_stack("armor", element.index):is_empty() then
|
||||
local equipping_item = itemstack:take_item()
|
||||
inv:set_stack("armor", element.index, equipping_item)
|
||||
mcl_armor.on_equip(equipping_item, obj)
|
||||
local old_stack = inv:get_stack("armor", element.index)
|
||||
local new_stack
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -1,60 +1,41 @@
|
|||
local S = minetest.get_translator("mcl_armor_stand")
|
||||
|
||||
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 == "mcl_armor_stand:armor_entity" then
|
||||
-- Remove duplicates
|
||||
if object then
|
||||
obj:remove()
|
||||
else
|
||||
object = obj
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return object
|
||||
-- Spawn a stand entity
|
||||
local function spawn_stand_entity(pos, node)
|
||||
local luaentity = minetest.add_entity(pos, "mcl_armor_stand:armor_entity"):get_luaentity()
|
||||
luaentity:update_rotation(node or minetest.get_node(pos))
|
||||
return luaentity
|
||||
end
|
||||
|
||||
local function update_entity(pos, node)
|
||||
local node = node or minetest.get_node(pos)
|
||||
local object = get_stand_object(pos)
|
||||
if object then
|
||||
if not string.find(node.name, "mcl_armor_stand:") then
|
||||
object:remove()
|
||||
return
|
||||
-- Find a stand entity or spawn one
|
||||
local function get_stand_entity(pos, node)
|
||||
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 0)) do
|
||||
local luaentity = obj:get_luaentity()
|
||||
if luaentity and luaentity.name == "mcl_armor_stand:armor_entity" then
|
||||
return luaentity
|
||||
end
|
||||
else
|
||||
object = minetest.add_entity(pos, "mcl_armor_stand:armor_entity")
|
||||
end
|
||||
if object then
|
||||
local yaw = 0
|
||||
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
|
||||
return spawn_stand_entity(pos, node)
|
||||
end
|
||||
|
||||
-- Migrate the old inventory format
|
||||
local function migrate_inventory(inv)
|
||||
inv:set_size("armor", 5)
|
||||
local lists = inv:get_lists()
|
||||
for name, element in pairs(mcl_armor.elements) do
|
||||
local listname = "armor_" .. name
|
||||
local list = lists[listname]
|
||||
if list then
|
||||
inv:set_stack("armor", element.index, list[1])
|
||||
inv:set_size(listname, 0)
|
||||
end
|
||||
object:set_yaw(yaw)
|
||||
mcl_armor.update(object)
|
||||
end
|
||||
end
|
||||
|
||||
-- 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)
|
||||
-- Drop all armor on the ground when it got destroyed
|
||||
local function drop_inventory(pos)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
for _, stack in pairs(inv:get_list("armor")) do
|
||||
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)
|
||||
|
@ -87,136 +68,27 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
|
|||
_mcl_hardness = 2,
|
||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||
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
|
||||
spawn_stand_entity(pos)
|
||||
end,
|
||||
on_destruct = function(pos)
|
||||
drop_inventory(pos)
|
||||
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)
|
||||
print(pos, node, clicker, itemstack, pointed_thing)
|
||||
local protname = clicker:get_player_name()
|
||||
|
||||
if minetest.is_protected(pos, protname) then
|
||||
minetest.record_protection_violation(pos, protname)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local inv = minetest.get_inventory({type = "node", pos = pos})
|
||||
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
|
||||
return mcl_armor.equip(itemstack, get_stand_entity(pos, node).object, true)
|
||||
end,
|
||||
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)
|
||||
get_stand_entity(pos, node):update_rotation(node)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
|
@ -224,52 +96,43 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
|
|||
})
|
||||
|
||||
minetest.register_entity("mcl_armor_stand:armor_entity", {
|
||||
physical = true,
|
||||
visual = "mesh",
|
||||
mesh = "3d_armor_entity.obj",
|
||||
visual_size = {x=1, y=1},
|
||||
collisionbox = {-0.1,-0.4,-0.1, 0.1,1.3,0.1},
|
||||
pointable = false,
|
||||
textures = {"blank.png"},
|
||||
pos = nil,
|
||||
timer = 0,
|
||||
on_activate = function(self, staticdata)
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
local pos = self.object:get_pos()
|
||||
self.pos = vector.round(pos)
|
||||
self.inventory = minetest.get_meta(pos):get_inventory()
|
||||
update_entity(pos)
|
||||
initial_properties = {
|
||||
physical = true,
|
||||
visual = "mesh",
|
||||
mesh = "3d_armor_entity.obj",
|
||||
visual_size = {x=1, y=1},
|
||||
collisionbox = {-0.1,-0.4,-0.1, 0.1,1.3,0.1},
|
||||
pointable = false,
|
||||
textures = {"blank.png"},
|
||||
timer = 0,
|
||||
static_save = false,
|
||||
},
|
||||
on_activate = function(self)
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
self.node_pos = vector.round(self.object:get_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,
|
||||
update_armor = function(self, info)
|
||||
self.object:set_properties({textures = {info.texture}})
|
||||
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
|
||||
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
|
||||
update_rotation = function(self, node)
|
||||
self.object:set_yaw(minetest.dir_to_yaw(minetest.facedir_to_dir(node.param2)))
|
||||
end,
|
||||
})
|
||||
|
||||
-- FIXME: Armor helper entity can get destroyed by /clearobjects
|
||||
minetest.register_lbm({
|
||||
label = "Respawn armor stand entities",
|
||||
name = "mcl_armor_stand:respawn_entities",
|
||||
nodenames = {"mcl_armor_stand:armor_stand"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
update_entity(pos, node)
|
||||
spawn_stand_entity(pos, node)
|
||||
end,
|
||||
})
|
||||
|
||||
|
@ -282,7 +145,6 @@ minetest.register_craft({
|
|||
}
|
||||
})
|
||||
|
||||
|
||||
-- Legacy handling
|
||||
minetest.register_alias("3d_armor_stand:armor_stand", "mcl_armor_stand:armor_stand")
|
||||
minetest.register_entity(":3d_armor_stand:armor_entity", {
|
||||
|
|
Loading…
Reference in a new issue