moresnow/soft_falling.lua

107 lines
3.4 KiB
Lua

-- moresnow shall not crush plants (buildable_to is set) when falling
-- on them - snow is not like sand or gravel (at least when falling slowly)
local old_try_place = minetest.registered_entities["__builtin:falling_node"].try_place
minetest.registered_entities["__builtin:falling_node"].try_place = function(self, bcp, bcn)
if core.get_item_group(self.node.name, "soft_falling") == 0 then
return old_try_place(self, bcp, bcn)
end
return moresnow.new_try_place(self, bcp, bcn)
end
-- avoid cascades of dropping moresnow nodes that are actually sitting
-- perfectly well on buildable_to plants
local old_check_single_for_falling = core.check_single_for_falling
core.check_single_for_falling = function(p)
return moresnow.check_single_for_falling(p)
end
-- this is a only minimally modified copy of the function in builtin/game/falling.lua:
moresnow.new_try_place = function(self, bcp, bcn)
local bcd = core.registered_nodes[bcn.name]
-- Add levels if dropped on same leveled node
if bcd and bcd.paramtype2 == "leveled" and
bcn.name == self.node.name then
local addlevel = self.node.level
if (addlevel or 0) <= 0 then
addlevel = bcd.leveled
end
if core.add_node_level(bcp, addlevel) < addlevel then
return true
elseif bcd.buildable_to then
-- Node level has already reached max, don't place anything
return true
end
end
-- Decide if we're replacing the node or placing on top
local np = vector.copy(bcp)
if bcd and bcd.buildable_to and
(not self.floats or bcd.liquidtype == "none") then
core.remove_node(bcp)
else
np.y = np.y + 1
end
-- Check what's here
local n2 = core.get_node(np)
local nd = core.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
if nd and nd.buildable_to == false then
nd.on_dig(np, n2, nil)
-- If it's still there, it might be protected
if core.get_node(np).name == n2.name then
return false
end
else
if core.get_item_group(self.node.name, "soft_falling") == 0 then
core.remove_node(np)
else
-- do not crush the plant below!
np.y = np.y + 1
end
end
end
-- Create node
local def = core.registered_nodes[self.node.name]
if def then
core.add_node(np, self.node)
if self.meta then
core.get_meta(np):from_table(self.meta)
end
if def.sounds and def.sounds.place then
core.sound_play(def.sounds.place, {pos = np}, true)
end
end
core.check_for_falling(np)
return true
end
-- this is a only minimally modified copy of the function in builtin/game/falling.lua:
moresnow.check_single_for_falling = function(p)
local n = core.get_node(p)
if core.get_item_group(n.name, "falling_node") ~= 0 then
local p_bottom = vector.offset(p, 0, -1, 0)
-- Only spawn falling node if node below is loaded
local n_bottom = core.get_node_or_nil(p_bottom)
local d_bottom = n_bottom and core.registered_nodes[n_bottom.name]
if d_bottom then
-- do not trigger a cascade of falling nodes when it's just
-- moresnow nodes that rest perfectly well on top of plants (buildable_to)
if(d_bottom.name and d_bottom.name ~= "air"
and core.get_item_group(n.name, "soft_falling") > 0) then
return false
end
end
end
-- makes use of local builtin_shared variable which we don't have available here - so
-- we need to call the original
return old_check_single_for_falling(p)
end