1dd37e31ff
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.
94 lines
2.7 KiB
Lua
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
|
|
})
|