Crafter/mods/main/falling.lua

141 lines
3.8 KiB
Lua

--
-- Falling entity ("rewrite"")
--
minetest.register_entity(":__builtin:falling_node", {
initial_properties = {
visual = "wielditem",
visual_size = {x = 0.667, y = 0.667},
textures = {},
physical = true,
is_visible = false,
collide_with_objects = false,
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
},
node = {},
meta = {},
set_node = function(self, node, meta)
self.node = node
meta = meta or {}
if type(meta.to_table) == "function" then
meta = meta:to_table()
end
for _, list in pairs(meta.inventory or {}) do
for i, stack in pairs(list) do
if type(stack) == "userdata" then
list[i] = stack:to_string()
end
end
end
self.meta = meta
self.object:set_properties({
is_visible = true,
textures = {node.name},
})
end,
get_staticdata = function(self)
local ds = {
node = self.node,
meta = self.meta,
}
return minetest.serialize(ds)
end,
on_activate = function(self, staticdata)
self.object:set_armor_groups({immortal = 1})
local ds = minetest.deserialize(staticdata)
if ds and ds.node then
self:set_node(ds.node, ds.meta)
elseif ds then
self:set_node(ds)
elseif staticdata ~= "" then
self:set_node({name = staticdata})
end
end,
on_step = function(self, dtime)
-- Set gravity
local acceleration = self.object:get_acceleration()
if not vector.equals(acceleration, {x = 0, y = -10, z = 0}) then
self.object:set_acceleration({x = 0, y = -10, z = 0})
end
-- Turn to actual node when colliding with ground, or continue to move
local pos = self.object:get_pos()
-- Position of bottom center point
local bcp = {x = pos.x, y = pos.y - 0.7, z = pos.z}
-- 'bcn' is nil for unloaded nodes
local bcn = minetest.get_node_or_nil(bcp)
-- Delete on contact with ignore at world edges
if bcn and bcn.name == "ignore" then
self.object:remove()
return
end
local bcd = bcn and minetest.registered_nodes[bcn.name]
if bcn and
(not bcd or bcd.walkable or
(minetest.get_item_group(self.node.name, "float") ~= 0 and
bcd.liquidtype ~= "none")) then
if bcd and bcd.leveled and
bcn.name == self.node.name then
local addlevel = self.node.level
if not addlevel or addlevel <= 0 then
addlevel = bcd.leveled
end
if minetest.add_node_level(bcp, addlevel) == 0 then
self.object:remove()
return
end
elseif bcd and bcd.buildable_to and
(minetest.get_item_group(self.node.name, "float") == 0 or
bcd.liquidtype == "none") then
minetest.remove_node(bcp)
return
end
local np = {x = bcp.x, y = bcp.y + 1, z = bcp.z}
-- Check what's here
local n2 = minetest.get_node(np)
local nd = minetest.registered_nodes[n2.name]
-- If it's not air or liquid, remove node and replace it with
-- it's drops
if n2.name ~= "air" and (not nd or nd.liquidtype == "none") then
minetest.remove_node(np)
if nd and nd.buildable_to == false then
-- Add dropped items
local drops = minetest.get_node_drops(n2, "")
for _, dropped_item in pairs(drops) do
minetest.add_item(np, dropped_item)
end
end
-- Run script hook
for _, callback in pairs(minetest.registered_on_dignodes) do
callback(np, n2)
end
end
-- Create node and remove entity
local def = minetest.registered_nodes[self.node.name]
if def then
minetest.add_node(np, self.node)
if self.meta then
local meta = minetest.get_meta(np)
meta:from_table(self.meta)
end
if def.sounds and def.sounds.fall then
minetest.sound_play(def.sounds.fall, {pos = np}, true)
end
end
self.object:remove()
minetest.check_for_falling(np)
return
end
local vel = self.object:get_velocity()
if vector.equals(vel, {x = 0, y = 0, z = 0}) then
local npos = self.object:get_pos()
self.object:set_pos(vector.round(npos))
end
end
})