Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Circular structure builder
- -- Copyright (C) 2012 Timothy Goddard
- -- modified by Marco Nicoletti (Happydude11209)
- --
- -- Permission is hereby granted, free of charge, to any person obtaining a copy of
- -- this software and associated documentation files (the "Software"), to deal in
- -- the Software without restriction, including without limitation the rights to
- -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- -- the Software, and to permit persons to whom the Software is furnished to do so,
- -- subject to the following conditions:
- --
- -- The above copyright notice and this permission notice shall be included in all
- -- copies or substantial portions of the Software.
- --
- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- -- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- -- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- -- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- -- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- --
- -- usage: cbuild <buildType> <radius> [height] [-c]
- -- buildType should be dome, bowl, sphere, or cylinder
- -- radius is distance from centre - total width is actually 2 * radius + 1
- -- the structure will be built with its lowest point on the level the turtle is at
- -- the block the turtle starts on will be the horizontal centre
- -- if -c is passed, will only calculate number of blocks required and not build
- local arg = { ... }
- buildType = arg[1]
- radius = tonumber(arg[2])
- height = tonumber(arg[3])
- cost_calc = false
- resume = false
- blocks = 0
- if arg[1] == "-r" then
- resume = true
- if fs.exists("cbuildsave") then
- saveFile = fs.open("cbuildsave", "r")
- currentFile = saveFile.readAll()
- for key, value in string.gmatch(currentFile, "(%S+)=(%S+)") do
- write(key .. " = ")
- print(value)
- if key == "x" then
- resumeX = tonumber(value)
- elseif key == "y" then
- resumeY = tonumber(value)
- elseif key == "z" then
- resumeZ = tonumber(value)
- elseif key == "radius" then
- radius = tonumber(value)
- elseif key == "type" then
- buildType = value
- elseif key == "height" then
- resumeHeight = tonumber(value)
- elseif key == "precount" then
- resumePrecount = tonumber(value)
- elseif key == "blocks" then
- resumeBlocks = tonumber(value)
- elseif key == "facing" then
- resumeFacing = tonumber(value)
- elseif key == "side" then
- resumeSide = tonumber(value)
- end
- end
- saveFile.close()
- else
- resume = false
- print("No save file exists, sorry.")
- return
- end
- end
- if not resume then
- if arg[3] == "-c" or arg[4] == "-c" then
- cost_calc = true
- end
- end
- needsFuel = false
- if pcall(turtle.select, 16) then
- needsFuel = true
- else
- needsFuel = false
- end
- -- Navigation features
- -- allow the turtle to move while tracking its position
- -- this allows us to just give a destination point and have it go there
- if resume then
- positionx = resumeX
- positiony = resumeY
- facing = resumeFacing
- else
- positionx = radius
- positiony = radius
- facing = 0
- end
- function updateSaveFile(currentX, currentY, currentZ, currentRadius, currentHeight, currentType, currentPrecount, currentBlocks, currentFacing, currentSide)
- saveFile = fs.open("cbuildsave", "w")
- saveFile.writeLine("x=" .. currentX)
- saveFile.writeLine("y=" .. currentY)
- saveFile.writeLine("z=" .. currentZ)
- saveFile.writeLine("radius=" .. currentRadius)
- saveFile.writeLine("height=" .. currentHeight)
- saveFile.writeLine("type=" .. currentType)
- saveFile.writeLine("precount=" .. currentPrecount)
- saveFile.writeLine("blocks=" .. currentBlocks)
- saveFile.writeLine("facing=" .. currentFacing)
- saveFile.writeLine("side=" .. currentSide)
- saveFile.close()
- end
- function turnRightTrack()
- turtle.turnRight()
- facing = facing + 1
- if facing >= 4 then
- facing = 0
- end
- updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
- end
- function turnLeftTrack()
- turtle.turnLeft()
- facing = facing - 1
- if facing < 0 then
- facing = 3
- end
- updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
- end
- function safeForward()
- success = false
- while not success do
- success = turtle.forward()
- if not success then
- print("Blocked attempting to move forward.")
- print("Please clear and press enter to continue.")
- io.read()
- end
- end
- end
- function safeBack()
- success = false
- while not success do
- success = turtle.back()
- if not success then
- print("Blocked attempting to move back.")
- print("Please clear and press enter to continue.")
- io.read()
- end
- end
- end
- function safeUp()
- success = false
- while not success do
- success = turtle.up()
- if not success then
- print("Blocked attempting to move up.")
- print("Please clear and press enter to continue.")
- io.read()
- end
- end
- end
- function moveY(targety)
- if targety == positiony then
- updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
- return
- end
- if (facing ~= 0 and facing ~= 2) then -- check axis
- turnRightTrack()
- end
- while targety > positiony do
- if facing == 0 then
- safeForward()
- else
- safeBack()
- end
- positiony = positiony + 1
- end
- while targety < positiony do
- if facing == 2 then
- safeForward()
- else
- safeBack()
- end
- positiony = positiony - 1
- end
- updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
- end
- function moveX(targetx)
- if targetx == positionx then
- return
- end
- if (facing ~= 1 and facing ~= 3) then -- check axis
- turnRightTrack()
- end
- while targetx > positionx do
- if facing == 1 then
- safeForward()
- else
- safeBack()
- end
- positionx = positionx + 1
- end
- while targetx < positionx do
- if facing == 3 then
- safeForward()
- else
- safeBack()
- end
- positionx = positionx - 1
- end
- updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
- end
- function navigateTo(targetx, targety)
- -- Cost calculation mode - don't move
- if cost_only then
- return
- end
- if needsFuel then
- while turtle.getFuelLevel() < 10 do
- cslot = 10
- turtle.select(cslot)
- while not turtle.refuel(1) do
- fueled = false
- for i = cslot, 16 do
- turtle.select(i)
- if turtle.refuel(1) then
- fueled = true
- i = 17
- end
- end
- if not fueled then
- print("Out of fuel, or not fuel items. Please refill (10-16) and press enter.")
- end
- end
- end
- end
- if facing == 0 or facing == 2 then -- Y axis
- moveY(targety)
- moveX(targetx)
- else
- moveX(targetx)
- moveY(targety)
- end
- end
- function round(num, idp)
- local mult = 10^(idp or 0)
- return math.floor(num * mult + 0.5) / mult
- end
- function progresBar(current, final, displayPercent)
- local termWidth, termHeight = term.getSize()
- local numPossibleEqualsSigns = termWidth - 2
- progres = (current / final) * 100
- equalsSigns = math.floor(numPossibleEqualsSigns * (current / final))
- x = 1
- if displayPercent then
- term.clear()
- end
- term.setCursorPos(x, 1)
- write("|")
- x = x + 1
- for signs = 1, equalsSigns do
- term.setCursorPos(x, 1)
- write("=")
- x = x + 1
- end
- term.setCursorPos(termWidth - 1, 1)
- write("|")
- if displayPercent then
- term.setCursorPos(1, 2)
- write(round(progres, 2) .. "%")
- end
- end
- cslot = 1
- function placeBlock()
- -- Cost calculation mode - don't move
- blocks = blocks + 1
- if cost_only then
- return
- end
- if turtle.getItemCount(cslot) == 0 then
- foundSlot = false
- while not foundSlot do
- for i = 1,9 do
- if turtle.getItemCount(i) > 0 then
- foundSlot = i
- break
- end
- end
- if not foundSlot then
- -- No resources
- print("Out of building materials. Please refill (1-9) and press enter to continue.")
- io.read()
- end
- end
- cslot = foundSlot
- turtle.select(foundSlot)
- end
- turtle.placeDown()
- updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
- end
- -- Main building functions
- preCount = 0
- progres = 0
- width = radius * 2 + 1
- sqrt3 = 3 ^ 0.5
- boundary_radius = radius + 1.0
- boundary2 = boundary_radius ^ 2
- function buildCylinder(calculateCost, zstart, zend)
- if calculateCost then
- cost_only = true
- else
- cost_only = false
- end
- if resume then
- zstart = resumeZ
- zend = resumeHeight
- end
- -- This loop is for each vertical layer through the cylinder
- for z = zstart,zend do
- if not cost_only then
- safeUp()
- end
- if cost_only then
- progresBar(z, zend, false)
- print("Calculating...")
- -- print("Layer " .. z)
- end
- -- cz2 = (radius - z) ^ 2
- -- limit_offset_y = (boundary2 - cz2) ^ 0.5
- limit_offset_y = boundary_radius
- max_offset_y = math.ceil(limit_offset_y)
- -- We do first the +x side, then the -x side to make movement efficient
- for side = 0,1 do
- if resume then
- side = resumeSide
- end
- -- On the right we go from small y to large y, on the left reversed
- -- This makes us travel clockwise around each layer
- if (side == 0) then
- if resume then
- ystart = resumeY
- else
- ystart = radius - max_offset_y
- end
- yend = radius + max_offset_y
- ystep = 1
- else
- ystart = radius + max_offset_y
- yend = radius - max_offset_y
- ystep = -1
- end
- for y = ystart,yend,ystep do
- cy2 = (radius - y) ^ 2
- -- remainder2 = (boundary2 - cz2 - cy2)
- remainder2 = (boundary2 - cy2)
- if remainder2 >= 0 then
- -- This is the maximum difference in x from the centre we can be without definitely being outside the radius
- -- max_offset_x = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
- max_offset_x = math.ceil((boundary2 - cy2) ^ 0.5)
- -- Only do either the +x or -x side
- if (side == 0) then
- -- +x side
- xstart = radius
- xend = radius + max_offset_x
- else
- -- -x side
- xstart = radius - max_offset_x
- xend = radius - 1
- end
- -- Reverse direction we traverse xs when in -y side
- if y > radius then
- temp = xstart
- xstart = xend
- xend = temp
- xstep = -1
- else
- xstep = 1
- end
- for x = xstart,xend,xstep do
- cx2 = (radius - x) ^ 2
- -- distance_to_centre = (cx2 + cy2 + cz2) ^ 0.5
- distance_to_centre = (cx2 + cy2) ^ 0.5
- -- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
- if distance_to_centre < boundary_radius and distance_to_centre + sqrt3 >= boundary_radius then
- offsets = {{0, 1, 0}, {0, -1, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 0, 1}, {0, 0, -1}}
- for i=1,6 do
- offset = offsets[i]
- dx = offset[1]
- dy = offset[2]
- -- dz = offset[3]
- -- if ((radius - (x + dx)) ^ 2 + (radius - (y + dy)) ^ 2 + (radius - (z + dz)) ^ 2) ^ 0.5 >= boundary_radius then
- if ((radius - (x + dx)) ^ 2 + (radius - (y + dy)) ^ 2) ^ 0.5 >= boundary_radius then
- -- This is a point to use
- navigateTo(x, y)
- placeBlock()
- if not cost_only then
- progresBar(blocks, preCount, true)
- write(", Layer " .. z .. "/" .. zend)
- end
- break
- end
- end
- end
- end
- end
- end
- end
- end
- if cost_only then
- preCount = blocks
- blocks = 0
- end
- end
- function buildOther(calculateCost, zstart, zend)
- if calculateCost then
- cost_only = true
- else
- cost_only = false
- end
- -- This loop is for each vertical layer through the sphere or dome.
- for z = zstart,zend do
- if not cost_only then
- safeUp()
- end
- if cost_only then
- progresBar(z, zend, false)
- print("Calculating...")
- -- print("Layer " .. z)
- end
- cz2 = (radius - z) ^ 2
- limit_offset_y = (boundary2 - cz2) ^ 0.5
- max_offset_y = math.ceil(limit_offset_y)
- -- We do first the +x side, then the -x side to make movement efficient
- for side = 0,1 do
- -- On the right we go from small y to large y, on the left reversed
- -- This makes us travel clockwise around each layer
- if (side == 0) then
- ystart = radius - max_offset_y
- yend = radius + max_offset_y
- ystep = 1
- else
- ystart = radius + max_offset_y
- yend = radius - max_offset_y
- ystep = -1
- end
- for y = ystart,yend,ystep do
- cy2 = (radius - y) ^ 2
- remainder2 = (boundary2 - cz2 - cy2)
- if remainder2 >= 0 then
- -- This is the maximum difference in x from the centre we can be without definitely being outside the radius
- max_offset_x = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
- -- Only do either the +x or -x side
- if (side == 0) then
- -- +x side
- xstart = radius
- xend = radius + max_offset_x
- else
- -- -x side
- xstart = radius - max_offset_x
- xend = radius - 1
- end
- -- Reverse direction we traverse xs when in -y side
- if y > radius then
- temp = xstart
- xstart = xend
- xend = temp
- xstep = -1
- else
- xstep = 1
- end
- for x = xstart,xend,xstep do
- cx2 = (radius - x) ^ 2
- distance_to_centre = (cx2 + cy2 + cz2) ^ 0.5
- -- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
- if distance_to_centre < boundary_radius and distance_to_centre + sqrt3 >= boundary_radius then
- offsets = {{0, 1, 0}, {0, -1, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 0, 1}, {0, 0, -1}}
- for i=1,6 do
- offset = offsets[i]
- dx = offset[1]
- dy = offset[2]
- dz = offset[3]
- if ((radius - (x + dx)) ^ 2 + (radius - (y + dy)) ^ 2 + (radius - (z + dz)) ^ 2) ^ 0.5 >= boundary_radius then
- -- This is a point to use
- navigateTo(x, y)
- placeBlock()
- if not cost_only then
- progresBar(blocks, preCount, true)
- write(", Layer " .. z .. "/" .. zend)
- end
- break
- end
- end
- end
- end
- end
- end
- end
- end
- if cost_only then
- preCount = blocks
- blocks = 0
- end
- end
- cost_only = true
- if buildType == "cylinder" then
- buildCylinder(true, 1, height)
- if not cost_calc then
- cost_only = false
- buildCylinder(false, 1, height)
- end
- elseif buildType == "sphere" then
- buildOther(true, 0, width - 1)
- if not cost_calc then
- cost_only = false
- buildOther(false, 0, width - 1)
- end
- elseif buildType == "dome" then
- buildOther(true, radius, width - 1)
- if not cost_calc then
- cost_only = false
- buildOther(false, radius, width - 1)
- end
- elseif buildType == "bowl" then
- buildOther(true, 0, radius)
- if not cost_calc then
- cost_only = false
- buildOther(false, 0, radius)
- end
- else
- print("Unknown type")
- print("Usage: cbuild <type> <radius> [height] [-c] [-r]")
- print("Acceptable types: sphere, dome, bowl, and cylinder")
- print("pass -c to calculate needed blocks")
- -- print("pass -r to resume from reload")
- return
- end
- -- Return to where we started in x,y place and turn to face original direction
- -- Don't change vertical place though - should be solid under us!
- navigateTo(radius, radius)
- term.clear()
- term.setCursorPos(1,1)
- while (facing > 0) do
- turnLeftTrack()
- end
- if cost_calc then
- blocks = preCount
- end
- if buildType == "cylinder" then
- print("Blocks used: " .. blocks)
- print("While building a cylinder of radius " .. radius .. " and height " .. height)
- else
- print("Blocks used: " .. blocks)
- print("While building a " .. buildType .. " of radius " .. radius)
- end
- fs.delete("cbuildsave")
Advertisement
Add Comment
Please, Sign In to add comment