Turtle programme
unknown
plain_text
2 years ago
63 kB
5
Indexable
-- Variable Setup
-- Command Line input Table
local argTable = {...}
-- Flag Variables: These are conditions for different features (all flags are named foo_bar, all other variables are named fooBar)
local cmd_line = false
local cmd_line_resume = false
local cmd_line_cost_only = false
local chain_next_shape = false -- This tells goHome() where to end, if true it goes to (0, 0, positionZ) if false it goes to (-1, -1, 0)
local special_chain = false -- For certain shapes that finish where the next chained shape should start, goHome() will only turn to face 0 if true
local cost_only = false
local sim_mode = false
local resupply = false
local enderchest_refilling = false
local can_use_gps = false
local return_to_home = false -- whether the turtle shall return to start after build
-- Record Keeping Variables: These are for recoding the blocks and fuel used
local blocks = 0
local fuel = 0
-- Position Tracking Variables: These are for keeping track of the turtle's position
local positionX = 0
local positionY = 0
local positionZ = 0
local facing = 0
local gpsPositionX = 0
local gpsPositionY = 0
local gpsPositionZ = 0
local gpsFacing = 0
-- General Variables: Other variables that don't fit in the other categories
local choice = ""
-- Progress Table: These variables are the tables that the turtle's progress is tracked in
local tempProgTable = {}
local progTable = {} --This is the LOCAL table! used for local stuff only, and is ONLY EVER WRITTEN when sim_mode is FALSE
local progFileName = "ShapesProgressFile"
-- Utility functions
function writeOut(...) -- ... lets writeOut() pass any arguments to print(). so writeOut(1,2,3) is the same as print(1,2,3). previously writeOut(1,2,3) would have been the same as print(1)
for i, v in ipairs(arg) do
print(v)
end
end
function getInput(inputType, message, option1, option2)
local input = ""
if inputType == "string" then
writeOut(message.. "(" ..option1 .. " or "..option2..")" )
while true do
input = io.read()
input = string.lower(input)
if input ~= option1 and input ~= option2 then
writeOut("You didn't enter a valid option. Please try again.")
else
return input
end
end
end
if inputType == "int" then
writeOut(message)
while true do
input = io.read()
if tonumber(input) ~= nil then
return tonumber(input)
else
writeOut("Need a number. Please try again")
end
end
end
end
function wrapModules() -- checks for and wraps turtle modules
local test = 0
if peripheral.getType("left" )== "resupply" then
resupplymodule=peripheral.wrap("left")
resupply = true
elseif peripheral.getType("right") == "resupply" then
resupplymodule=peripheral.wrap("right")
resupply = true
end
if peripheral.getType("left") == "modem" then
modem=peripheral.wrap("left")
test, _, _ = gps.locate(1)
if test ~= nil then
can_use_gps = true
end
elseif peripheral.getType("right") == "modem" then
modem=peripheral.wrap("right")
test, _, _ = gps.locate(1)
if test ~= nil then
can_use_gps = true
end
end
if resupply then
return "resupply"
end
end
function linkToRSStation() -- Links to resupply station
if resupplymodule.link() then
return true
else
writeOut("Please put Resupply Station to the left of the turtle and press Enter to continue")
io.read()
linkToRSStation()
end
end
function compareResources()
if (turtle.compareTo(1) == false) then
turtle.drop()
end
end
function firstFullSlot()
for i = 1, 16 do
if (turtle.getItemCount(i) > 1) then
return i
end
end
end
function turtleEmpty()
for i = 1, 16 do
if (turtle.getItemCount(i) > 1) then
return false
end
end
return true
end
function checkResources()
if resupply then
if turtle.getItemCount(activeSlot) <= 1 then
while not(resupplymodule.resupply(1)) do
os.sleep(0.5)
end
end
elseif enderchest_refilling then
compareResources()
while (turtle.getItemCount(activeSlot) <= 1) do
if (activeSlot == 15) and (turtle.getItemCount(activeSlot)<=1) then
turtle.select(16)
turtle.digUp()
for i = 1, 15 do
turtle.select(i)
turtle.drop()
end
turtle.select(16)
turtle.placeUp()
turtle.select(1)
for i = 1, 15 do
turtle.suckUp()
end
turtle.select(16)
turtle.digUp()
activeSlot = 1
turtle.select(activeSlot)
else
activeSlot = activeSlot + 1
-- writeOut("Turtle slot empty, trying slot "..activeSlot)
turtle.select(activeSlot)
end
compareResources()
os.sleep(0.2)
end
else
compareResources()
while (turtle.getItemCount(activeSlot) <= 1) do
if turtleEmpty() then
writeOut("Turtle is empty, please put building block in slots and press enter to continue")
io.read()
activeSlot = 1
turtle.select(activeSlot)
else
activeSlot = firstFullSlot()
turtle.select(activeSlot)
end
compareResources()
end
end
end
function checkFuel()
if (not(tonumber(turtle.getFuelLevel()) == nil)) then
while turtle.getFuelLevel() < 50 do
writeOut("Turtle almost out of fuel, pausing. Please drop fuel in inventory. And press enter.")
io.read()
turtle.refuel()
end
end
end
function placeBlock()
blocks = blocks + 1
simulationCheck()
if cost_only then
return
end
if turtle.detectDown() and not turtle.compareDown() then
turtle.digDown()
end
checkResources()
turtle.placeDown()
progressUpdate()
end
function round(toRound, decimalPlace) -- Needed for Polygons
local mult = 10 ^ (decimalPlace or 0)
local sign = toRound / math.abs(toRound)
return sign * math.floor(((math.abs(toRound) * mult) + 0.5)) / mult
end
-- Navigation functions
-- Allow the turtle to move while tracking its position
-- This allows us to just give a destination point and have it go there
function turnRightTrack()
simulationCheck()
facing = facing + 1
if facing >= 4 then
facing = 0
end
progressUpdate()
if cost_only then
return
end
turtle.turnRight()
end
function turnLeftTrack()
simulationCheck()
facing = facing - 1
if facing < 0 then
facing = 3
end
progressUpdate()
if cost_only then
return
end
turtle.turnLeft()
end
function turnAroundTrack()
turnLeftTrack()
turnLeftTrack()
end
function turnToFace(direction)
if (direction < 0) then
return false
end
direction = direction % 4
while facing ~= direction do
turnRightTrack()
end
return true
end
function safeForward()
simulationCheck()
if facing == 0 then
positionY = positionY + 1
elseif facing == 1 then
positionX = positionX + 1
elseif facing == 2 then
positionY = positionY - 1
elseif facing == 3 then
positionX = positionX - 1
end
fuel = fuel + 1
progressUpdate()
if cost_only then
return
end
checkFuel()
local success = false
local tries = 0
while not success do
success = turtle.forward()
if not success then
while (not success) and tries < 6 do
tries = tries + 1
turtle.dig()
success = turtle.forward()
sleep(0.3)
end
if not success then
writeOut("Blocked attempting to move forward.")
writeOut("Please clear and press enter to continue.")
io.read()
end
end
end
end
function safeBack()
simulationCheck()
if facing == 0 then
positionY = positionY - 1
elseif facing == 1 then
positionX = positionX - 1
elseif facing == 2 then
positionY = positionY + 1
elseif facing == 3 then
positionX = positionX + 1
end
fuel = fuel + 1
progressUpdate()
if cost_only then
return
end
checkFuel()
local success = false
local tries = 0
while not success do
success = turtle.back()
if not success then
turnAroundTrack()
while turtle.detect() and tries < 6 do
tries = tries + 1
if turtle.dig() then
break
end
sleep(0.3)
end
turnAroundTrack()
success = turtle.back()
if not success then
writeOut("Blocked attempting to move back.")
writeOut("Please clear and press enter to continue.")
io.read()
end
end
end
end
function safeUp()
simulationCheck()
positionZ = positionZ + 1
fuel = fuel + 1
progressUpdate()
if cost_only then
return
end
checkFuel()
local success = false
while not success do
success = turtle.up()
if not success then
while turtle.detectUp() do
if not turtle.digUp() then
writeOut("Blocked attempting to move up.")
writeOut("Please clear and press enter to continue.")
io.read()
end
end
end
end
end
function safeDown()
simulationCheck()
positionZ = positionZ - 1
fuel = fuel + 1
progressUpdate()
if cost_only then
return
end
checkFuel()
local success = false
while not success do
success = turtle.down()
if not success then
while turtle.detectDown() do
if not turtle.digDown() then
writeOut("Blocked attempting to move down.")
writeOut("Please clear and press enter to continue.")
io.read()
end
end
end
end
end
function moveY(targetY)
if targetY == positionY then
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
end
while targetY < positionY do
if facing == 2 then
safeForward()
else
safeBack()
end
end
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
end
while targetX < positionX do
if facing == 3 then
safeForward()
else
safeBack()
end
end
end
function moveZ(targetZ)
if targetZ == positionZ then
return
end
while targetZ < positionZ do
safeDown()
end
while targetZ > positionZ do
safeUp()
end
end
-- I *HIGHLY* suggest formatting all shape subroutines to use the format that dome() uses; specifically, navigateTo(x,y,[z]) then placeBlock(). This should ensure proper "data recording" and also makes readability better
function navigateTo(targetX, targetY, targetZ, move_z_first)
targetZ = targetZ or positionZ -- If targetZ isn't used in the function call, it defaults to its current z position, this should make it compatible with all previous implementations of navigateTo()
move_z_first = move_z_first or false -- Defaults to moving z last, if true is passed as 4th argument, it moves vertically first
if move_z_first then
moveZ(targetZ)
end
if facing == 0 or facing == 2 then -- Y axis
moveY(targetY)
moveX(targetX)
else
moveX(targetX)
moveY(targetY)
end
if not move_z_first then
moveZ(targetZ)
end
end
function goHome()
if chain_next_shape then
if not special_chain then
navigateTo(0, 0) -- So another program can chain multiple shapes together to create bigger structures
end
else
navigateTo(-1, -1, 0) -- So the user can collect the turtle when it is done, not 0,0,0 because some shapes use the 0,0 column
end
turnToFace(0)
end
-- Shape Building functions
function drawLine(endX, endY, startX, startY)
startX = startX or positionX
startY = startY or positionY
deltaX = math.abs(endX - startX)
deltaY = math.abs(endY - startY)
errorVar = 0
if deltaX >= deltaY then
deltaErr = math.abs(deltaY/deltaX)
if startX < endX then
if startY < endY then
counterY = startY
for counterX = startX, endX do
navigateTo(counterX, counterY)
placeBlock()
errorVar = errorVar + deltaErr
if errorVar >= 0.5 then
counterY = counterY + 1
errorVar = errorVar - 1
end
end
else
counterY = startY
for counterX = startX, endX do
navigateTo(counterX, counterY)
placeBlock()
errorVar = errorVar + deltaErr
if errorVar >= 0.5 then
counterY = counterY - 1
errorVar = errorVar - 1
end
end
end
else
if startY < endY then
counterY = startY
for counterX = startX, endX, -1 do
navigateTo(counterX, counterY)
placeBlock()
errorVar = errorVar + deltaErr
if errorVar >= 0.5 then
counterY = counterY + 1
errorVar = errorVar - 1
end
end
else
counterY = startY
for counterX = startX, endX, -1 do
navigateTo(counterX, counterY)
placeBlock()
errorVar = errorVar + deltaErr
if errorVar >= 0.5 then
counterY = counterY - 1
errorVar = errorVar - 1
end
end
end
end
else
deltaErr = math.abs(deltaX/deltaY)
if startY < endY then
if startX < endX then
counterX = startX
for counterY = startY, endY do
navigateTo(counterX, counterY)
placeBlock()
errorVar = errorVar + deltaErr
if errorVar >= 0.5 then
counterX = counterX + 1
errorVar = errorVar - 1
end
end
else
counterX = startX
for counterY = startY, endY do
navigateTo(counterX, counterY)
placeBlock()
errorVar = errorVar + deltaErr
if errorVar >= 0.5 then
counterX = counterX - 1
errorVar = errorVar - 1
end
end
end
else
if startX < endX then
counterX = startX
for counterY = startY, endY, -1 do
navigateTo(counterX, counterY)
placeBlock()
errorVar = errorVar + deltaErr
if errorVar >= 0.5 then
counterX = counterX + 1
errorVar = errorVar - 1
end
end
else
counterX = startX
for counterY = startY, endY, -1 do
navigateTo(counterX, counterY)
placeBlock()
errorVar = errorVar + deltaErr
if errorVar >= 0.5 then
counterX = counterX - 1
errorVar = errorVar - 1
end
end
end
end
end
end
function rectangle(width, depth, startX, startY)
startX = startX or positionX
startY = startY or positionY
endX = startX + width - 1
endY = startY + depth - 1
drawLine(startX, endY, startX, startY)
drawLine(endX, endY, startX, endY)
drawLine(endX, startY, endX, endY)
drawLine(startX, startY, endX, startY)
end
function square(length, startX, startY)
startX = startX or positionX
startY = startY or positionY
rectangle(length, length, startX, startY)
end
function wall(depth, height)
for i = 1, depth do
for j = 1, height do
placeBlock()
if j < height then
navigateTo(positionX, positionY, positionZ + 1)
end
end
if (i ~= depth) then
navigateTo(positionX, positionY + 1, 0)
end
end
end
function platform(width, depth, startX, startY)
startX = startX or positionX
startY = startY or positionY
endX = startX + width - 1
endY = startY + depth - 1
forward = true
for counterY = startY, endY do
if forward then
for counterX = startX, endX do
navigateTo(counterX, counterY)
placeBlock()
end
else
for counterX = endX, startX, -1 do
navigateTo(counterX, counterY)
placeBlock()
end
end
forward = not forward
end
end
function cuboid(width, depth, height, hollow)
for i = 0, height - 1 do
navigateTo(0, 0, i)
if (hollow == "n") then
platform(width, depth, 0, 0)
else
rectangle(width, depth, 0, 0)
end
end
end
function pyramid(length, hollow)
-- local height = math.ceil(length / 2) - 1
i = 0
while (length > 0) do
navigateTo(i, i, i)
if (hollow == "y") then
rectangle(length, length, i, i)
else
platform(length, length, i, i)
end
i = i + 1
length = length - 2
end
end
function stair(width, height, startX, startY) -- Last two might be able to be used to make a basic home-like shape later?
startX = startX or positionX
startY = startY or positionY
endX = startX + width - 1
endY = startY + height - 1
forward = true
for counterY = startY, endY do
if forward then
for counterX = startX, endX do
navigateTo(counterX, counterY)
placeBlock()
end
else
for counterX = endX, startX, -1 do
navigateTo(counterX, counterY)
placeBlock()
end
end
if counterY ~= endY then
navigateTo(positionX, positionY, positionZ + 1)
forward = not forward
end
end
end
function circle(diameter)
odd = not (math.fmod(diameter, 2) == 0)
radius = diameter / 2
if odd then
width = (2 * math.ceil(radius)) + 1
offset = math.floor(width/2)
else
width = (2 * math.ceil(radius)) + 2
offset = math.floor(width/2) - 0.5
end
--diameter --radius * 2 + 1
sqrt3 = 3 ^ 0.5
boundaryRadius = radius + 1.0
boundary2 = boundaryRadius ^ 2
radius2 = radius ^ 2
z = math.floor(radius)
cz2 = (radius - z) ^ 2
limitOffsetY = (boundary2 - cz2) ^ 0.5
maxOffsetY = math.ceil(limitOffsetY)
-- 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 (from below) around each layer
if (side == 0) then
yStart = math.floor(radius) - maxOffsetY
yEnd = math.floor(radius) + maxOffsetY
yStep = 1
else
yStart = math.floor(radius) + maxOffsetY
yEnd = math.floor(radius) - maxOffsetY
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
maxOffsetX = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
-- Only do either the +x or -x side
if (side == 0) then
-- +x side
xStart = math.floor(radius)
xEnd = math.floor(radius) + maxOffsetX
else
-- -x side
xStart = math.floor(radius) - maxOffsetX
xEnd = math.floor(radius) - 1
end
-- Reverse direction we traverse xs when in -y side
if y > math.floor(radius) then
temp = xStart
xStart = xEnd
xEnd = temp
xStep = -1
else
xStep = 1
end
for x = xStart,xEnd,xStep do
-- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
if isSphereBorder(offset, x, y, z, radius2) then
navigateTo(x, y)
placeBlock()
end
end
end
end
end
end
function blockInSphereIsFull(offset, x, y, z, radiusSq)
x = x - offset
y = y - offset
z = z - offset
x = x ^ 2
y = y ^ 2
z = z ^ 2
return x + y + z <= radiusSq
end
function isSphereBorder(offset, x, y, z, radiusSq)
spot = blockInSphereIsFull(offset, x, y, z, radiusSq)
if spot then
spot = not blockInSphereIsFull(offset, x, y - 1, z, radiusSq) or
not blockInSphereIsFull(offset, x, y + 1, z, radiusSq) or
not blockInSphereIsFull(offset, x - 1, y, z, radiusSq) or
not blockInSphereIsFull(offset, x + 1, y, z, radiusSq) or
not blockInSphereIsFull(offset, x, y, z - 1, radiusSq) or
not blockInSphereIsFull(offset, x, y, z + 1, radiusSq)
end
return spot
end
function dome(typus, diameter)
-- Main dome and sphere building routine
odd = not (math.fmod(diameter, 2) == 0)
radius = diameter / 2
if odd then
width = (2 * math.ceil(radius)) + 1
offset = math.floor(width/2)
else
width = (2 * math.ceil(radius)) + 2
offset = math.floor(width/2) - 0.5
end
--diameter --radius * 2 + 1
sqrt3 = 3 ^ 0.5
boundaryRadius = radius + 1.0
boundary2 = boundaryRadius ^ 2
radius2 = radius ^ 2
if typus == "dome" then
zstart = math.ceil(radius)
elseif typus == "sphere" then
zstart = 1
elseif typus == "bowl" then
zstart = 1
end
if typus == "bowl" then
zend = math.floor(radius)
else
zend = width - 1
end
-- This loop is for each vertical layer through the sphere or dome.
for z = zstart,zend do
if not cost_only and z ~= zstart then
navigateTo(positionX, positionY, positionZ + 1)
end
--writeOut("Layer " .. z)
cz2 = (radius - z) ^ 2
limitOffsetY = (boundary2 - cz2) ^ 0.5
maxOffsetY = math.ceil(limitOffsetY)
-- 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 (from below) around each layer
if (side == 0) then
yStart = math.floor(radius) - maxOffsetY
yEnd = math.floor(radius) + maxOffsetY
yStep = 1
else
yStart = math.floor(radius) + maxOffsetY
yEnd = math.floor(radius) - maxOffsetY
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
maxOffsetX = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
-- Only do either the +x or -x side
if (side == 0) then
-- +x side
xStart = math.floor(radius)
xEnd = math.floor(radius) + maxOffsetX
else
-- -x side
xStart = math.floor(radius) - maxOffsetX
xEnd = math.floor(radius) - 1
end
-- Reverse direction we traverse xs when in -y side
if y > math.floor(radius) then
temp = xStart
xStart = xEnd
xEnd = temp
xStep = -1
else
xStep = 1
end
for x = xStart,xEnd,xStep do
-- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
if isSphereBorder(offset, x, y, z, radius2) then
navigateTo(x, y)
placeBlock()
end
end
end
end
end
end
end
function cylinder(diameter, height)
for i = 1, height do
circle(diameter)
if i ~= height then
navigateTo(positionX, positionY, positionZ + 1)
end
end
end
function isINF(value)
return (value == math.huge or value == -math.huge)
end
function isNAN(value)
return value ~= value
end
polygonCornerList = {} -- Public list of corner coords for n-gons, will be used for hexagons, octagons, and future polygons.
-- It should be a nested list eg. {{x0,y0},{x1,y1},{x2,y2}...}
function constructPolygonFromList() -- Uses polygonCornerList to draw sides between each point
if #polygonCornerList == 0 then
return false
end
for i = 1, #polygonCornerList do
if (isINF(polygonCornerList[i][1]) or isNAN(polygonCornerList[i][1])) then
polygonCornerList[i][1] = 0
end
if (isINF(polygonCornerList[i][2]) or isNAN(polygonCornerList[i][2])) then
polygonCornerList[i][2] = 0
end
end
for i = 1, #polygonCornerList do
startX = polygonCornerList[i][1]
startY = polygonCornerList[i][2]
if i == #polygonCornerList then
j = 1
else
j = i + 1
end
stopX = polygonCornerList[j][1]
stopY = polygonCornerList[j][2]
drawLine(stopX, stopY, startX, startY)
end
return true
end
function circleLikePolygon(numSides, diameter, offsetAngle) -- works like the circle code, allows building a circle with the same diameter from the same start point to inscribe the polygon. offSetAngle is optional, defaults to 0.
radius = diameter / 2
if (numSides % 2 == 1) then -- if numSides is odd
startAngle = math.pi / 2 -- always have a vertex at 90 deg (+y) and at least one grid aligned edge. Before offSetAngle
else -- if numSides is even
startAngle = (math.pi / 2) + (math.pi / numSides) -- always have at least two grid aligned edges. Before offSetAngle
end
startAngle = startAngle + (math.rad(offsetAngle or 0)) -- offsetAngle will be in degrees
for i = 1, numSides do
polygonCornerList[i] = {radius * math.cos(startAngle + ((i - 1) * ((math.pi * 2) / numSides))), radius * math.sin(startAngle + ((i - 1) * ((math.pi * 2) / numSides)))}
end
for i = 1, #polygonCornerList do
polygonCornerList[i][1] = round(polygonCornerList[i][1] + radius + 1)
polygonCornerList[i][2] = round(polygonCornerList[i][2] + radius + 1)
end
if not constructPolygonFromList() then
error("This error should never happen.")
end
end
function polygon(numSides, sideLength, offsetAngle) -- offSetAngle is optional, defaults to 0.
currentAngle = 0 + (math.rad(offsetAngle or 0)) -- start at 0 or offset angle. offsetAngle will be in degrees
addAngle = ((math.pi * 2) / numSides)
pointerX, pointerY = 0, 0
sideLength = sideLength - 1
for i = 1, numSides do
polygonCornerList[i] = {pointerX, pointerY}
pointerX = sideLength * math.cos(currentAngle) + pointerX
pointerY = sideLength * math.sin(currentAngle) + pointerY
currentAngle = currentAngle + addAngle
end
minX, minY = 0, 0
for i = 1, #polygonCornerList do -- find the smallest x and y
if (polygonCornerList[i][1] <= minX) then
minX = polygonCornerList[i][1]
end
if (polygonCornerList[i][2] <= minY) then
minY = polygonCornerList[i][2]
end
end
minX = math.abs(minX) -- should eventually calculate the difference between minX and 0
minY = math.abs(minY) -- should eventually calculate the difference between minY and 0
for i = 1, #polygonCornerList do -- make it bounded to 0, 0
polygonCornerList[i][1] = round(polygonCornerList[i][1] + minX)
polygonCornerList[i][2] = round(polygonCornerList[i][2] + minY)
end
if not constructPolygonFromList() then
error("This error should never happen.")
end
end
function circleLikePolygonPrism(numSides, diameter, height, offSetAngle)
offSetAngle = offSetAngle or 0
for i = 1, height do
circleLikePolygon(numSides, diameter, offsetAngle)
if i ~= height then
navigateTo(positionX, positionY, positionZ + 1)
end
end
end
function polygonPrism(numSides, sideLength, height, offSetAngle)
offSetAngle = offSetAngle or 0
for i = 1, height do
polygon(numSides, sideLength, offSetAngle)
if i ~= height then
navigateTo(positionX, positionY, positionZ + 1)
end
end
end
function hexagon(sideLength) -- Deprecated, please use polygon(6, sideLength, 0). Fills out polygonCornerList with the points for a hexagon.
sideLength = sideLength - 1
local changeX = sideLength / 2
local changeY = round(math.sqrt(3) * changeX, 0)
changeX = round(changeX, 0)
polygonCornerList[1] = {changeX, 0}
polygonCornerList[2] = {(changeX + sideLength), 0}
polygonCornerList[3] = {((2 * changeX) + sideLength), changeY}
polygonCornerList[4] = {(changeX + sideLength), (2 * changeY)}
polygonCornerList[5] = {changeX, (2 * changeY)}
polygonCornerList[6] = {0, changeY}
if not constructPolygonFromList() then
error("This error should never happen.")
end
end
function octagon(sideLength) -- Deprecated, please use polygon(8, sideLength, 0). Fills out polygonCornerList with the points for an octagon
sideLength = sideLength - 1
local change = round((sideLength - 1) / math.sqrt(2), 0)
polygonCornerList[1] = {change, 0}
polygonCornerList[2] = {(change + sideLength), 0}
polygonCornerList[3] = {((2 * change) + sideLength), change}
polygonCornerList[4] = {((2 * change) + sideLength), (change + sideLength)}
polygonCornerList[5] = {(change + sideLength), ((2 * change) + sideLength)}
polygonCornerList[6] = {change, ((2 * change) + sideLength)}
polygonCornerList[7] = {0, (change + sideLength)}
polygonCornerList[8] = {0, change}
if not constructPolygonFromList() then
error("This error should never happen.")
end
end
function hexagonPrism(length, height) -- Deprecated, please use polygonPrism(6, sideLength, height, 0).
for i = 1, height do
hexagon(length)
if i ~= height then
navigateTo(positionX, positionY, positionZ + 1)
end
end
end
function octagonPrism(length, height) -- Deprecated, please use polygonPrism(8, sideLength, height, 0).
for i = 1, height do
octagon(length)
if i ~= height then
navigateTo(positionX, positionY, positionZ + 1)
end
end
end
-- Previous Progress Resuming, Simulation functions, Command Line, and File Backend
-- Will check for a "progress" file.
function CheckForPrevious()
if fs.exists(progFileName) then
return true
else
return false
end
end
-- Creates a progress file, containing a serialized table consisting of the shape type, shape input params, and the last known x, y, and z coords of the turtle (beginning of build project)
function ProgressFileCreate()
if not CheckForPrevious() then
fs.makeDir(progFileName)
return true
else
return false
end
end
-- Deletes the progress file (at the end of the project, or at beginning if user chooses to delete old progress)
function ProgressFileDelete()
if fs.exists(progFileName) then
fs.delete(progFileName)
return true
else
return false
end
end
-- To read the shape params from the file. Shape type, and input params (e.g. "dome" and radius)
function ReadShapeParams()
-- TODO. Unneeded for now, can just use the table elements directly
end
function WriteShapeParams(...) -- The ... lets it take any number of arguments and stores it to the table arg{} | This is still unused anywhere
local paramTable = arg
local paramName = "param"
local paramName2 = paramName
for i, v in ipairs(paramTable) do -- Iterates through the args passed to the function, ex. paramTable[1] i = 1 so paramName2 should be "param1", tested and works!
paramName2 = paramName .. i
tempProgTable[paramName2] = v
progTable[paramName2] = v
end
end
-- function to write the progress to the file (x, y, z)
function writeProgress()
local progFile
local progString = ""
if not (sim_mode or cost_only) then
progString = textutils.serialize(progTable) -- Put in here to save processing time when in cost_only
progFile = fs.open(progFileName, "w")
progFile.write(progString)
progFile.close()
end
end
-- Reads progress from file (shape, x, y, z, facing, blocks, param1, param2, param3)
function readProgress()
local progFile = fs.open(progFileName, "r")
local readProgTable = textutils.unserialize(progFile.readAll())
progFile.close()
return readProgTable
end
-- compares the progress read from the file to the current sim progress. needs all four params
function compareProgress()
local progTableIn = progTable
local readProgTable = readProgress()
if (progTableIn.shape == readProgTable.shape and progTableIn.x == readProgTable.x and progTableIn.y == readProgTable.y and progTableIn.blocks == readProgTable.blocks and progTableIn.facing == readProgTable.facing) then
writeOut("All caught up!")
return true -- We're caught up!
else
return false -- Not there yet...
end
end
function getGPSInfo() -- TODO: finish this
position = gps.locate()
gpsPositionX = position.x
gpsPositionZ = position.y
gpsPositionY = position.z
end
function setSimFlags(b)
sim_mode = b
cost_only = b
if cmd_line_cost_only then
cost_only = true
end
end
function simulationCheck() -- checks state of the simulation
if sim_mode then
if compareProgress() then
setSimFlags(false) -- If we're caught up, un-set flags
else
setSimFlags(true) -- If not caught up, just re-affirm that the flags are set
end
end
end
function continueQuery()
if cmd_line_resume then
return true
else
if not cmd_line then
writeOut("Do you want to continue the last job?")
local yes = io.read()
if yes == "y" then
return true
else
return false
end
end
end
end
function progressUpdate() -- This ONLY updates the local table variable. Writing is handled above. -- I want to change this to allow for any number of params
progTable = {shape = choice, enderchest_refilling = tempProgTable.enderchest_refilling, param1 = tempProgTable.param1, param2 = tempProgTable.param2, param3 = tempProgTable.param3, param4 = tempProgTable.param4, x = positionX, y = positionY, z = positionZ, facing = facing, blocks = blocks}
if not sim_mode then
writeProgress()
end
end
-- Command Line
function checkCommandLine() --True if arguments were passed
if #argTable > 0 then
cmd_line = true
return true
else
cmd_line = false
return false
end
end
function needsHelp() -- True if -h is passed
for i, v in pairs(argTable) do
if v == "-h" or v == "-help" or v == "--help" then
return true
else
return false
end
end
end
function setFlagsFromCommandLine() -- Sets count_only, chain_next_shape, and sim_mode
for i, v in pairs(argTable) do
if v == "-c" or v == "-cost" or v == "--cost" then
cost_only = true
cmd_line_cost_only = true
writeOut("Cost Only Mode")
end
if v == "-z" or v == "-chain" or v == "--chain" then
chain_next_shape = true
writeOut("Chained Shape Mode")
end
if v == "-r" or v == "-resume" or v == "--resume" then
cmd_line_resume = true
writeOut("Resuming")
end
if v == "-e" or v == "-ender" or v == "--ender" then
enderchest_refilling = true
tempProgTable.enderchest_refilling = true
writeOut("Enderchest Mode")
end
if v == "-g" or v == "-home" or v == "--home" then
return_to_home = true
writeOut("Will return home")
end
end
end
function setTableFromCommandLine() -- Sets progTable and tempProgTable from command line arguments
progTable.shape = argTable[1]
tempProgTable.shape = argTable[1]
local paramName = "param"
local paramName2 = paramName
for i = 2, #argTable do
local addOn = tostring(i - 1)
paramName2 = paramName .. addOn
progTable[paramName2] = argTable[i]
tempProgTable[paramName2] = argTable[i]
end
end
-- Menu, Drawing and Main functions
function choiceIsValidShape(choice)
local validShapes = {"rectangle", "square", "line", "wall", "platform", "stair", "stairs", "cuboid", "1/2-sphere", "1/2 sphere", "half-sphere", "half sphere", "dome", "bowl", "sphere", "circle", "cylinder", "pyramid", "polygon", "polyprism", "polygonc", "polyprismc"}
for i = 1, #validShapes do
if choice == validShapes[i] then
return true
end
end
return false
end
function choiceFunction()
if sim_mode == false and cmd_line == false then -- If we are NOT resuming progress
local page = 1
choice = io.read()
choice = string.lower(choice) -- All checks are against lower case words so this is to ensure that
while ((choice == "next") or (choice == "back")) do
if (choice == "next") then
if page == 1 then
writeMenu2()
page = 2
else
writeMenu()
page = 1
end
end
if (choice == "back") then
if page == 1 then
writeMenu2()
page = 2
else
writeMenu()
page = 1
end
end
choice = io.read()
choice = string.lower(choice) -- All checks are aginst lower case words so this is to ensure that
end
if choice == "end" or choice == "exit" then
writeOut("Goodbye.")
return
end
if choice == "help" then
getHelp()
return
end
if choice == "credits" then
showCredits()
return
end
tempProgTable = {shape = choice}
progTable = {shape = choice}
if not choiceIsValidShape(choice) then
writeOut(choice .. " is not a valid shape choice.")
return
end
writeOut("Building a "..choice)
local yes = getInput("string","Want to just calculate the cost?","y","n")
if yes == 'y' then
cost_only = true
end
local yes = getInput("string","Want turtle to return to start after build?","y","n")
if yes == 'y' then
return_to_home = true
end
local yes = getInput("string","Want the turtle to refill from enderchest (slot 16)?","y","n")
if yes == 'y' then
enderchest_refilling = true
tempProgTable.enderchest_refilling = true
end
elseif sim_mode == true then -- If we ARE resuming progress
tempProgTable = readProgress()
choice = tempProgTable.shape
choice = string.lower(choice) -- All checks are aginst lower case words so this is to ensure that
enderchest_refilling = tempProgTable.enderchest_refilling
elseif cmd_line == true then -- If running from command line
if needsHelp() then
showCmdLineHelp()
return
end
choice = tempProgTable.shape
choice = string.lower(choice) -- All checks are aginst lower case words so this is to ensure that
enderchest_refilling = tempProgTable.enderchest_refilling
writeOut("Building a "..choice)
end
if not cost_only then
turtle.select(1)
activeSlot = 1
if turtle.getItemCount(activeSlot) == 0 then
if resupply then
writeOut("Please put building blocks in the first slot.")
else
writeOut("Please put building blocks in the first slot (and more if you need them)")
end
while turtle.getItemCount(activeSlot) <= 1 do
os.sleep(.1)
end
end
else
activeSlot = 1
end
-- Shape selection if cascade
-- Line based shapes
if choice == "rectangle" then
local depth = 0
local width = 0
if sim_mode == false and cmd_line == false then
width = getInput("int","How wide does it need to be?")
depth = getInput("int","How deep does it need to be?")
elseif sim_mode == true or cmd_line == true then
width = tempProgTable.param1
depth = tempProgTable.param2
end
tempProgTable.param1 = width
tempProgTable.param2 = depth
progTable = {param1 = width, param2 = depth} -- THIS is here because we NEED to update the local table!
rectangle(width, depth)
end
if choice == "square" then
local sideLength
if sim_mode == false and cmd_line == false then
sideLength = getInput("int","How long does each side need to be?")
elseif sim_mode == true or cmd_line == true then
sideLength = tempProgTable.param1
end
tempProgTable.param1 = sideLength
progTable = {param1 = sideLength}
square(sideLength)
end
if choice == "line" then
local startX = 0
local startY = 0
local endX = 0
local endY = 0
if sim_mode == false and cmd_line == false then
writeOut("Note that the turtle's starting position is 0, 0.")
startX = getInput("int","Where does the start X need to be?")
startY = getInput("int","Where does the start Y need to be?")
endX = getInput("int","Where does the end X need to be?")
endY = getInput("int","Where does the end Y need to be?")
elseif sim_mode == true or cmd_line == true then
startX = tempProgTable.param1
startY = tempProgTable.param2
endX = tempProgTable.param3
endY = tempProgTable.param4
end
tempProgTable.param1 = startX
tempProgTable.param2 = startY
tempProgTable.param3 = endX
tempProgTable.param4 = endY
progTable = {param1 = startX, param2 = startY, param3 = endX, param4 = endY}
drawLine(endX, endY, startX, startY)
end
if choice == "wall" then
local depth = 0
local height = 0
if sim_mode == false and cmd_line == false then
depth = getInput("int","How deep does it need to be?")
height = getInput("int","How high does it need to be?")
elseif sim_mode == true or cmd_line == true then
depth = tempProgTable.param1
height = tempProgTable.param2
end
tempProgTable.param1 = depth
tempProgTable.param2 = height
progTable = {param1 = depth, param2 = height}
wall(depth, height)
end
if choice == "platform" then
local width = 0
local depth = 0
if sim_mode == false and cmd_line == false then
width = getInput("int","How wide does it need to be?")
depth = getInput("int","How deep does it need to be?")
elseif sim_mode == true or cmd_line == true then
width = tempProgTable.param1
depth = tempProgTable.param2
end
tempProgTable.param1 = width
tempProgTable.param2 = depth
progTable = {param1 = width, param2 = depth}
platform(width, depth)
end
if choice == "stair" or choice == "stairs" then
local width = 0
local height = 0
if sim_mode == false and cmd_line == false then
width = getInput("int","How wide does it need to be?")
height = getInput("int","How high does it need to be?")
elseif sim_mode == true or cmd_line == true then
width = tempProgTable.param1
height = tempProgTable.param2
end
tempProgTable.param1 = width
tempProgTable.param2 = height
progTable = {param1 = width, param2 = height}
stair(width, height)
special_chain = true
end
if choice == "cuboid" then
local width = 0
local depth = 0
local height = 0
local hollow = ""
if sim_mode == false and cmd_line == false then
width = getInput("int","How wide does it need to be?")
depth = getInput("int","How deep does it need to be?")
height = getInput("int","How high does it need to be?")
hollow = getInput("string","Does it need to be hollow?","y","n")
elseif sim_mode == true or cmd_line == true then
width = tempProgTable.param1
depth = tempProgTable.param2
height = tempProgTable.param3
hollow = tempProgTable.param4
end
tempProgTable.param1 = width
tempProgTable.param2 = depth
tempProgTable.param3 = height
tempProgTable.param4 = hollow
progTable = {param1 = width, param2 = depth, param3 = height}
cuboid(width, depth, height, hollow)
end
if choice == "pyramid" then
local length = 0
local hollow = ""
if sim_mode == false and cmd_line == false then
length = getInput("int","How long does each side of the base layer need to be?")
hollow = getInput("string","Does it need to be hollow?","y","n")
elseif sim_mode == true or cmd_line == true then
length = tempProgTable.param1
hollow = tempProgTable.param2
end
tempProgTable.param1 = length
tempProgTable.param2 = hollow
progTable = {param1 = length, param2 = hollow}
pyramid(length, hollow)
end
-- Circle based shapes
if choice == "1/2-sphere" or choice == "1/2 sphere" then
local diameter = 0
local half = ""
if sim_mode == false and cmd_line == false then
diameter = getInput("int","What diameter does it need to be?")
half = getInput("string","What half of the sphere does it need to be?","bottom","top")
elseif sim_mode == true or cmd_line == true then
diameter = tempProgTable.param1
half = tempProgTable.param2
end
tempProgTable.param1 = diameter
tempProgTable.param2 = half
progTable = {param1 = diameter, param2 = half}
if half == "bottom" then
dome("bowl", diameter)
elseif half == "top" then
dome("dome", diameter)
end
end
if choice == "dome" then
local diameter = 0
if sim_mode == false and cmd_line == false then
diameter = getInput("int","What diameter does it need to be?")
elseif sim_mode == true or cmd_line == true then
diameter = tempProgTable.param1
end
tempProgTable.param1 = diameter
progTable = {param1 = diameter}
dome("dome", diameter)
end
if choice == "bowl" then
local diameter = 0
if sim_mode == false and cmd_line == false then
diameter = getInput("int","What diameter does it need to be?")
elseif sim_mode == true or cmd_line == true then
diameter = tempProgTable.param1
end
tempProgTable.param1 = diameter
progTable = {param1 = diameter}
dome("bowl", diameter)
end
if choice == "sphere" then
local diameter = 0
if sim_mode == false and cmd_line == false then
diameter = getInput("int","What diameter does it need to be?")
elseif sim_mode == true or cmd_line == true then
diameter = tempProgTable.param1
end
tempProgTable.param1 = diameter
progTable = {param1 = diameter}
dome("sphere", diameter)
end
if choice == "circle" then
local diameter = 0
if sim_mode == false and cmd_line == false then
diameter = getInput("int","What diameter does it need to be?")
elseif sim_mode == true or cmd_line == true then
diameter = tempProgTable.param1
end
tempProgTable.param1 = diameter
progTable = {param1 = diameter}
circle(diameter)
end
if choice == "cylinder" then
local diameter = 0
local height = 0
if sim_mode == false and cmd_line == false then
diameter = getInput("int","What diameter does it need to be?")
height = getInput("int","How high does it need to be?")
elseif sim_mode == true or cmd_line == true then
diameter = tempProgTable.param1
height = tempProgTable.param2
end
tempProgTable.param1 = diameter
tempProgTable.param2 = height
progTable = {param1 = diameter, param2 = height}
cylinder(diameter, height)
end
-- Polygon shapes
if choice == "hexagon" then
local length = 0
if sim_mode == false and cmd_line == false then
length = getInput("int","How long does each side need to be?")
elseif sim_mode == true or cmd_line == true then
length = tempProgTable.param1
end
tempProgTable.param1 = length
progTable = {param1 = length}
hexagon(length)
end
if choice == "octagon" then
local length = 0
if sim_mode == false and cmd_line == false then
length = getInput("int","How long does each side need to be?")
elseif sim_mode == true or cmd_line == true then
length = tempProgTable.param1
end
tempProgTable.param1 = length
progTable = {param1 = length}
octagon(length)
end
if choice == "polygon" then
local numSides = 3
local length = 0
local offSetAngle = 0
if sim_mode == false and cmd_line == false then
numSides = getInput("int","How many sides to build?")
length = getInput("int","How long does each side need to be?")
offSetAngle = getInput("int","What offset angle does it need to be, in degrees? (usually 0)")
elseif sim_mode == true or cmd_line == true then
numSides = tempProgTable.param1
length = tempProgTable.param2
offSetAngle = tempProgTable.param3
end
tempProgTable.param1 = numSides
progTable = {param1 = numSides}
tempProgTable.param2 = length
progTable = {param2 = length}
tempProgTable.param3 = offSetAngle
progTable = {param3 = offSetAngle}
polygon(numSides, length, offSetAngle)
end
if choice == "polygonc" then
local numSides = 3
local diameter = 0
local offSetAngle = 0
if sim_mode == false and cmd_line == false then
numSides = getInput("int","How many sides to build?")
diameter = getInput("int","What diameter does it need to be?")
offSetAngle = getInput("int","What offset angle does it need to be, in degrees? (usually 0)")
elseif sim_mode == true or cmd_line == true then
numSides = tempProgTable.param1
diameter = tempProgTable.param2
offSetAngle = tempProgTable.param3
end
tempProgTable.param1 = numSides
progTable = {param1 = numSides}
tempProgTable.param2 = diameter
progTable = {param2 = diameter}
tempProgTable.param3 = offSetAngle
progTable = {param3 = offSetAngle}
circleLikePolygon(numSides, diameter, offSetAngle)
end
if choice == "polyprism" then
local numSides = 3
local length = 0
local height = 0
local offSetAngle = 0
if sim_mode == false and cmd_line == false then
numSides = getInput("int","How many sides to build?")
length = getInput("int","How long does each side need to be?")
height = getInput("int","How high does it need to be?")
offSetAngle = getInput("int","What offset angle does it need to be, in degrees? (usually 0)")
elseif sim_mode == true or cmd_line == true then
numSides = tempProgTable.param1
length = tempProgTable.param2
height = tempProgTable.param3
offSetAngle = tempProgTable.param4
end
tempProgTable.param1 = numSides
progTable = {param1 = numSides}
tempProgTable.param2 = length
progTable = {param2 = length}
tempProgTable.param3 = height
progTable = {param3 = height}
tempProgTable.param4 = offSetAngle
progTable = {param4 = offSetAngle}
polygonPrism(numSides, length, height, offSetAngle)
end
if choice == "polyprismc" then
local numSides = 3
local diameter = 0
local height = 0
local offSetAngle = 0
if sim_mode == false and cmd_line == false then
numSides = getInput("int","How many sides to build?")
diameter = getInput("int","What diameter does it need to be?")
height = getInput("int","How high does it need to be?")
offSetAngle = getInput("int","What offset angle does it need to be, in degrees? (usually 0)")
elseif sim_mode == true or cmd_line == true then
numSides = tempProgTable.param1
diameter = tempProgTable.param2
height = tempProgTable.param3
offSetAngle = tempProgTable.param4
end
tempProgTable.param1 = numSides
progTable = {param1 = numSides}
tempProgTable.param2 = diameter
progTable = {param2 = diameter}
tempProgTable.param3 = height
progTable = {param3 = height}
tempProgTable.param4 = offSetAngle
progTable = {param4 = offSetAngle}
circleLikePolygonPrism(numSides, diameter, height, offSetAngle)
end
if choice == "6-prism" or choice == "6 prism" then
local length = 0
local height = 0
if sim_mode == false and cmd_line == false then
length = getInput("int","How long does each side need to be?")
height = getInput("int","How high does it need to be?")
elseif sim_mode == true or cmd_line == true then
length = tempProgTable.param1
height = tempProgTable.param2
end
tempProgTable.param1 = length
tempProgTable.param2 = height
progTable = {param1 = length, param2 = height}
hexagonPrism(length, height)
end
if choice == "8-prism" or choice == "8 prism" then
local length = 0
local height = 0
if sim_mode == false and cmd_line == false then
length = getInput("int","How long does each side need to be?")
height = getInput("int","How high does it need to be?")
elseif sim_mode == true or cmd_line == true then
length = tempProgTable.param1
height = tempProgTable.param2
end
tempProgTable.param1 = length
tempProgTable.param2 = height
progTable = {param1 = length, param2 = height}
octagonPrism(length, height)
end
if return_to_home then
goHome() -- After all shape building has finished
end
writeOut("Done") -- Saves a few lines when put here rather than in each if statement
end
function writeMenu()
term.clear()
term.setCursorPos(1, 1)
writeOut("Shape Maker 1.8 by Keridos/CupricWolf/pokemane")
if resupply then -- Any ideas to make this more compact/better looking (in terms of code)?
writeOut("Resupply Mode Active")
elseif (resupply and can_use_gps) then
writeOut("Resupply and GPS Mode Active")
elseif can_use_gps then
writeOut("GPS Mode Active")
else
writeOut("Standard Mode Active")
end
if not cmd_line then
writeOut("What shape do you want to build?")
writeOut("[page 1/2]")
writeOut("next for page 2")
writeOut("+---------+-----------+-------+-------+")
writeOut("| square | rectangle | wall | line |")
writeOut("| cylinder| platform | stair | cuboid|")
writeOut("| pyramid | 1/2-sphere| sphere| circle|")
writeOut("+---------+-----------+-------+-------+")
writeOut("")
end
end
function writeMenu2()
term.clear()
term.setCursorPos(1, 1)
writeOut("Shape Maker 1.8 by Keridos/CupricWolf/pokemane")
if resupply then -- Any ideas to make this more compact/better looking (in terms of code)?
writeOut("Resupply Mode Active")
elseif (resupply and can_use_gps) then
writeOut("Resupply and GPS Mode Active")
elseif can_use_gps then
writeOut("GPS Mode Active")
else
writeOut("Standard Mode Active")
end
writeOut("What shape do you want to build?")
writeOut("[page 2/2]")
writeOut("back for page 1")
writeOut("+---------+-----------+-------+-------+")
writeOut("| polygon | polyprism | dome | |")
writeOut("| polygonC| polyprismC| | |")
writeOut("| help | credits | end | |")
writeOut("+---------+-----------+-------+-------+")
writeOut("")
end
function showCmdLineHelp()
term.clear()
term.setCursorPos(1, 1)
writeOut("Command line help")
writeOut("Usage: shape [shape-type] [param1] [param2] [param3] [param4] [-c] [-h] [-z] [-r]")
writeOut("-c or -cost or --cost: Activate cost only mode")
writeOut("-h or -help or --help: Show this information")
io.read()
writeOut("-z or -chain or --chain: Lets you chain together multiple shapes")
writeOut("-g or -home or --home: Make turtle go 'home' after build")
writeOut("-r or -resume or --resume: Resume the last build if possible")
io.read()
writeOut("-e or -ender or --ender: Activate enderchest refilling")
writeOut("shape-type can be any of the shapes in the menu")
writeOut("After shape-type input all of the parameters for the shape, varies by shape")
writeOut("Put any flags (-c, -h, etc.) at the end of your command")
end
function getHelp()
term.clear()
term.setCursorPos(1, 1)
writeOut("Width is to the right of the turtle. (X-Axis)")
writeOut("Depth is to the front of the turtle. (Y-Axis)")
writeOut("Height is to the top of the turtle. (Z-Axis)")
writeOut("Length is the side length of some shapes. (Squares and Polygons)")
io.read()
term.clear()
term.setCursorPos(1, 1)
local page = 1
writeOut("What shape do you want help with?")
writeOut("[page 1/2]")
writeOut("next for page 2")
writeOut("+---------+-----------+-------+-------+")
writeOut("| square | rectangle | wall | line |")
writeOut("| cylinder| platform | stair | cuboid|")
writeOut("| pyramid | 1/2-sphere| sphere| circle|")
writeOut("+---------+-----------+-------+-------+")
writeOut("")
choice = io.read()
choice = string.lower(choice)
while ((choice == "next") or (choice == "back")) do
if (choice == "next") then
if (page == 1) then
page = 2
term.clear()
term.setCursorPos(1, 1)
writeOut("What shape do you want help with?")
writeOut("[page 2/2]")
writeOut("back for page 1")
writeOut("+---------+-----------+-------+-------+")
writeOut("| polygon | polyprism | dome | |")
writeOut("| polygonC| polyprismC| | |")
writeOut("| help | credits | end | |")
writeOut("+---------+-----------+-------+-------+")
writeOut("")
else
page = 1
term.clear()
term.setCursorPos(1, 1)
writeOut("What shape do you want help with?")
writeOut("[page 1/2]")
writeOut("next for page 2")
writeOut("+---------+-----------+-------+-------+")
writeOut("| square | rectangle | wall | line |")
writeOut("| cylinder| platform | stair | cuboid|")
writeOut("| pyramid | 1/2-sphere| sphere| circle|")
writeOut("+---------+-----------+-------+-------+")
writeOut("")
end
end
if (choice == "back") then
if (page == 1) then
page = 2
term.clear()
term.setCursorPos(1, 1)
writeOut("What shape do you want help with?")
writeOut("[page 2/2]")
writeOut("back for page 1")
writeOut("+---------+-----------+-------+-------+")
writeOut("| polygon | polyprism | dome | |")
writeOut("| polygonC| polyprismC| | |")
writeOut("| help | credits | end | |")
writeOut("+---------+-----------+-------+-------+")
writeOut("")
else
page = 1
term.clear()
term.setCursorPos(1, 1)
writeOut("What shape do you want help with?")
writeOut("[page 2/2]")
writeOut("next for page 2")
writeOut("+---------+-----------+-------+-------+")
writeOut("| square | rectangle | wall | line |")
writeOut("| cylinder| platform | stair | cuboid|")
writeOut("| pyramid | 1/2-sphere| sphere| circle|")
writeOut("+---------+-----------+-------+-------+")
writeOut("")
end
end
choice = io.read()
choice = string.lower(choice)
end
if not choiceIsValidShape(choice) then
writeOut(choice .. " is not a valid shape choice.")
return
end
-- If cascade time!
if choice == "rectangle" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The rectangle is a perimeter of width by depth. Use platform if you want a filled in rectangle. The rectangle takes two parameters (two integers) Width then Depth.")
end
if choice == "square" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The square is a perimeter of length by length. Use platform if you want a filled in square. The square takes one parameter (one integer) Length.")
end
if choice == "line" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The line is drawn between the start and end points given. The turtle's initial position is 0, 0 so that must by taken into account. The line takes four parameters (four integers) Start X then Start Y then End X then End Y.")
end
if choice == "wall" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The wall is a vertical plane. The wall takes two parameters (two integers) Depth then Height.")
end
if choice == "platform" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The platform is a horizontal plane of width by depth. Use rectangle or square if you want just a perimeter. The platform takes two parameters (two integers) Width then Depth.")
end
if choice == "stair" or choice == "stairs" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The stair or stairs are an incline of width by height. The stair takes two parameters (two integers) Width then Height.")
end
if choice == "cuboid" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The cuboid is a rectangular prism of width by depth by height. The hollow parameter determines if the shape is solid or like a rectangular tube. The cuboid takes four parameters (three intergers and one y/n) Width then Depth then Height then Hollow(y/n).")
end
if choice == "1/2-sphere" or choice == "1/2 sphere" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The half sphere is the top or bottom half of a sphere. The half parameter determines of the top or bottom half of the sphere built. The half sphere takes two parameters (one integer and one top/bottom) Diameter then half(top/bottom).")
end
if choice == "dome" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The dome shape is a short-cut to the top half sphere. The dome takes one parameter (one integer) Diameter.")
end
if choice == "bowl" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The bowl shape is a short-cut to the bottom half sphere. The bowl takes one parameter (one integer) Diameter.")
end
if choice == "sphere" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The sphere is just that, a sphere. It is hollow. The sphere takes one parameter (one integer) Diameter.")
end
if choice == "circle" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The circle is just that, a circle. It is just a perimeter. The circle takes one parameter (one integer) Diameter.")
end
if choice == "cylinder" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The cylinder is a cylindrical tube of diameter by height. The cylinder takes two parameters (two integers) Diameter then Height.")
end
if choice == "pyramid" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The pyramid is a four sided pyramid with base length by length. The hollow parameter determines if the inside is filled. The pyramid takes two parameters (one integer and one y/n) Base Length then Hollow(y/n).")
end
if choice == "polygon" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The polygon is a polygonal perimeter. The polygon takes three parameters (three integers) Number of Sides then Side Length then Offset Angle.")
end
if choice == "polygonC" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The polygonC is a polygonal perimeter that inscribes inside a circle with the same diameter. The polygonC takes three parameters (three integers) Number of Sides then Diameter then Offset Angle.")
end
if choice == "polyprism" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The polyprism is a polygonal prism shaped tube. The polyprism takes four parameters (four integers) Number of Sides then Side Length then Height then Offset Angle.")
end
if choice == "polyprismC" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The polyprismC is a polygonal prism shaped tube that inscribes inside a cylinder with the same diameter. The polyprismC takes four parameters (four integers) Number of Sides then Diameter then Height then Offset Angle.")
end
if choice == "hexagon" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The hexagon is a hexagonal perimeter. The hexagon takes one parameter (one integer) Length.")
end
if choice == "octagon" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The octagon is and octagonal perimeter. The octagon takes one parameter (one integer) Length.")
end
if choice == "6-prism" or choice == "6 prism" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The 6 prism is a hexagonal prism shaped tube. The 6 prism takes two parameters (two integers) Length then Height.")
end
if choice == "8-prism" or choice == "8 prism" then
term.clear()
term.setCursorPos(1, 1)
writeOut("The 8 prism is an octagonal prism shaped tube. The 8 prism takes two parameters (two integers) Length then Height.")
end
end
function showCredits()
term.clear()
term.setCursorPos(1, 1)
writeOut("Credits for the shape builder:")
writeOut("Based on work by Michiel, Vliekkie, and Aeolun")
writeOut("Sphere/dome code by IMarvinTPA")
writeOut("Additional improvements by Keridos, CupricWolf, and pokemane")
end
function main()
if wrapModules()=="resupply" then
linkToRSStation()
end
if checkCommandLine() then
if needsHelp() then
showCmdLineHelp()
return -- Close the program after help info is shown
end
setFlagsFromCommandLine()
setTableFromCommandLine()
end
if (CheckForPrevious()) then -- Will check to see if there was a previous job and gps is enabled, and if so, ask if the user would like to re-initialize to current progress status
if not continueQuery() then -- If the user doesn't want to continue
ProgressFileDelete()
setSimFlags(false) -- Just to be safe
writeMenu()
choiceFunction()
else -- If the user wants to continue
setSimFlags(true)
choiceFunction()
end
else
setSimFlags(false)
writeMenu()
choiceFunction()
end
if (blocks ~= 0) and (fuel ~= 0) then -- Do not show on help or credits page or when selecting end
writeOut("Blocks used: " .. blocks)
writeOut("Fuel used: " .. fuel)
end
ProgressFileDelete() -- Removes file upon successful completion of a job, or completion of a previous job.
progTable = {}
tempProgTable = {}
end
main()Editor is loading...
Leave a Comment