]> git.lizzy.rs Git - worldedit.git/blobdiff - functions.lua
Fix worldedit.spiral and the correspondign chat command, //spiral.
[worldedit.git] / functions.lua
index 2d16daf8e40e13f220ec38beb37e2f7f5a0f1bf0..2d949c65bf2fdcb43f6f6e061010941bbbcffaca 100644 (file)
@@ -75,7 +75,50 @@ worldedit.replace = function(pos1, pos2, searchnode, replacenode)
        return count\r
 end\r
 \r
---adds a hollow cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, returning the number of nodes added\r
+--adds a hollow sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
+worldedit.hollow_sphere = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed\r
+       local node = {name=nodename}\r
+       local pos1 = {x=0, y=0, z=0}\r
+       local full_radius = radius * radius + radius\r
+       local env = minetest.env\r
+       for x = -radius, radius do\r
+               pos1.x = pos.x + x\r
+               for y = -radius, radius do\r
+                       pos1.y = pos.y + y\r
+                       for z = -radius, radius do\r
+                               if x*x+y*y+z*z >= (radius-1) * (radius-1) + (radius-1) and x*x+y*y+z*z <= full_radius then\r
+                                       pos1.z = pos.z + z\r
+                                       env:add_node({x=pos.x+x,y=pos.y+y,z=pos.z+z}, node)\r
+                               end\r
+                       end\r
+               end\r
+       end\r
+end\r
+\r
+--adds a sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
+worldedit.sphere = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed\r
+       local node = {name=nodename}\r
+       local pos1 = {x=0, y=0, z=0}\r
+       local full_radius = radius * radius + radius\r
+       local count = 0\r
+       local env = minetest.env\r
+       for x = -radius, radius do\r
+               pos1.x = pos.x + x\r
+               for y = -radius, radius do\r
+                       pos1.y = pos.y + y\r
+                       for z = -radius, radius do\r
+                               if x*x+y*y+z*z <= full_radius then\r
+                                       pos1.z = pos.z + z\r
+                                       env:add_node(pos1, node)\r
+                                       count = count + 1\r
+                               end\r
+                       end\r
+               end\r
+       end\r
+       return count\r
+end\r
+\r
+--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\r
 worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename)\r
        local other1, other2\r
        if axis == "x" then\r
@@ -90,6 +133,11 @@ worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename)
        local currentpos = {x=pos.x, y=pos.y, z=pos.z}\r
        local node = {name=nodename}\r
        local count = 0\r
+       local step = 1\r
+       if length < 0 then\r
+               length = -length\r
+               step = -1\r
+       end\r
        for i = 1, length do\r
                local offset1, offset2 = 0, radius\r
                local delta = -radius\r
@@ -126,12 +174,12 @@ worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename)
                        end\r
                        offset1 = offset1 + 1\r
                end\r
-               currentpos[axis] = currentpos[axis] + 1\r
+               currentpos[axis] = currentpos[axis] + step\r
        end\r
        return count\r
 end\r
 \r
---adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, returning the number of nodes added\r
+--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\r
 worldedit.cylinder = function(pos, axis, length, radius, nodename)\r
        local other1, other2\r
        if axis == "x" then\r
@@ -146,6 +194,11 @@ worldedit.cylinder = function(pos, axis, length, radius, nodename)
        local currentpos = {x=pos.x, y=pos.y, z=pos.z}\r
        local node = {name=nodename}\r
        local count = 0\r
+       local step = 1\r
+       if length < 0 then\r
+               length = -length\r
+               step = -1\r
+       end\r
        for i = 1, length do\r
                local offset1, offset2 = 0, radius\r
                local delta = -radius\r
@@ -180,82 +233,104 @@ worldedit.cylinder = function(pos, axis, length, radius, nodename)
                                delta = delta - (offset2 * 2)\r
                        end\r
                end\r
-               currentpos[axis] = currentpos[axis] + 1\r
+               currentpos[axis] = currentpos[axis] + step\r
        end\r
        return count\r
 end\r
 \r
---adds a spiral at `pos` with size `size`, returning the number of nodes changed\r
-worldedit.spiral = function(pos, size, nodename)\r
-       local shift_x, shift_y\r
-       sa = spiralt(size)\r
-       shift_y = #sa -- "Height" of the Array\r
-       local fe = sa[1]\r
-       shift_x = #fe -- "Width" of the Array\r
-       fe = nil\r
+--adds a pyramid at `pos` with height `height`, composed of `nodename`, returning the number of nodes added\r
+worldedit.pyramid = function(pos, height, nodename)\r
+       local pos1x, pos1y, pos1z = pos.x - height, pos.y, pos.z - height\r
+       local pos2x, pos2y, pos2z = pos.x + height, pos.y + height, pos.z + height\r
+       local pos = {x=0, y=pos1y, z=0}\r
 \r
        local count = 0\r
        local node = {name=nodename}\r
-       for x, v in ipairs(sa) do\r
-               for y, z in ipairs(v) do\r
-                       minetest.env:add_node({x=pos.x - shift_x + x,y=pos.y - shift_y + y,z=pos.z + z}, node)\r
-                       count = count + 1\r
+       local env = minetest.env\r
+       while pos.y <= pos2y do --each vertical level of the pyramid\r
+               pos.x = pos1x\r
+               while pos.x <= pos2x do\r
+                       pos.z = pos1z\r
+                       while pos.z <= pos2z do\r
+                               env:add_node(pos, node)\r
+                               pos.z = pos.z + 1\r
+                       end\r
+                       pos.x = pos.x + 1\r
                end\r
-       end\r
-       return count\r
-end\r
+               count = count + ((pos2y - pos.y) * 2 + 1) ^ 2\r
+               pos.y = pos.y + 1\r
 \r
