basic_robot/scripts/terrain_smoother.lua

223 lines
7.4 KiB
Lua

--smoothie robot: smooths selected terrain with slopes: define region with chat c1,c2, smooth with s
if not paste then
_G.minetest.forceload_block(self.pos(),true)
paste = {};
round = function(x)
if x>0 then
return math.floor(x+0.5)
else
return -math.floor(-x+0.5)
end
end
is_solid = function(i,j,k, is_return)
local dat = data[i]
if not is_return then
if not dat then return false end
dat = dat[j];
if not dat then return false end
dat = dat[k];
if not dat then return false end
return true
else
if not dat then return 0 end
dat = dat[j];
if not dat then return 0 end
dat = dat[k];
if not dat then return 0 end
return dat
end
end
solidnodes = {
["default:stone"] = 1,
["default:dirt"] = 2,
["default:stone_with_coal"] = 0,
["default:dirt_with_dry_grass"] = 2,
["default:silver_sand"] = 0,
["default:sand"] = 0,
}
solidtypes =
{
[1] = "stone",
[2] = "dirt"
};
data = {};
self.listen(1)
self.label("mr. smoothie")
end
speaker, msg = self.listen_msg()
if msg and (true or speaker == "rnd") then
local player = _G.minetest.get_player_by_name(speaker);
local p = player:getpos(); p.x = round(p.x); p.y=round(p.y); p.z = round(p.z);
if msg == "c1" then
paste.src1 = {x=p.x,y=p.y,z=p.z};say("marker 1 set at " .. p.x .. " " .. p.y .. " " .. p.z)
elseif msg == "c2" then
paste.src2 = {x=p.x,y=p.y,z=p.z};say("marker 2 set at " .. p.x .. " " .. p.y .. " " .. p.z)
elseif msg == "c" then -- LOAD geometry in memory
local x1 = math.min(paste.src1.x,paste.src2.x);local y1 = math.min(paste.src1.y,paste.src2.y);local z1 = math.min(paste.src1.z,paste.src2.z);
local x2 = math.max(paste.src1.x,paste.src2.x);local y2 = math.max(paste.src1.y,paste.src2.y);local z2 = math.max(paste.src1.z,paste.src2.z);
x1=x1-1;y1=y1-1;z1=z1-1;x2=x2+1;y2=y2+1;z2=z2+1;
local count = 0; data = {};
for i = x1,x2 do
for j = y1,y2 do
for k = z1,z2 do
local node = _G.minetest.get_node({x=i,y=j,z=k});
local typ = solidnodes[node.name];
if not typ then if string.sub(node.name,1,4) == "more" then typ = 1 end end
if typ then
if not data[i] then data[i]= {} end
if not data[i][j] then data[i][j]= {} end
data[i][j][k] = -typ
count = count +1;
end
end
end
end
say(count .. " nodes copied ");
elseif msg == "s" then -- SMOOTHING PROCESS
local x1 = math.min(paste.src1.x,paste.src2.x);local y1 = math.min(paste.src1.y,paste.src2.y);local z1 = math.min(paste.src1.z,paste.src2.z);
local x2 = math.max(paste.src1.x,paste.src2.x);local y2 = math.max(paste.src1.y,paste.src2.y);local z2 = math.max(paste.src1.z,paste.src2.z);
local count = 0; local newnode = {};
for i = x1,x2 do
for j = y1,y2 do
for k = z1,z2 do
local x = i;local y = j; local z = k;
--say(x .. " " .. y .. " " .. z)
if is_solid(x,y,z) and not is_solid(x,y+1,z) then -- floor node
local xs1,xs2,zs1,zs2
if is_solid(x-1,y,z) then if is_solid(x-1,y+1,z) then xs1 = 1 else xs1 = 0 end else xs1 = -1 end
if is_solid(x+1,y,z) then if is_solid(x+1,y+1,z) then xs2 = 1 else xs2 = 0 end else xs2 = -1 end
if is_solid(x,y,z-1) then if is_solid(x,y+1,z-1) then zs1 = 1 else zs1 = 0 end else zs1 = -1 end
if is_solid(x,y,z+1) then if is_solid(x,y+1,z+1) then zs2 = 1 else zs2 = 0 end else zs2 = -1 end
local dx = xs2 - xs1; local dz = zs2 - zs1; ch = 0;
if dx > 0 and dz == 0 then
if xs1<0 then
newnode[1] = "moreblocks:slope_stone"; newnode[2] = 1; ch = 1
data[x][y][z] = 2;
end
elseif dx<0 and dz == 0 then
if xs2<0 then
newnode[1] = "moreblocks:slope_stone"; newnode[2] = 3; ch = 1
data[x][y][z] = 2;
end
elseif dx == 0 and dz < 0 then
if zs2<0 then
newnode[1] = "moreblocks:slope_stone"; newnode[2] = 2; ch = 1
data[x][y][z] = 2;
end
elseif dx == 0 and dz > 0 then
if zs1<0 then
newnode[1] = "moreblocks:slope_stone"; newnode[2] = 0; ch = 1
data[x][y][z] = 2;
end
elseif dx<0 and dz>0 then
newnode[2] = 0; ch = 1
if xs2 == 0 and zs1 == 0 then
newnode[1] = "moreblocks:slope_stone_inner";
data[x][y][z] = 5;
else
newnode[1] = "moreblocks:slope_stone_outer_cut"
data[x][y][z] = 3;
end
elseif dx>0 and dz>0 then
newnode[2] = 1; ch = 1
if xs1 == 0 and zs1 == 0 then
newnode[1] = "moreblocks:slope_stone_inner"
data[x][y][z] = 5;
else
newnode[1] = "moreblocks:slope_stone_outer_cut"
data[x][y][z] = 3;
end
elseif dx>0 and dz<0 then
newnode[2] = 2; ch = 1
if xs1==0 and zs2 == 0 then
newnode[1] = "moreblocks:slope_stone_inner"
data[x][y][z] = 5;
else
newnode[1] = "moreblocks:slope_stone_outer_cut"
data[x][y][z] = 3;
end
elseif dx<0 and dz<0 then
newnode[2] = 3; ch = 1
if xs2 == 0 and zs2 == 0 then
newnode[1] = "moreblocks:slope_stone_inner"
data[x][y][z] = 5;
else
newnode[1] = "moreblocks:slope_stone_outer_cut"
data[x][y][z] = 3;
end
end
if ch == 1 then _G.minetest.swap_node({x=x,y=y,z=z},{name = newnode[1], param2 = newnode[2]}) end
end
end
end
end
--2nd pass
-- smooth stones below slope_stone_outer_cut if there is at least one air in neighbor 4 diag. positions
-- and set same param2 as above outer_cut
-- slope = 2, outer cut = 3, inner cut = 4, inner = 5
for i = x1,x2 do
for j = y1,y2 do
for k = z1,z2 do
local x = i;local y = j; local z = k;
if is_solid(x,y,z) and is_solid(x,y+1,z,true) == 3 then -- fix stone below outer cut
if not is_solid(x-1,y,z-1) or not is_solid(x+1,y,z-1) or not is_solid(x-1,y,z+1)
or not is_solid(x+1,y,z+1) then
-- replace with inner cut to smooth diag. ramps
local param2 = _G.minetest.get_node({x=x,y=y+1,z=z}).param2;
_G.minetest.swap_node({x=x,y=y,z=z},{name = "moreblocks:slope_stone_inner_cut", param2 = param2})
end
--fix possible holes
elseif is_solid(x,y,z,true) == 5 and not is_solid(x,y+1,z) then --hole fix: inner
if is_solid(x-1,y,z-1) and is_solid(x+1,y,z-1) and is_solid(x-1,y,z+1)
and is_solid(x+1,y,z+1) then
_G.minetest.swap_node({x=x,y=y,z=z},{name = "default:stone"})
end
elseif is_solid(x,y,z,true) == 4 and not is_solid(x,y+1,z) then -- hole fix: inner cut
if is_solid(x-1,y,z-1) and is_solid(x+1,y,z-1) and is_solid(x-1,y,z+1)
and is_solid(x+1,y,z+1) then
_G.minetest.swap_node({x=x,y=y,z=z},{name = "default:stone"})
end
elseif is_solid(x,y,z,true)<0 and not is_solid(x,y+1,z) then -- attempt to smooth blocky stones near outer cuts
local x0,z0;
if is_solid(x-1,y,z,true) == 3 -- outer cut
then x0 = x-1; z0 = z;
elseif is_solid(x+1,y,z,true) == 3
then x0 = x+1; z0 = z;
elseif is_solid(x-1,y,z-1,true) == 3
then x0 = x-1; z0 = z-1;
elseif is_solid(x+1,y,z+1,true) == 3
then x0 = x+1; z0 = z+1;
end
if x0 then
local param2 = _G.minetest.get_node({x=x0,y=y,z=z0}).param2;
_G.minetest.swap_node({x=x,y=y,z=z},{name = "moreblocks:slope_stone_inner_cut", param2 = param2})
end
end
end
end
end
end
end