f6102b9512
There are other situations where we right-click on things and expect a non-placement action, and that action fails. We should probably be more consistent about not placing in these cases, as players may be surprised by it, and be left in trouble due to not having a tool to dig it back up. Requiring sneak is safer. Now technically shelves violate this principle, but their violation is much narrower in scope, i.e. only placement of containers. This reverts commit 4795a63116782fe47e72847dd308468a345b9369.
226 lines
5.4 KiB
Lua
226 lines
5.4 KiB
Lua
-- LUALOCALS < ---------------------------------------------------------
|
|
local minetest, nodecore, pairs, vector
|
|
= minetest, nodecore, pairs, vector
|
|
-- LUALOCALS > ---------------------------------------------------------
|
|
|
|
local modstore = minetest.get_mod_storage()
|
|
|
|
local function hingeaxis(pos, node)
|
|
local fd = node and node.param2 or 0
|
|
fd = nodecore.facedirs[fd]
|
|
fd = vector.multiply(vector.add(fd.f, fd.r), 0.5)
|
|
return {
|
|
x = fd.x == 0 and 0 or pos.x + fd.x,
|
|
y = fd.y == 0 and 0 or pos.y + fd.y,
|
|
z = fd.z == 0 and 0 or pos.z + fd.z
|
|
}
|
|
end
|
|
|
|
local convey = {}
|
|
|
|
local function conveytrace(okay, seg, u)
|
|
if u.tkey2 then
|
|
local w = convey[u.tkey2]
|
|
if w then return w end
|
|
if nodecore.buildable_to(u.to2) then
|
|
for x in pairs(seg) do
|
|
okay[x] = true
|
|
end
|
|
u.to = u.to2
|
|
u.tkey = u.tkey2
|
|
return
|
|
end
|
|
end
|
|
local w = convey[u.tkey]
|
|
if w then return w end
|
|
if nodecore.buildable_to(u.to) then
|
|
for x in pairs(seg) do
|
|
okay[x] = true
|
|
end
|
|
end
|
|
end
|
|
|
|
local function set_node(pos, node)
|
|
local exists = minetest.get_node(pos)
|
|
if exists.name ~= node.name
|
|
or exists.param ~= node.param
|
|
or exists.param2 ~= node.param2 then
|
|
return minetest.set_node(pos, node)
|
|
end
|
|
end
|
|
|
|
minetest.register_globalstep(function()
|
|
local nonheads = {}
|
|
for _, v in pairs(convey) do
|
|
if v.tkey2 and (convey[v.tkey2] or nodecore.buildable_to(v.to2)) then
|
|
nonheads[v.tkey2] = true
|
|
else
|
|
nonheads[v.tkey] = true
|
|
end
|
|
end
|
|
local okay = {}
|
|
for k, v in pairs(convey) do
|
|
if not nonheads[k] then
|
|
local seg = {}
|
|
local u = v
|
|
while u do
|
|
seg[u] = true
|
|
u = conveytrace(okay, seg, u)
|
|
end
|
|
for x in pairs(seg) do
|
|
convey[x.fkey] = nil
|
|
end
|
|
end
|
|
end
|
|
for _, v in pairs(convey) do
|
|
okay[v] = true
|
|
end
|
|
convey = {}
|
|
|
|
local air = {name = "air"}
|
|
local toset = {}
|
|
for v in pairs(okay) do
|
|
toset[v.fkey] = {pos = v.from, node = air}
|
|
end
|
|
for v in pairs(okay) do
|
|
toset[v.tkey] = {
|
|
pos = v.to,
|
|
node = v.node,
|
|
meta = minetest.get_meta(v.from):to_table()
|
|
}
|
|
end
|
|
for _, v in pairs(toset) do
|
|
set_node(v.pos, v.node)
|
|
if v.meta then
|
|
minetest.get_meta(v.pos):from_table(v.meta)
|
|
nodecore.visinv_update_ents(v.pos)
|
|
end
|
|
nodecore.fallcheck(v.pos)
|
|
end
|
|
end)
|
|
|
|
local is_falling = {groups = { falling_node = true }}
|
|
|
|
local function trypush(pos, dir, dir2)
|
|
local node = minetest.get_node(pos)
|
|
if not nodecore.match(node, is_falling) then return end
|
|
|
|
local data = {
|
|
from = pos,
|
|
fkey = minetest.pos_to_string(pos),
|
|
to = vector.add(pos, dir),
|
|
node = node,
|
|
}
|
|
data.tkey = minetest.pos_to_string(data.to)
|
|
if dir2 then
|
|
data.to2 = vector.add(pos, dir2)
|
|
data.tkey2 = minetest.pos_to_string(data.to2)
|
|
end
|
|
convey[data.fkey] = data
|
|
end
|
|
|
|
local squelch = modstore:get_string("squelch")
|
|
squelch = squelch and squelch ~= "" and minetest.deserialize(squelch) or {}
|
|
minetest.register_globalstep(function(dtime)
|
|
for k, v in pairs(squelch) do
|
|
squelch[k] = (v > dtime) and (v - dtime) or nil
|
|
end
|
|
modstore:set_string("squelch", squelch)
|
|
end)
|
|
|
|
local is_door = {groups = { door = true }}
|
|
|
|
function nodecore.operate_door(pos, node, dir)
|
|
local key = minetest.pos_to_string(pos)
|
|
if squelch[key] then return end
|
|
node = node or minetest.get_node_or_nil(pos)
|
|
if (not node) or (not nodecore.match(node, is_door)) then return end
|
|
|
|
local fd = nodecore.facedirs[node.param2 or 0]
|
|
local rotdir
|
|
if vector.equals(dir, fd.k) or vector.equals(dir, fd.r) then
|
|
rotdir = "r"
|
|
elseif vector.equals(dir, fd.l) or vector.equals(dir, fd.f) then
|
|
rotdir = "f"
|
|
else return end
|
|
|
|
local found = {}
|
|
local hinge = hingeaxis(pos, node)
|
|
if nodecore.scan_flood(pos, 128, function(p)
|
|
local n = minetest.get_node_or_nil(p)
|
|
if not n then return true end
|
|
if (not nodecore.match(n, is_door))
|
|
or (not vector.equals(hingeaxis(p, n), hinge)) then return false end
|
|
found[minetest.pos_to_string(p)] = {pos = p, node = n}
|
|
end
|
|
) then return end
|
|
|
|
local toop = {}
|
|
for k, v in pairs(found) do
|
|
local ffd = nodecore.facedirs[v.node.param2 or 0]
|
|
v.dir = ffd[rotdir]
|
|
v.dir2 = rotdir == "r" and ffd.k or ffd.l
|
|
local to = vector.add(v.pos, v.dir)
|
|
|
|
if (not found[minetest.pos_to_string(to)])
|
|
and (not nodecore.buildable_to(to))
|
|
then return end
|
|
|
|
local str = minetest.pos_to_string(to)
|
|
if squelch[str] then return end
|
|
|
|
v.str = str
|
|
v.to = to
|
|
v.fd = ffd
|
|
|
|
toop[k .. "l"] = {
|
|
pos = vector.add(v.pos, ffd.l),
|
|
dir = rotdir == "r" and ffd.k or ffd.f
|
|
}
|
|
toop[k .. "k"] = {
|
|
pos = vector.add(v.pos, ffd.k),
|
|
dir = rotdir == "r" and ffd.r or ffd.l
|
|
}
|
|
end
|
|
|
|
local toset = {}
|
|
for k, v in pairs(found) do
|
|
toset[k] = {pos = v.pos, name = "air", param2 = 0}
|
|
squelch[k] = 0.5
|
|
squelch[v.str] = 0.5
|
|
end
|
|
for _, v in pairs(found) do
|
|
for i, xfd in pairs(nodecore.facedirs) do
|
|
if vector.equals(xfd.t, v.fd.t)
|
|
and vector.equals(xfd.r, rotdir == "r" and v.fd.f or v.fd.k) then
|
|
toset[minetest.pos_to_string(v.to)] = {
|
|
pos = v.to,
|
|
name = v.node.name,
|
|
param2 = i
|
|
}
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
for _, v in pairs(toset) do
|
|
set_node(v.pos, v)
|
|
if v.name ~= "air" then
|
|
local p = vector.round(vector.multiply(v.pos, 0.25))
|
|
local k = "sfx" .. minetest.pos_to_string(p)
|
|
if not squelch[k] then
|
|
squelch[k] = 0
|
|
minetest.sound_play("nc_doors_operate",
|
|
{pos = v.pos, gain = 0.5})
|
|
end
|
|
end
|
|
end
|
|
for _, v in pairs(found) do
|
|
trypush({x = v.pos.x, y = v.pos.y + 1, z = v.pos.z}, v.dir, v.dir2)
|
|
end
|
|
for _, v in pairs(toop) do
|
|
nodecore.operate_door(v.pos, nil, v.dir)
|
|
trypush(v.pos, v.dir)
|
|
end
|
|
end
|