local ofs = {
neighbors = {
{x = 1, y = 0, z = 0};
{x = -1, y = 0, z = 0};
{x = 0, y = 1, z = 0};
{x = 0, y = -1, z = 0};
{x = 0, y = 0, z = 1};
{x = 0, y = 0, z = -1};
};
planecorners = {
{x = 1, y = 0, z = 1};
{x = -1, y = 0, z = 1};
{x = -1, y = 0, z = -1};
{x = 1, y = 0, z = -1};
{x = 1, y = 1, z = 0};
{x = -1, y = 1, z = 0};
{x = -1, y = -1, z = 0};
{x = 1, y = -1, z = 0};
};
cubecorners = {
{x = 1, y = 1, z = 1};
{x = -1, y = 1, z = 1};
{x = -1, y = -1, z = 1};
{x = -1, y = -1, z = -1};
{x = 1, y = -1, z = -1};
{x = 1, y = 1, z = -1};
{x = 1, y = -1, z = 1};
{x = -1, y = 1, z = -1};
};
nextto = {
{x = 1, y = 0, z = 0};
{x = -1, y = 0, z = 0};
{x = 0, y = 0, z = 1};
{x = 0, y = 0, z = -1};
};
}
ofs.adjoining = sorcery.lib.tbl.append(sorcery.lib.tbl.append(
ofs.neighbors,ofs.planecorners),ofs.cubecorners)
local purge_container = function(only, pos,node,meta,user)
local offset = function(pos,range)
local r = function(min,max)
return (math.random() * (max - min)) + min
end
return {
x = pos.x + r(0 - range, range);
y = pos.y;
z = pos.z + r(0 - range, range);
}
end
for name, inv in pairs(meta.inventory) do
if only and not sorcery.lib.tbl.has(only,name) then goto skip end
for _, item in pairs(inv) do
if not item:is_empty() then
minetest.add_item(offset(pos,0.4), item)
end
end
::skip::end
end;
return {
offsets = ofs;
purge_container = function(...) return purge_container(nil, ...) end;
purge_only = function(lst)
return function(...)
return purge_container(lst, ...)
end
end;
is_air = function(pos)
local n = sorcery.lib.node.force(pos)
if n.name == 'air' then return true end
local d = minetest.registered_nodes[n.name]
if not d then return false end
return not d.walkable
end;
is_clear = function(pos)
if not sorcery.lib.node.is_air(pos) then return false end
local ents = minetest.get_objects_inside_radius(pos,0.5)
if #ents > 0 then return false end
return true
end;
get_arrival_point = function(pos)
local try = function(p)
local air = sorcery.lib.node.is_clear
if air(p) then
if air(vector.offset(p,0,1,0)) then return p end
if air(vector.offset(p,0,-1,0)) then return vector.offset(p,0,-1,0) end
end
return false
end
do local t = try(pos) if t then return t end end
for _,o in pairs(ofs.neighbors) do
local p = vector.add(pos, o)
do local t = try(p) if t then return t end end
end
end;
amass = function(startpoint,names,directions)
if not directions then directions = ofs.neighbors end
local nodes, positions, checked = {},{},{}
local checkedp = function(pos)
for _,v in pairs(checked) do
if vector.equals(pos,v) then return true end
end
return false
end
local i,stack = 1,{startpoint} repeat
local pos = stack[i]
local n = sorcery.lib.node.force(pos).name
if sorcery.lib.tbl.has(names, n, function(check,against)
return sorcery.lib.item.groupmatch(against,check)
end) then -- match found
-- record the find
nodes[pos] = n
if positions[n] then positions[n][#positions[n]] = pos
else positions[n] = {pos} end
-- check selected neighbors to see if any need scanning
for _,d in pairs(directions) do
local sum = vector.add(pos, d)
if not checkedp(sum) then
stack[#stack + 1] = sum
end
end
end
checked[#checked+1] = pos
i = i + 1
until i > #stack
return nodes, positions
end;
forneighbor = function(pos, n, fn)
for _,p in pairs(n) do
local sum = vector.add(pos, p)
local n = minetest.get_node(sum)
if n.name == 'ignore' then
minetest.load_area(sum)
n = minetest.get_node(sum)
end
fn(sum, n)
end
end;
force = function(pos,preload_for)
local n = minetest.get_node_or_nil(pos)
if preload_for then sorcery.lib.node.preload(pos,preload_for) end
if n then return n end
minetest.load_area(pos)
return minetest.get_node(pos)
end;
-- when items have already been removed; notify cannot be relied on
-- to reach the entire network; this function accounts for the gap
notifyneighbors = function(pos)
sorcery.lib.node.forneighbor(pos, sorcery.ley.txofs, function(sum,node)
if minetest.get_item_group(node.name,'sorcery_ley_device') ~= 0 then
sorcery.ley.notify(sum)
end
end)
end;
blockpos = function(pos)
return {
x = math.floor(pos.x / 16);
y = math.floor(pos.y / 16);
z = math.floor(pos.z / 16);
}
end;
preload = function(pos, user)
minetest.load_area(pos)
user:send_mapblock(sorcery.lib.node.blockpos(pos))
end;
discharger = function(pos)
local below = sorcery.lib.node.force(vector.subtract(pos,{x=0,y=1,z=0}))
if below.name == 'hopper:hopper'
or below.name == 'hopper:hopper_side' then
local hopper = minetest.get_meta(below):get_inventory()
return function(i)
if hopper:room_for_item('main',i) then
return hopper:add_item('main',i), true
end
return i, false
end
else
return function(i) return i, false end
end
end;
}