Aaron Suen 1dd37e31ff The Luantipocalypse
The Minetest engine has now been renamed to Luanti.  The "core"
namespace is now preferred over the "minetest" namespace for
engine/builtin APIs.

As part of this process, add an "nc" alias (now preferred) for
the nodecore API namespace as well, to save us a little code
verbosity.
2024-10-14 18:44:58 -04:00

94 lines
2.7 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local core, math, nc, pairs
= core, math, nc, pairs
local math_random
= math.random
-- LUALOCALS > ---------------------------------------------------------
--[[
Nodes with the "falling_repose" group will not only fall if unsupported
from below, but if there is a sufficient drop off the sides, so simulate
an "angle of repose."
--]]
nc.register_on_register_item(function(_, def)
if def.type ~= "node" then return end
def.groups = def.groups or {}
if def.groups.falling_repose then def.groups.falling_node = 1 end
def.repose_drop = def.repose_drop or nc.fall_force
end)
local function check_empty(pos, dx, dy, dz)
for ndy = dy, 0 do
local p = {x = pos.x + dx, y = pos.y + ndy, z = pos.z + dz}
if not nc.buildable_to(p) then return end
end
return {x = pos.x + dx, y = pos.y, z = pos.z + dz}
end
function nc.falling_repose_positions(pos, node, def)
node = node or core.get_node(pos)
def = def or core.registered_items[node.name] or {}
local repose = def.groups and def.groups.falling_repose
if not repose then return end
-- Reposing nodes can always sit comfortably atop
-- a non-moving node; it's only when stacked on other
-- falling nodes that they can slip off.
local sitdef = core.registered_items[core.get_node(
{x = pos.x, y = pos.y - 1, z = pos.z}).name]
if not (sitdef and sitdef.groups and sitdef.groups.falling_node)
then return end
local open = {}
local ok = check_empty(pos, 1, -repose, 0)
if ok then open[1] = ok end
ok = check_empty(pos, -1, -repose, 0)
if ok then open[#open + 1] = ok end
ok = check_empty(pos, 0, -repose, 1)
if ok then open[#open + 1] = ok end
ok = check_empty(pos, 0, -repose, -1)
if ok then open[#open + 1] = ok end
return #open > 0 and open or nil, node, def
end
function nc.falling_repose_check(pos)
if core.check_single_for_falling(pos) then return end
local open, node, def = nc.falling_repose_positions(pos)
if not open then return end
return def.repose_drop(pos, node, open[math_random(1, #open)])
end
local reposeq
local qqty
local qmax = 100
local function reposeall()
for _, v in pairs(reposeq) do v() end
reposeq = nil
qqty = nil
end
core.register_abm({
label = "falling repose",
nodenames = {"group:falling_repose"},
neighbors = {"air"},
interval = 2,
chance = 5,
arealoaded = 1,
action = function(pos)
if not reposeq then
reposeq = {}
qqty = 0
core.after(0, reposeall)
end
local f = function() nc.falling_repose_check(pos) end
if #reposeq > qmax then
local i = math_random(1, qqty)
if i < qmax then reposeq[i] = f end
else
reposeq[#reposeq + 1] = f
end
qqty = qqty + 1
end
})