---wip: \r
-sign = function(s)\r
-       if s > 0 then\r
-               return 1\r
-       end\r
-       if s < 0 then\r
-               return -1\r
-       end\r
-       return 0\r
-end\r
+               pos1x, pos2x = pos1x + 1, pos2x - 1\r
+               pos1z, pos2z = pos1z + 1, pos2z - 1\r
 \r
---wip: needs to be faster\r
-function spiral_index(y, x) -- returns the value at (x, y) in a spiral that starts at 1 and goes outwards\r
-       if y == -x and y >= x then\r
-               return (2 * y + 1) ^ 2\r
-       end\r
-       local l = math.max(math.abs(y), math.abs(x))\r
-       local value\r
-       if math.abs(y) == l then\r
-               value = x\r
-               if y < 0 then\r
-                       value = -value\r
-               end\r
-       else\r
-               value = y\r
-               if x < 0 then\r
-                       value = -value\r
-               end\r
-       end\r
-       t1 = l * 2\r
-       if x + y < 0 then\r
-               t1 = -t1\r
-       end\r
-       t2 = y ^ 2 - x ^ 2\r
-       if t2 < 0 then\r
-               t2 = -t2\r
        end\r
-       return ((2 * l - 1) ^ 2) + (l * 4) + t1 + (t2 * (l - value))\r
+       return count\r
 end\r
 \r
---wip: needs to be faster\r
-function spiralt(side)\r
-       local spiral = {}\r
-       local start, stop = math.floor((-side+1)/2), math.floor((side-1)/2)\r
-       for i = 1, side do\r
-               spiral[i] = {}\r
-               for j = 1, side do\r
-                       spiral[i][j] = side ^ 2 - spiral_index(stop - i + 1,start + j - 1) --moves the coordinates so (0,0) is at the center of the spiral\r
+--adds a spiral at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added\r
+worldedit.spiral = function(pos, width, height, spacer, nodename) --wip: clean this up\r
+       -- spiral matrix - http://rosettacode.org/wiki/Spiral_matrix#Lua\r
+       av, sn = math.abs, function(s) return s~=0 and s/av(s) or 0 end\r
+       local function sindex(z, x) -- returns the value at (x, z) in a spiral that starts at 1 and goes outwards\r
+               if z == -x and z >= x then return (2*z+1)^2 end\r
+               local l = math.max(av(z), av(x))\r
+               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\r
+       end\r
+       local function spiralt(side)\r
+               local ret, id, start, stop = {}, 0, math.floor((-side+1)/2), math.floor((side-1)/2)\r
+               for i = 1, side do\r
+                       for j = 1, side do\r
+                               local id = side^2 - sindex(stop - i + 1,start + j - 1)\r
+                               ret[id] = {x=i,z=j}\r
+                       end\r
+               end\r
+               return ret\r
+       end\r
+       -- connect the joined parts\r
+       local spiral = spiralt(width)\r
+       height = tonumber(height)\r
+       if height < 1 then height = 1 end\r
+       spacer = tonumber(spacer)-1\r
+       if spacer < 1 then spacer = 1 end\r
+       local count = 0\r
+       local node = {name=nodename}\r
+       local np,lp\r
+       for y=0,height do\r
+               lp = nil\r
+               for _,v in ipairs(spiral) do\r
+                       np = {x=pos.x+v.x*spacer, y=pos.y+y, z=pos.z+v.z*spacer}\r
+                       if lp~=nil then\r
+                               if lp.x~=np.x then \r
+                                       if lp.x<np.x then \r
+                                               for i=lp.x+1,np.x do\r
+                                                       minetest.env:add_node({x=i, y=np.y, z=np.z}, node)\r
+                                                       count = count + 1\r
+                                               end\r
+                                       else\r
+                                               for i=np.x,lp.x-1 do\r
+                                                       minetest.env:add_node({x=i, y=np.y, z=np.z}, node)\r
+                                                       count = count + 1\r
+                                               end\r
+                                       end\r
+                               end\r
+                               if lp.z~=np.z then \r
+                                       if lp.z<np.z then \r
+                                               for i=lp.z+1,np.z do\r
+                                                       minetest.env:add_node({x=np.x, y=np.y, z=i}, node)\r
+                                                       count = count + 1\r
+                                               end\r
+                                       else\r
+                                               for i=np.z,lp.z-1 do\r
+                                                       minetest.env:add_node({x=np.x, y=np.y, z=i}, node)\r
+                                                       count = count + 1\r
+                                               end\r
+                                       end\r
+                               end\r
+                       end\r
+                       lp = np\r
                end\r
        end\r
-       return spiral\r
+       return count\r
 end\r
 \r
 --copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes copied\r
@@ -568,7 +643,7 @@ worldedit.deserialize_old = function(originpos, value)
 end\r
 \r
 --saves the nodes and meta defined by positions `pos1` and `pos2` into a file, returning the number of nodes saved\r
-worldedit.metasave = function(pos1, pos2, file)\r
+worldedit.metasave = function(pos1, pos2, file) --wip: simply work with strings instead of doing IO\r
        local path = minetest.get_worldpath() .. "/schems"\r
        local filename = path .. "/" .. file .. ".wem"\r
        os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist\r
@@ -609,7 +684,7 @@ worldedit.metasave = function(pos1, pos2, file)
 end\r
 \r
 --loads the nodes and meta from `file` to position `pos1`, returning the number of nodes loaded\r
-worldedit.metaload = function(pos1, file)\r
+worldedit.metaload = function(pos1, file) --wip: simply work with strings instead of doing IO\r
        local filename = minetest.get_worldpath() .. "/schems/" .. file .. ".wem"\r
        local rows, err = table.load(filename)\r
        if err then return _,err end\r