2012-10-14 03:45:50 +02:00
worldedit = worldedit or { }
2013-07-12 20:22:30 +02:00
local minetest = minetest --local copy of global
2012-10-14 03:45:50 +02:00
2013-06-23 05:05:34 +02:00
--adds a hollow sphere centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
2013-06-23 05:08:51 +02:00
worldedit.hollow_sphere = function ( pos , radius , nodename )
2013-07-12 20:22:30 +02:00
--set up voxel manipulator
local manip = minetest.get_voxel_manip ( )
2013-07-21 22:54:25 +02:00
local pos1 = { x = pos.x - radius , y = pos.y - radius , z = pos.z - radius }
local pos2 = { x = pos.x + radius , y = pos.y + radius , z = pos.z + radius }
local emerged_pos1 , emerged_pos2 = manip : read_from_map ( pos1 , pos2 )
local area = VoxelArea : new ( { MinEdge = emerged_pos1 , MaxEdge = emerged_pos2 } )
2013-07-12 20:22:30 +02:00
2013-07-21 22:54:25 +02:00
--fill emerged area with ignore
local nodes = { }
local ignore = minetest.get_content_id ( " ignore " )
for i = 1 , worldedit.volume ( emerged_pos1 , emerged_pos2 ) do
nodes [ i ] = ignore
end
--fill selected area with node
2013-07-12 20:22:30 +02:00
local node_id = minetest.get_content_id ( nodename )
local min_radius , max_radius = radius * ( radius - 1 ) , radius * ( radius + 1 )
2013-07-28 03:34:42 +02:00
local offsetx , offsety , offsetz = pos.x - emerged_pos1.x , pos.y - emerged_pos1.y , pos.z - emerged_pos1.z
local zstride , ystride = area.zstride , area.ystride
2013-06-25 00:21:48 +02:00
local count = 0
2013-07-28 03:34:42 +02:00
for z = - radius , radius do
local newz = ( z + offsetz ) * zstride
for y = - radius , radius do
local newy = newz + ( y + offsety ) * ystride
for x = - radius , radius do
local squared = x * x + y * y + z * z
if squared >= min_radius and squared <= max_radius then --position is on surface of sphere
local i = newy + ( x + offsetx ) + 1
nodes [ i ] = node_id
count = count + 1
end
2012-10-14 03:45:50 +02:00
end
end
end
2013-07-12 20:22:30 +02:00
--update map nodes
manip : set_data ( nodes )
manip : write_to_map ( )
manip : update_map ( )
2013-06-25 00:21:48 +02:00
return count
2012-10-14 03:45:50 +02:00
end
2013-06-23 05:05:34 +02:00
--adds a sphere centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
2013-06-23 05:08:51 +02:00
worldedit.sphere = function ( pos , radius , nodename )
2013-07-12 20:22:30 +02:00
--set up voxel manipulator
local manip = minetest.get_voxel_manip ( )
2013-07-21 22:54:25 +02:00
local pos1 = { x = pos.x - radius , y = pos.y - radius , z = pos.z - radius }
local pos2 = { x = pos.x + radius , y = pos.y + radius , z = pos.z + radius }
local emerged_pos1 , emerged_pos2 = manip : read_from_map ( pos1 , pos2 )
local area = VoxelArea : new ( { MinEdge = emerged_pos1 , MaxEdge = emerged_pos2 } )
2013-07-12 20:22:30 +02:00
2013-07-21 22:54:25 +02:00
--fill emerged area with ignore
local nodes = { }
local ignore = minetest.get_content_id ( " ignore " )
for i = 1 , worldedit.volume ( emerged_pos1 , emerged_pos2 ) do
nodes [ i ] = ignore
end
--fill selected area with node
2013-07-12 20:22:30 +02:00
local node_id = minetest.get_content_id ( nodename )
local max_radius = radius * ( radius + 1 )
2013-07-28 03:34:42 +02:00
local offsetx , offsety , offsetz = pos.x - emerged_pos1.x , pos.y - emerged_pos1.y , pos.z - emerged_pos1.z
local zstride , ystride = area.zstride , area.ystride
2013-06-25 00:21:48 +02:00
local count = 0
2013-07-28 03:34:42 +02:00
for z = - radius , radius do
local newz = ( z + offsetz ) * zstride
for y = - radius , radius do
local newy = newz + ( y + offsety ) * ystride
for x = - radius , radius do
if x * x + y * y + z * z <= max_radius then --position is inside sphere
local i = newy + ( x + offsetx ) + 1
nodes [ i ] = node_id
count = count + 1
end
2013-04-28 00:28:20 +02:00
end
end
end
2013-07-12 20:22:30 +02:00
--update map nodes
manip : set_data ( nodes )
manip : write_to_map ( )
manip : update_map ( )
2013-06-25 00:21:48 +02:00
return count
2013-04-28 00:28:20 +02:00
end
2013-06-23 05:05:34 +02:00
--adds a hollow dome centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
2013-07-21 22:54:25 +02:00
worldedit.hollow_dome = function ( pos , radius , nodename )
2013-07-12 20:22:30 +02:00
--set up voxel manipulator
local manip = minetest.get_voxel_manip ( )
2013-07-21 22:54:25 +02:00
local pos1 = { x = pos.x - radius , y = pos.y , z = pos.z - radius }
local pos2 = { x = pos.x + radius , y = pos.y + radius , z = pos.z + radius }
local emerged_pos1 , emerged_pos2 = manip : read_from_map ( pos1 , pos2 )
local area = VoxelArea : new ( { MinEdge = emerged_pos1 , MaxEdge = emerged_pos2 } )
2013-07-12 20:22:30 +02:00
2013-07-21 22:54:25 +02:00
--fill emerged area with ignore
local nodes = { }
local ignore = minetest.get_content_id ( " ignore " )
for i = 1 , worldedit.volume ( emerged_pos1 , emerged_pos2 ) do
nodes [ i ] = ignore
end
--fill selected area with node
2013-07-12 20:22:30 +02:00
local node_id = minetest.get_content_id ( nodename )
local min_radius , max_radius = radius * ( radius - 1 ) , radius * ( radius + 1 )
2013-07-28 03:34:42 +02:00
local offsetx , offsety , offsetz = pos.x - emerged_pos1.x , pos.y - emerged_pos1.y , pos.z - emerged_pos1.z
local zstride , ystride = area.zstride , area.ystride
2013-06-25 00:21:48 +02:00
local count = 0
2013-07-28 03:34:42 +02:00
for z = - radius , radius do
local newz = ( z + offsetz ) * zstride
for y = 0 , radius do
local newy = newz + ( y + offsety ) * ystride
for x = - radius , radius do
local squared = x * x + y * y + z * z
if squared >= min_radius and squared <= max_radius then --position is on surface of sphere
local i = newy + ( x + offsetx ) + 1
nodes [ i ] = node_id
count = count + 1
end
2013-04-28 00:28:20 +02:00
end
end
end
2013-07-12 20:22:30 +02:00
--update map nodes
manip : set_data ( nodes )
manip : write_to_map ( )
manip : update_map ( )
2013-06-25 00:21:48 +02:00
return count
2013-04-28 00:28:20 +02:00
end
2013-06-23 05:05:34 +02:00
--adds a dome centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
2013-06-23 05:08:51 +02:00
worldedit.dome = function ( pos , radius , nodename ) --wip: use bresenham sphere for maximum speed
2013-07-12 20:22:30 +02:00
--set up voxel manipulator
local manip = minetest.get_voxel_manip ( )
2013-07-21 22:54:25 +02:00
local pos1 = { x = pos.x - radius , y = pos.y , z = pos.z - radius }
local pos2 = { x = pos.x + radius , y = pos.y + radius , z = pos.z + radius }
local emerged_pos1 , emerged_pos2 = manip : read_from_map ( pos1 , pos2 )
local area = VoxelArea : new ( { MinEdge = emerged_pos1 , MaxEdge = emerged_pos2 } )
2013-07-12 20:22:30 +02:00
2013-07-21 22:54:25 +02:00
--fill emerged area with ignore
local nodes = { }
local ignore = minetest.get_content_id ( " ignore " )
for i = 1 , worldedit.volume ( emerged_pos1 , emerged_pos2 ) do
nodes [ i ] = ignore
end
--fill selected area with node
2013-07-12 20:22:30 +02:00
local node_id = minetest.get_content_id ( nodename )
local max_radius = radius * ( radius + 1 )
2013-07-28 03:34:42 +02:00
local offsetx , offsety , offsetz = pos.x - emerged_pos1.x , pos.y - emerged_pos1.y , pos.z - emerged_pos1.z
local zstride , ystride = area.zstride , area.ystride
2013-06-25 00:21:48 +02:00
local count = 0
2013-07-28 03:34:42 +02:00
for z = - radius , radius do
local newz = ( z + offsetz ) * zstride
for y = 0 , radius do
local newy = newz + ( y + offsety ) * ystride
for x = - radius , radius do
if x * x + y * y + z * z <= max_radius then --position is inside sphere
local i = newy + ( x + offsetx ) + 1
nodes [ i ] = node_id
count = count + 1
end
2012-10-14 03:45:50 +02:00
end
end
end
2013-07-12 20:22:30 +02:00
--update map nodes
manip : set_data ( nodes )
manip : write_to_map ( )
manip : update_map ( )
2013-06-25 00:21:48 +02:00
return count
2012-10-14 03:45:50 +02:00
end
--adds a hollow cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added
2013-07-21 22:54:25 +02:00
worldedit.hollow_cylinder = function ( pos , axis , length , radius , nodename ) --wip: rewrite this using voxelmanip
2012-10-14 03:45:50 +02:00
local other1 , other2
if axis == " x " then
other1 , other2 = " y " , " z "
elseif axis == " y " then
other1 , other2 = " x " , " z "
else --axis == "z"
other1 , other2 = " x " , " y "
end
2013-07-12 20:22:30 +02:00
--handle negative lengths
2012-10-14 03:45:50 +02:00
local currentpos = { x = pos.x , y = pos.y , z = pos.z }
if length < 0 then
length = - length
2013-06-23 18:46:59 +02:00
currentpos [ axis ] = currentpos [ axis ] - length
2012-10-14 03:45:50 +02:00
end
2013-06-23 18:46:59 +02:00
--create schematic for single node column along the axis
local node = { name = nodename , param1 = 0 , param2 = 0 }
local nodes = { }
2012-10-14 03:45:50 +02:00
for i = 1 , length do
2013-06-23 18:46:59 +02:00
nodes [ i ] = node
end
local schematic = { size = { [ axis ] = length , [ other1 ] = 1 , [ other2 ] = 1 } , data = nodes }
2012-10-14 03:45:50 +02:00
2013-06-23 18:46:59 +02:00
--add columns in a circle around axis to form cylinder
local place_schematic = minetest.place_schematic
local count = 0
local offset1 , offset2 = 0 , radius
local delta = - radius
while offset1 <= offset2 do
--add node at each octant
local first1 , first2 = pos [ other1 ] + offset1 , pos [ other1 ] - offset1
local second1 , second2 = pos [ other2 ] + offset2 , pos [ other2 ] - offset2
currentpos [ other1 ] , currentpos [ other2 ] = first1 , second1
place_schematic ( currentpos , schematic ) --octant 1
currentpos [ other1 ] = first2
place_schematic ( currentpos , schematic ) --octant 4
currentpos [ other2 ] = second2
place_schematic ( currentpos , schematic ) --octant 5
currentpos [ other1 ] = first1
place_schematic ( currentpos , schematic ) --octant 8
local first1 , first2 = pos [ other1 ] + offset2 , pos [ other1 ] - offset2
local second1 , second2 = pos [ other2 ] + offset1 , pos [ other2 ] - offset1
currentpos [ other1 ] , currentpos [ other2 ] = first1 , second1
place_schematic ( currentpos , schematic ) --octant 2
currentpos [ other1 ] = first2
place_schematic ( currentpos , schematic ) --octant 3
currentpos [ other2 ] = second2
place_schematic ( currentpos , schematic ) --octant 6
currentpos [ other1 ] = first1
place_schematic ( currentpos , schematic ) --octant 7
2012-10-14 03:45:50 +02:00
2013-07-12 20:22:30 +02:00
count = count + 8 --wip: broken because sometimes currentpos is repeated
2013-06-23 18:46:59 +02:00
--move to next location
delta = delta + ( offset1 * 2 ) + 1
if delta >= 0 then
offset2 = offset2 - 1
delta = delta - ( offset2 * 2 )
2012-10-14 03:45:50 +02:00
end
2013-06-23 18:46:59 +02:00
offset1 = offset1 + 1
2012-10-14 03:45:50 +02:00
end
2013-07-12 20:22:30 +02:00
count = count * length --apply the length to the number of nodes
2012-10-14 03:45:50 +02:00
return count
end
--adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added
2013-07-21 22:54:25 +02:00
worldedit.cylinder = function ( pos , axis , length , radius , nodename , env ) --wip: rewrite this using voxelmanip
2012-10-14 03:45:50 +02:00
local other1 , other2
if axis == " x " then
other1 , other2 = " y " , " z "
elseif axis == " y " then
other1 , other2 = " x " , " z "
else --axis == "z"
other1 , other2 = " x " , " y "
end
2013-07-12 20:22:30 +02:00
--handle negative lengths
2012-10-14 03:45:50 +02:00
local currentpos = { x = pos.x , y = pos.y , z = pos.z }
if length < 0 then
length = - length
2013-07-12 20:22:30 +02:00
currentpos [ axis ] = currentpos [ axis ] - length
2012-10-14 03:45:50 +02:00
end
2013-07-12 20:22:30 +02:00
2013-07-28 03:34:42 +02:00
--set up voxel manipulator
local manip = minetest.get_voxel_manip ( )
local pos1 = {
[ axis ] = currentpos [ axis ] ,
[ other1 ] = currentpos [ other1 ] - radius ,
[ other2 ] = currentpos [ other2 ] - radius
}
local pos2 = {
[ axis ] = currentpos [ axis ] + length - 1 ,
[ other1 ] = currentpos [ other1 ] + radius ,
[ other2 ] = currentpos [ other2 ] + radius
}
local emerged_pos1 , emerged_pos2 = manip : read_from_map ( pos1 , pos2 )
local area = VoxelArea : new ( { MinEdge = emerged_pos1 , MaxEdge = emerged_pos2 } )
--fill emerged area with ignore
2013-07-12 20:22:30 +02:00
local nodes = { }
2013-07-28 03:34:42 +02:00
local ignore = minetest.get_content_id ( " ignore " )
for i = 1 , worldedit.volume ( emerged_pos1 , emerged_pos2 ) do
nodes [ i ] = ignore
2013-07-12 20:22:30 +02:00
end
2012-10-14 03:45:50 +02:00
2013-07-28 03:34:42 +02:00
--fill selected area with node
local node_id = minetest.get_content_id ( nodename )
local max_radius = radius * ( radius + 1 )
local stride = { x = 1 , y = area.ystride , z = area.zstride }
local offset = { x = currentpos.x - emerged_pos1.x , y = currentpos.y - emerged_pos1.y , z = currentpos.z - emerged_pos1.z }
local min_slice , max_slice = offset [ axis ] , offset [ axis ] + length - 1
2013-07-12 20:22:30 +02:00
local count = 0
2013-07-28 03:34:42 +02:00
for axis1 = - radius , radius do
local newaxis1 = ( axis1 + offset [ other1 ] ) * stride [ other1 ]
for axis2 = - radius , radius do
local newaxis2 = newaxis1 + ( axis2 + offset [ other2 ] ) * stride [ other2 ]
if axis1 * axis1 + axis2 * axis2 <= max_radius then
for slice = min_slice , max_slice do
local i = newaxis2 + slice * stride [ axis ] + 1
nodes [ i ] = node_id
end
count = count + length
end
2013-07-12 20:22:30 +02:00
end
2013-07-28 03:34:42 +02:00
end
2012-10-14 03:45:50 +02:00
2013-07-28 03:34:42 +02:00
--update map nodes
manip : set_data ( nodes )
manip : write_to_map ( )
manip : update_map ( )
2013-07-12 20:22:30 +02:00
2012-10-14 03:45:50 +02:00
return count
end
2013-06-23 05:05:34 +02:00
--adds a pyramid centered at `pos` with height `height`, composed of `nodename`, returning the number of nodes added
2013-07-21 22:54:25 +02:00
worldedit.pyramid = function ( pos , height , nodename , env ) --wip: rewrite this using voxelmanip
2012-10-14 03:45:50 +02:00
local pos1x , pos1y , pos1z = pos.x - height , pos.y , pos.z - height
local pos2x , pos2y , pos2z = pos.x + height , pos.y + height , pos.z + height
local pos = { x = 0 , y = pos1y , z = 0 }
2013-07-28 03:34:42 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
--set up voxel manipulator
local manip = minetest.get_voxel_manip ( )
local emerged_pos1 , emerged_pos2 = manip : read_from_map ( pos1 , pos2 )
local area = VoxelArea : new ( { MinEdge = emerged_pos1 , MaxEdge = emerged_pos2 } )
--fill emerged area with ignore
local nodes = { }
local ignore = minetest.get_content_id ( " ignore " )
for i = 1 , worldedit.volume ( emerged_pos1 , emerged_pos2 ) do
nodes [ i ] = ignore
end
--fill selected area with node
local node_id = minetest.get_content_id ( nodename )
for i in area : iterp ( pos1 , pos2 ) do
nodes [ i ] = node_id
end
--update map nodes
manip : set_data ( nodes )
manip : write_to_map ( )
manip : update_map ( )
2012-10-14 03:45:50 +02:00
local count = 0
local node = { name = nodename }
2013-04-28 19:08:09 +02:00
if env == nil then env = minetest.env end
2012-10-14 03:45:50 +02:00
while pos.y <= pos2y do --each vertical level of the pyramid
pos.x = pos1x
while pos.x <= pos2x do
pos.z = pos1z
while pos.z <= pos2z do
env : add_node ( pos , node )
pos.z = pos.z + 1
end
pos.x = pos.x + 1
end
count = count + ( ( pos2y - pos.y ) * 2 + 1 ) ^ 2
pos.y = pos.y + 1
pos1x , pos2x = pos1x + 1 , pos2x - 1
pos1z , pos2z = pos1z + 1 , pos2z - 1
end
return count
end
2013-06-23 05:05:34 +02:00
--adds a spiral centered at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added
2013-04-28 19:08:09 +02:00
worldedit.spiral = function ( pos , width , height , spacer , nodename , env ) --wip: clean this up
2012-10-14 03:45:50 +02:00
-- spiral matrix - http://rosettacode.org/wiki/Spiral_matrix#Lua
2013-06-23 18:46:59 +02:00
--wip: rewrite this whole thing, nobody can understand it anyways
2012-10-14 03:45:50 +02:00
av , sn = math.abs , function ( s ) return s ~= 0 and s / av ( s ) or 0 end
local function sindex ( z , x ) -- returns the value at (x, z) in a spiral that starts at 1 and goes outwards
if z == - x and z >= x then return ( 2 * z + 1 ) ^ 2 end
local l = math.max ( av ( z ) , av ( x ) )
return ( 2 * l - 1 ) ^ 2 + 4 * l + 2 * l * sn ( x + z ) + sn ( z ^ 2 - x ^ 2 ) * ( l - ( av ( z ) == l and sn ( z ) * x or sn ( x ) * z ) ) -- OH GOD WHAT
end
local function spiralt ( side )
local ret , id , start , stop = { } , 0 , math.floor ( ( - side + 1 ) / 2 ) , math.floor ( ( side - 1 ) / 2 )
for i = 1 , side do
for j = 1 , side do
local id = side ^ 2 - sindex ( stop - i + 1 , start + j - 1 )
ret [ id ] = { x = i , z = j }
end
end
return ret
end
2013-07-12 20:22:30 +02:00
if env == nil then env = minetest.env end
2012-10-14 03:45:50 +02:00
-- connect the joined parts
local spiral = spiralt ( width )
height = tonumber ( height )
if height < 1 then height = 1 end
spacer = tonumber ( spacer ) - 1
if spacer < 1 then spacer = 1 end
local count = 0
local node = { name = nodename }
local np , lp
for y = 0 , height do
lp = nil
for _ , v in ipairs ( spiral ) do
np = { x = pos.x + v.x * spacer , y = pos.y + y , z = pos.z + v.z * spacer }
if lp ~= nil then
if lp.x ~= np.x then
if lp.x < np.x then
for i = lp.x + 1 , np.x do
2013-04-28 19:08:09 +02:00
env : add_node ( { x = i , y = np.y , z = np.z } , node )
2012-10-14 03:45:50 +02:00
count = count + 1
end
else
for i = np.x , lp.x - 1 do
2013-04-28 19:08:09 +02:00
env : add_node ( { x = i , y = np.y , z = np.z } , node )
2012-10-14 03:45:50 +02:00
count = count + 1
end
end
end
if lp.z ~= np.z then
if lp.z < np.z then
for i = lp.z + 1 , np.z do
2013-04-28 19:08:09 +02:00
env : add_node ( { x = np.x , y = np.y , z = i } , node )
2012-10-14 03:45:50 +02:00
count = count + 1
end
else
for i = np.z , lp.z - 1 do
2013-04-28 19:08:09 +02:00
env : add_node ( { x = np.x , y = np.y , z = i } , node )
2012-10-14 03:45:50 +02:00
count = count + 1
end
end
end
end
lp = np
end
end
return count
2013-04-28 19:08:09 +02:00
end