Advertisement
jakikoske

OreQuarry Copy

Dec 10th, 2013
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 62.09 KB | None | 0 0
  1. local bottomLayer = 2 -- The y co-ords of the layer immediately above bedrock
  2.  
  3. -- Enumeration to store the the different types of message that can be written
  4. messageLevel = { DEBUG=0, INFO=1, WARNING=2, ERROR=3, FATAL=4 }
  5.  
  6. -- Enumeration to store names for the 6 directions
  7. direction = { FORWARD=0, RIGHT=1, BACK=2, LEFT=3, UP=4, DOWN=5 }
  8.  
  9. -- Enumeration of mining states
  10. miningState = { START=0, LAYER=1, EMPTYCHESTDOWN=2, EMPTYINVENTORY=3 }
  11.  
  12. local messageOutputLevel = messageLevel.INFO
  13. local messageOutputFileName
  14. local fuelLevelToRefuelAt = 5
  15. local refuelItemsToUseWhenRefuelling = 4
  16. local emergencyFuelToRetain = 0
  17. local maximumGravelStackSupported = 25 -- The number of stacked gravel or sand blocks supported
  18. local noiseBlocksCount
  19. local returningToStart = false
  20. local lookForChests = false -- Determines if chests should be located as part of the quarrying
  21. local miningOffset -- The offset to the mining layer. This is set depending on whether chests are being looked for or not
  22. local lastEmptySlot -- The last inventory slot that was empty when the program started (is either 15 if not looking for chests or 14 if we are)
  23. local turtleId
  24. local isWirelessTurtle
  25. local currentlySelectedSlot = 0 -- The slot that the last noise block was found in
  26. local lastMoveNeededDig = true -- Determines whether the last move needed a dig first
  27. local haveBeenAtZeroZeroOnLayer -- Determines whether the turtle has been at (0, 0) in this mining layer
  28. local orientationAtZeroZero -- The turtle's orientation when it was at (0, 0)
  29. local levelToReturnTo -- The level that the turtle should return to in order to head back to the start to unload
  30.  
  31. -- Variables used to support a resume
  32. local startupParamsFile = "OreQuarryParams.txt"
  33. local oreQuarryLocation = "OreQuarryLocation.txt"
  34. local returnToStartFile = "OreQuarryReturn.txt"
  35. local startupBackup = "startup_bak"
  36. local supportResume = true -- Determines whether the turtle is being run in the mode that supports resume
  37. local resuming = false -- Determines whether the turtle is currently in the process of resuming
  38. local resumeX
  39. local resumeY
  40. local resumeZ
  41. local resumeOrient
  42. local resumeMiningState
  43.  
  44. -- Variables to store the current location and orientation of the turtle. x is right, left, y is up, down and
  45. -- z is forward, back with relation to the starting orientation. Y is the actual turtle level, x and z are
  46. -- in relation to the starting point (i.e. the starting point is (0, 0))
  47. local currX
  48. local currY
  49. local currZ
  50. local currOrient
  51. local currMiningState = miningState.START
  52.  
  53. -- Command line parameters
  54. local startHeight -- Represents the height (y co-ord) that the turtle started at
  55. local quarryWidth -- Represents the length of the mines that the turtle will dig
  56.  
  57. -- ********************************************************************************** --
  58. -- Writes an output message
  59. -- ********************************************************************************** --
  60. function writeMessage(message, msgLevel)
  61.   if (msgLevel >= messageOutputLevel) then
  62.     print(message)
  63.  
  64.     -- If this turtle has a modem, then write the message to red net
  65.     if (isWirelessTurtle == true) then
  66.       if (turtleId == nil) then
  67.         rednet.broadcast(message)
  68.       else
  69.         -- Broadcast the message (prefixed with the turtle's id)
  70.         rednet.broadcast("[".. turtleId.."] "..message)
  71.       end
  72.     end
  73.  
  74.     if (messageOutputFileName ~= nil) then
  75.       -- Open file, write message and close file (flush doesn't seem to work!)
  76.       local outputFile
  77.       if (fs.exists(messageOutputFileName) == true) then
  78.         outputFile = io.open(messageOutputFileName, "a")
  79.       else
  80.         outputFile = io.open(messageOutputFileName, "w")
  81.       end
  82.  
  83.       outputFile:write(message)
  84.       outputFile:write("\n")
  85.       outputFile:close()
  86.     end
  87.   end
  88. end
  89.  
  90. -- ********************************************************************************** --
  91. -- Ensures that the turtle has fuel
  92. -- ********************************************************************************** --
  93. function ensureFuel()
  94.  
  95.   -- Determine whether a refuel is required
  96.   local fuelLevel = turtle.getFuelLevel()
  97.   if (fuelLevel ~= "unlimited") then
  98.     if (fuelLevel < fuelLevelToRefuelAt) then
  99.       -- Need to refuel
  100.       turtle.select(16)
  101.       currentlySelectedSlot = 16
  102.       local fuelItems = turtle.getItemCount(16)
  103.  
  104.       -- Do we need to impact the emergency fuel to continue? (always  
  105.       -- keep one fuel item in slot 16)
  106.       if (fuelItems == 0) then
  107.         writeMessage("Completely out of fuel!", messageLevel.FATAL)
  108.       elseif (fuelItems == 1) then
  109.         writeMessage("Out of Fuel!", messageLevel.ERROR)
  110.         turtle.refuel()
  111.       elseif (fuelItems <= (emergencyFuelToRetain + 1)) then
  112.         writeMessage("Consuming emergency fuel supply. "..(fuelItems - 2).." emergency fuel items remain", messageLevel.WARNING)
  113.         turtle.refuel(1)
  114.       else
  115.         -- Refuel the lesser of the refuelItemsToUseWhenRefuelling and the number of items more than
  116.         -- the emergency fuel level
  117.         if (fuelItems - (emergencyFuelToRetain + 1) < refuelItemsToUseWhenRefuelling) then
  118.           turtle.refuel(fuelItems - (emergencyFuelToRetain + 1))
  119.         else
  120.           turtle.refuel(refuelItemsToUseWhenRefuelling)
  121.         end
  122.       end
  123.     end
  124.   end
  125. end        
  126.  
  127. -- ********************************************************************************** --
  128. -- Checks that the turtle has inventory space by checking for spare slots and returning
  129. -- to the starting point to empty out if it doesn't.
  130. --
  131. -- Takes the position required to move to in order to empty the turtle's inventory
  132. -- should it be full as arguments
  133. -- ********************************************************************************** --
  134. function ensureInventorySpace()
  135.  
  136.   -- If already returning to start, then don't need to do anything
  137.   if (returningToStart == false) then
  138.  
  139.     -- If the last inventory slot is full, then need to return to the start and empty
  140.     if (turtle.getItemCount(lastEmptySlot) > 0) then
  141.  
  142.       -- Return to the starting point and empty the inventory, then go back to mining
  143.       returnToStartAndUnload(true)
  144.     end
  145.   end
  146. end
  147.  
  148. -- ********************************************************************************** --
  149. -- Function to move to the starting point, call a function that is passed in
  150. -- and return to the same location (if required)
  151. -- ********************************************************************************** --
  152. function returnToStartAndUnload(returnBackToMiningPoint)
  153.  
  154.   writeMessage("returnToStartAndUnload called", messageLevel.DEBUG)
  155.   returningToStart = true
  156.   local storedX, storedY, storedZ, storedOrient
  157.   local prevMiningState = currMiningState
  158.  
  159.   if (resuming == true) then
  160.     -- Get the stored parameters from the necessary file
  161.     local resumeFile = fs.open(returnToStartFile, "r")
  162.     if (resumeFile ~= nil) then
  163.       -- Restore the parameters from the file
  164.       local beenAtZero = resumeFile.readLine()
  165.       if (beenAtZero == "y") then
  166.         haveBeenAtZeroZeroOnLayer = true
  167.       else
  168.         haveBeenAtZeroZeroOnLayer = false
  169.       end
  170.  
  171.       local miningPointFlag = resumeFile.readLine()
  172.       if (miningPointFlag == "y") then
  173.         returnBackToMiningPoint = true
  174.       else
  175.         returnBackToMiningPoint = false
  176.       end
  177.  
  178.       currX = readNumber(resumeFile)
  179.       currY = readNumber(resumeFile)
  180.       currZ = readNumber(resumeFile)
  181.       currOrient = readNumber(resumeFile)
  182.       levelToReturnTo = readNumber(resumeFile)
  183.       prevMiningState = readNumber(resumeFile)
  184.       orientationAtZeroZero = readNumber(resumeFile)
  185.       resumeFile.close()
  186.  
  187.     else
  188.       writeMessage("Failed to read return to start file", messageLevel.ERROR)
  189.     end
  190.   elseif (supportResume == true) then
  191.  
  192.     local outputFile = io.open(returnToStartFile, "w")
  193.  
  194.     if (haveBeenAtZeroZeroOnLayer == true) then
  195.       outputFile:write("y\n")
  196.     else
  197.       outputFile:write("n\n")
  198.     end
  199.     if (returnBackToMiningPoint == true) then
  200.       outputFile:write("y\n")
  201.     else
  202.       outputFile:write("n\n")
  203.     end
  204.  
  205.     outputFile:write(currX)
  206.     outputFile:write("\n")
  207.     outputFile:write(currY)
  208.     outputFile:write("\n")
  209.     outputFile:write(currZ)
  210.     outputFile:write("\n")
  211.     outputFile:write(currOrient)
  212.     outputFile:write("\n")
  213.     outputFile:write(levelToReturnTo)
  214.     outputFile:write("\n")
  215.     outputFile:write(prevMiningState)
  216.     outputFile:write("\n")
  217.     outputFile:write(orientationAtZeroZero)
  218.     outputFile:write("\n")
  219.  
  220.     outputFile:close()
  221.   end
  222.    
  223.   storedX = currX
  224.   storedY = currY
  225.   storedZ = currZ
  226.   storedOrient = currOrient
  227.  
  228.   -- Store the current location and orientation so that it can be returned to
  229.   currMiningState = miningState.EMPTYINVENTORY
  230.   writeMessage("last item count = "..turtle.getItemCount(lastEmptySlot), messageLevel.DEBUG)
  231.  
  232.   if ((turtle.getItemCount(lastEmptySlot) > 0) or (returnBackToMiningPoint == false)) then
  233.  
  234.     writeMessage("Heading back to surface", messageLevel.DEBUG)
  235.  
  236.     -- Move down to the correct layer to return via
  237.     if (currY > levelToReturnTo) then
  238.       while (currY > levelToReturnTo) do
  239.         turtleDown()
  240.       end
  241.     elseif (currY < levelToReturnTo) then
  242.       while (currY < levelToReturnTo) do
  243.         turtleUp()
  244.       end
  245.     end
  246.  
  247.     if ((haveBeenAtZeroZeroOnLayer == false) or (orientationAtZeroZero == direction.FORWARD)) then
  248.       -- Move back to the correct X position first
  249.       if (currX > 0) then
  250.         turtleSetOrientation(direction.LEFT)
  251.         while (currX > 0) do
  252.           turtleForward()
  253.         end
  254.       elseif (currX < 0) then
  255.         -- This should never happen
  256.         writeMessage("Current x is less than 0 in returnToStartAndUnload", messageLevel.ERROR)
  257.       end
  258.  
  259.       -- Then move back to the correct Z position
  260.       if (currZ > 0) then
  261.         turtleSetOrientation(direction.BACK)
  262.         while (currZ > 0) do
  263.           turtleForward()
  264.         end
  265.       elseif (currZ < 0) then
  266.         -- This should never happen
  267.         writeMessage("Current z is less than 0 in returnToStartAndUnload", messageLevel.ERROR)
  268.       end
  269.     else
  270.       -- Move back to the correct Z position first
  271.       if (currZ > 0) then
  272.         turtleSetOrientation(direction.BACK)
  273.         while (currZ > 0) do
  274.           turtleForward()
  275.         end
  276.       elseif (currZ < 0) then
  277.         -- This should never happen
  278.         writeMessage("Current z is less than 0 in returnToStartAndUnload", messageLevel.ERROR)
  279.       end
  280.  
  281.       -- Then move back to the correct X position
  282.       if (currX > 0) then
  283.         turtleSetOrientation(direction.LEFT)
  284.         while (currX > 0) do
  285.           turtleForward()
  286.         end
  287.       elseif (currX < 0) then
  288.         -- This should never happen
  289.         writeMessage("Current x is less than 0 in returnToStartAndUnload", messageLevel.ERROR)
  290.       end
  291.     end
  292.  
  293.     -- Return to the starting layer
  294.     if (currY < startHeight) then
  295.       while (currY < startHeight) do
  296.         turtleUp()
  297.       end
  298.     elseif (currY > startHeight) then
  299.       -- This should never happen
  300.       writeMessage("Current height is greater than start height in returnToStartAndUnload", messageLevel.ERROR)
  301.     end
  302.  
  303.     -- Empty the inventory
  304.     local slotLoop = 1
  305.  
  306.     -- Face the chest
  307.     turtleSetOrientation(direction.BACK)
  308.  
  309.     -- Loop over each of the slots (except the 16th one which stores fuel)
  310.     while (slotLoop < 16) do
  311.       -- If this is one of the slots that contains a noise block, empty all blocks except
  312.       -- one
  313.       turtle.select(slotLoop) -- Don't bother updating selected slot variable as it will set later in this function
  314.       if ((slotLoop <= noiseBlocksCount) or ((slotLoop == 15) and (lastEmptySlot == 14))) then
  315.         writeMessage("Dropping (n-1) from slot "..slotLoop.." ["..turtle.getItemCount(slotLoop).."]", messageLevel.DEBUG)  
  316.         if (turtle.getItemCount(slotLoop) > 0) then
  317.           turtle.drop(turtle.getItemCount(slotLoop) - 1)
  318.         end
  319.       else
  320.         -- Not a noise block, drop all of the items in this slot
  321.         writeMessage("Dropping (all) from slot "..slotLoop.." ["..turtle.getItemCount(slotLoop).."]", messageLevel.DEBUG)  
  322.         if (turtle.getItemCount(slotLoop) > 0) then
  323.           turtle.drop()
  324.         end
  325.       end
  326.      
  327.       slotLoop = slotLoop + 1
  328.     end
  329.  
  330.     -- While we are here, refill the fuel items if there is capacity
  331.     if (turtle.getItemCount(16) < 64) then
  332.       turtleSetOrientation(direction.LEFT)
  333.       turtle.select(16) -- Don't bother updating selected slot variable as it will set later in this function
  334.       local currFuelItems = turtle.getItemCount(16)
  335.       turtle.suck()
  336.       while ((currFuelItems ~= turtle.getItemCount(16)) and (turtle.getItemCount(16) < 64)) do
  337.         currFuelItems = turtle.getItemCount(16)
  338.         turtle.suck()
  339.       end
  340.  
  341.       slotLoop = noiseBlocksCount + 1
  342.       -- Have now picked up all the items that we can. If we have also picked up some
  343.       -- additional fuel in some of the other slots, then drop it again
  344.       while (slotLoop <= lastEmptySlot) do
  345.         -- Drop any items found in this slot
  346.         if (turtle.getItemCount(slotLoop) > 0) then
  347.           turtle.select(slotLoop) -- Don't bother updating selected slot variable as it will set later in this function
  348.           turtle.drop()
  349.         end
  350.         slotLoop = slotLoop + 1
  351.       end
  352.     end
  353.  
  354.     -- Select the 1st slot because sometimes when leaving the 15th or 16th slots selected it can result
  355.     -- in that slot being immediately filled (resulting in the turtle returning to base again too soon)
  356.     turtle.select(1)
  357.     currentlySelectedSlot = 1
  358.   end
  359.  
  360.   -- If required, move back to the point that we were mining at before returning to the start
  361.   if (returnBackToMiningPoint == true) then
  362.  
  363.     -- If resuming, refresh the starting point to be the top of the return shaft
  364.     if (resuming == true) then
  365.       currX = 0
  366.       currY = startHeight
  367.       currZ = 0
  368.       currOrient = resumeOrient
  369.     end
  370.  
  371.     -- Return back to the required layer
  372.     while (currY > levelToReturnTo) do
  373.       turtleDown()
  374.     end
  375.  
  376.     if ((haveBeenAtZeroZeroOnLayer == false) or (orientationAtZeroZero == direction.FORWARD)) then
  377.       -- Move back to the correct Z position first
  378.       writeMessage("Stored Z: "..storedZ..", currZ: "..currZ, messageLevel.DEBUG)
  379.       if (storedZ > currZ) then
  380.         writeMessage("Orienting forward", messageLevel.DEBUG)
  381.         writeMessage("Moving in z direction", messageLevel.DEBUG)
  382.         turtleSetOrientation(direction.FORWARD)
  383.         while (storedZ > currZ) do
  384.           turtleForward()
  385.         end
  386.       elseif (storedZ < currZ) then
  387.         -- This should never happen
  388.         writeMessage("Stored z is less than current z in returnToStartAndUnload", messageLevel.ERROR)
  389.       end
  390.  
  391.       -- Then move back to the correct X position
  392.       if (storedX > currX) then
  393.         writeMessage("Stored X: "..storedX..", currX: "..currX, messageLevel.DEBUG)
  394.         writeMessage("Orienting right", messageLevel.DEBUG)
  395.         writeMessage("Moving in x direction", messageLevel.DEBUG)
  396.         turtleSetOrientation(direction.RIGHT)
  397.         while (storedX > currX) do
  398.           turtleForward()
  399.         end
  400.       elseif (storedX < currX) then
  401.         -- This should never happen
  402.         writeMessage("Stored x is less than current x in returnToStartAndUnload", messageLevel.ERROR)
  403.       end
  404.     else
  405.       -- Move back to the correct X position first
  406.       if (storedX > currX) then
  407.         writeMessage("Stored X: "..storedX..", currX: "..currX, messageLevel.DEBUG)
  408.         writeMessage("Orienting right", messageLevel.DEBUG)
  409.         writeMessage("Moving in x direction", messageLevel.DEBUG)
  410.         turtleSetOrientation(direction.RIGHT)
  411.         while (storedX > currX) do
  412.           turtleForward()
  413.         end
  414.       elseif (storedX < currX) then
  415.         -- This should never happen
  416.         writeMessage("Stored x is less than current x in returnToStartAndUnload", messageLevel.ERROR)
  417.       end
  418.  
  419.       -- Then move back to the correct Z position
  420.       writeMessage("Stored Z: "..storedZ..", currZ: "..currZ, messageLevel.DEBUG)
  421.       if (storedZ > currZ) then
  422.         writeMessage("Orienting forward", messageLevel.DEBUG)
  423.         writeMessage("Moving in z direction", messageLevel.DEBUG)
  424.         turtleSetOrientation(direction.FORWARD)
  425.         while (storedZ > currZ) do
  426.           turtleForward()
  427.         end
  428.       elseif (storedZ < currZ) then
  429.         -- This should never happen
  430.         writeMessage("Stored z is less than current z in returnToStartAndUnload", messageLevel.ERROR)
  431.       end
  432.     end
  433.  
  434.     -- Move back to the correct layer
  435.     if (storedY < currY) then
  436.       while (storedY < currY) do
  437.         turtleDown()
  438.       end
  439.     elseif (storedY > currY) then
  440.       while (storedY > currY) do
  441.         turtleUp()
  442.       end
  443.     end
  444.  
  445.     -- Finally, set the correct orientation
  446.     turtleSetOrientation(storedOrient)
  447.  
  448.     writeMessage("Have returned to the mining point", messageLevel.DEBUG)
  449.   end
  450.  
  451.   -- Store the current location and orientation so that it can be returned to
  452.   currMiningState = prevMiningState
  453.  
  454.   returningToStart = false
  455.  
  456. end
  457.  
  458. -- ********************************************************************************** --
  459. -- Empties a chest's contents
  460. -- ********************************************************************************** --
  461. function emptyChest(suckFn)
  462.  
  463.   local prevInventoryCount = {}
  464.   local inventoryLoop
  465.   local chestEmptied = false
  466.  
  467.   -- Record the number of items in each of the inventory slots
  468.   for inventoryLoop = 1, 16 do
  469.     prevInventoryCount[inventoryLoop] = turtle.getItemCount(inventoryLoop)
  470.   end
  471.  
  472.   while (chestEmptied == false) do
  473.     -- Pick up the next item
  474.     suckFn()
  475.  
  476.     -- Determine the number of items in each of the inventory slots now
  477.     local newInventoryCount = {}
  478.     for inventoryLoop = 1, 16 do
  479.       newInventoryCount[inventoryLoop] = turtle.getItemCount(inventoryLoop)
  480.     end
  481.  
  482.     -- Now, determine whether there have been any items taken from the chest
  483.     local foundDifferentItemCount = false
  484.     inventoryLoop = 1
  485.     while ((foundDifferentItemCount == false) and (inventoryLoop <= 16)) do
  486.       if (prevInventoryCount[inventoryLoop] ~= newInventoryCount[inventoryLoop]) then
  487.         foundDifferentItemCount = true
  488.       else
  489.         inventoryLoop = inventoryLoop + 1
  490.       end
  491.     end
  492.    
  493.     -- If no items have been found with a different item count, then the chest has been emptied
  494.     chestEmptied = not foundDifferentItemCount
  495.  
  496.     if (chestEmptied == false) then
  497.       prevInventoryCount = newInventoryCount
  498.       -- Check that there is sufficient inventory space as may have picked up a block
  499.       ensureInventorySpace()
  500.     end
  501.   end
  502.  
  503.   writeMessage("Finished emptying chest", messageLevel.DEBUG)
  504. end
  505.  
  506. -- ********************************************************************************** --
  507. -- Write the current location to a file
  508. -- ********************************************************************************** --
  509. function saveLocation()
  510.  
  511.   -- Write the x, y, z and orientation to the file
  512.   if ((supportResume == true) and (resuming == false)) then
  513.     local outputFile = io.open(oreQuarryLocation, "w")
  514.     outputFile:write(currMiningState)
  515.     outputFile:write("\n")
  516.     outputFile:write(currX)
  517.     outputFile:write("\n")
  518.     outputFile:write(currY)
  519.     outputFile:write("\n")
  520.     outputFile:write(currZ)
  521.     outputFile:write("\n")
  522.     outputFile:write(currOrient)
  523.     outputFile:write("\n")
  524.     outputFile:close()
  525.   end
  526.  
  527. end
  528.  
  529. -- ********************************************************************************** --
  530. -- If the turtle is resuming and the current co-ordinates, orientation and
  531. -- mining state have been matched, then no longer resuming
  532. -- ********************************************************************************** --
  533. function updateResumingFlag()
  534.  
  535.   if (resuming == true) then
  536.     if ((resumeMiningState == currMiningState) and (resumeX == currX) and (resumeY == currY) and (resumeZ == currZ) and (resumeOrient == currOrient)) then
  537.       resuming = false
  538.     end
  539.   end
  540.  
  541. end
  542.  
  543. -- ********************************************************************************** --
  544. -- Generic function to move the Turtle (pushing through any gravel or other
  545. -- things such as mobs that might get in the way).
  546. --
  547. -- The only thing that should stop the turtle moving is bedrock. Where this is
  548. -- found, the function will return after 15 seconds returning false
  549. -- ********************************************************************************** --
  550. function moveTurtle(moveFn, detectFn, digFn, attackFn, compareFn, suckFn, maxDigCount, newX, newY, newZ)
  551.  
  552.   local moveSuccess = false
  553.  
  554.   -- If we are resuming, then don't do anything in this function other than updating the
  555.   -- co-ordinates as if the turtle had moved
  556.   if (resuming == true) then
  557.     -- Set the move success to true (but don't move) - unless this is below bedrock level
  558.     -- in which case return false
  559.     if (currY <= 0) then
  560.       moveSuccess = false
  561.     else
  562.       moveSuccess = true
  563.     end
  564.  
  565.     -- Update the co-ordinates to reflect the movement
  566.     currX = newX
  567.     currY = newY
  568.     currZ = newZ
  569.  
  570.   else
  571.     local prevX, prevY, prevZ
  572.     prevX = currX
  573.     prevY = currY
  574.     prevZ = currZ
  575.  
  576.     ensureFuel()
  577.  
  578.     -- Flag to determine whether digging has been tried yet. If it has
  579.     -- then pause briefly before digging again to allow sand or gravel to
  580.     -- drop
  581.     local digCount = 0
  582.  
  583.     if (lastMoveNeededDig == false) then
  584.       -- Didn't need to dig last time the turtle moved, so try moving first
  585.  
  586.       currX = newX
  587.       currY = newY
  588.       currZ = newZ
  589.       saveLocation()
  590.  
  591.       moveSuccess = moveFn()
  592.  
  593.       -- If move failed, update the co-ords back to the previous co-ords
  594.       if (moveSuccess == false) then
  595.         currX = prevX
  596.         currY = prevY
  597.         currZ = prevZ
  598.         saveLocation()
  599.       end
  600.  
  601.       -- Don't need to set the last move needed dig. It is already false, if
  602.       -- move success is now true, then it won't be changed
  603.     else    
  604.       -- If we are looking for chests, then check that this isn't a chest before trying to dig it
  605.       if (lookForChests == true) then
  606.         if (isNoiseBlock(compareFn) == false) then
  607.           if (detectFn() == true) then
  608.             -- Determine if it is a chest before digging it
  609.             if (isChestBlock(compareFn) == true) then
  610.               -- Have found a chest, empty it before continuing
  611.               emptyChest (suckFn)
  612.             end
  613.           end
  614.         end
  615.       end
  616.  
  617.       -- Try to dig (without doing a detect as it is quicker)
  618.       local digSuccess = digFn()
  619.       if (digSuccess == true) then
  620.         digCount = 1
  621.       end
  622.  
  623.       currX = newX
  624.       currY = newY
  625.       currZ = newZ
  626.       saveLocation()
  627.  
  628.       moveSuccess = moveFn()
  629.  
  630.       if (moveSuccess == true) then
  631.         lastMoveNeededDig = digSuccess
  632.       else
  633.         currX = prevX
  634.         currY = prevY
  635.         currZ = prevZ
  636.         saveLocation()
  637.       end
  638.  
  639.     end
  640.  
  641.     -- Loop until we've successfully moved
  642.     if (moveSuccess == false) then
  643.       while ((moveSuccess == false) and (digCount < maxDigCount)) do
  644.  
  645.         -- If there is a block in front, dig it
  646.         if (detectFn() == true) then
  647.        
  648.             -- If we've already tried digging, then pause before digging again to let
  649.             -- any sand or gravel drop, otherwise check for a chest before digging
  650.             if(digCount == 0) then
  651.               -- Am about to dig a block - check that it is not a chest if necessary
  652.               -- If we are looking for chests, then check that this isn't a chest before moving
  653.               if (lookForChests == true) then
  654.                 if (isNoiseBlock(compareFn) == false) then
  655.                   if (detectFn() == true) then
  656.                     -- Determine if it is a chest before digging it
  657.                     if (isChestBlock(compareFn) == true) then
  658.                       -- Have found a chest, empty it before continuing
  659.                       emptyChest (suckFn)
  660.                     end
  661.                   end
  662.                 end
  663.               end
  664.             else
  665.               sleep(0.1)
  666.             end
  667.  
  668.             digFn()
  669.             digCount = digCount + 1
  670.         else
  671.            -- Am being stopped from moving by a mob, attack it
  672.            attackFn()
  673.         end
  674.  
  675.         currX = newX
  676.         currY = newY
  677.         currZ = newZ
  678.         saveLocation()
  679.  
  680.         -- Try the move again
  681.         moveSuccess = moveFn()
  682.  
  683.         if (moveSuccess == false) then
  684.           currX = prevX
  685.           currY = prevY
  686.           currZ = prevZ
  687.           saveLocation()
  688.         end
  689.       end
  690.  
  691.       if (digCount == 0) then
  692.         lastMoveNeededDig = false
  693.       else
  694.         lastMoveNeededDig = true
  695.       end
  696.     end
  697.   end
  698.  
  699.   -- If we are resuming and the current co-ordinates and orientation are the resume point
  700.   -- then are no longer resuming
  701.   if (moveSuccess == true) then
  702.     updateResumingFlag()
  703.   end
  704.  
  705.   -- Return the move success
  706.   return moveSuccess
  707.  
  708. end
  709.  
  710. -- ********************************************************************************** --
  711. -- Move the turtle forward one block (updating the turtle's position)
  712. -- ********************************************************************************** --
  713. function turtleForward()
  714.  
  715.   -- Determine the new co-ordinate that the turtle will be moving to
  716.   local newX, newZ
  717.  
  718.   -- Update the current co-ordinates
  719.   if (currOrient == direction.FORWARD) then
  720.     newZ = currZ + 1
  721.     newX = currX
  722.   elseif (currOrient == direction.LEFT) then
  723.     newX = currX - 1
  724.     newZ = currZ
  725.   elseif (currOrient == direction.BACK) then
  726.     newZ = currZ - 1
  727.     newX = currX
  728.   elseif (currOrient == direction.RIGHT) then
  729.     newX = currX + 1
  730.     newZ = currZ
  731.   else
  732.     writeMessage ("Invalid currOrient in turtleForward function", messageLevel.ERROR)
  733.   end
  734.  
  735.   local returnVal = moveTurtle(turtle.forward, turtle.detect, turtle.dig, turtle.attack, turtle.compare, turtle.suck, maximumGravelStackSupported, newX, currY, newZ)
  736.  
  737.   if (returnVal == true) then
  738.     -- Check that there is sufficient inventory space as may have picked up a block
  739.     ensureInventorySpace()
  740.   end
  741.  
  742.   return returnVal
  743. end
  744.  
  745. -- ********************************************************************************** --
  746. -- Move the turtle up one block (updating the turtle's position)
  747. -- ********************************************************************************** --
  748. function turtleUp()
  749.  
  750.   local returnVal = moveTurtle(turtle.up, turtle.detectUp, turtle.digUp, turtle.attackUp, turtle.compareUp, turtle.suckUp, maximumGravelStackSupported, currX, currY + 1, currZ)
  751.  
  752.   if (returnVal == true) then
  753.     -- Check that there is sufficient inventory space as may have picked up a block
  754.     ensureInventorySpace()
  755.   end
  756.  
  757.   return returnVal
  758. end
  759.  
  760. -- ********************************************************************************** --
  761. -- Move the turtle down one block (updating the turtle's position)
  762. -- ********************************************************************************** --
  763. function turtleDown()
  764.  
  765.   local returnVal = moveTurtle(turtle.down, turtle.detectDown, turtle.digDown, turtle.attackDown, turtle.compareDown, turtle.suckDown, 1, currX, currY - 1, currZ)
  766.  
  767.   if (returnVal == true) then
  768.     -- Check that there is sufficient inventory space as may have picked up a block
  769.     ensureInventorySpace()
  770.   end
  771.  
  772.   return returnVal
  773.  
  774. end
  775.  
  776. -- ********************************************************************************** --
  777. -- Move the turtle back one block (updating the turtle's position)
  778. -- ********************************************************************************** --
  779. function turtleBack()
  780.  
  781.   -- Assume that the turtle will move, and switch the co-ords back if it doesn't
  782.   -- (do this so that we can write the co-ords to a file before moving)
  783.   local newX, newZ
  784.   local prevX, prevZ
  785.   prevX = currX
  786.   prevZ = currZ
  787.  
  788.   -- Update the current co-ordinates
  789.   if (currOrient == direction.FORWARD) then
  790.     newZ = currZ - 1
  791.     newX = currX
  792.   elseif (currOrient == direction.LEFT) then
  793.     newX = currX + 1
  794.     newZ = currZ
  795.   elseif (currOrient == direction.BACK) then
  796.     newZ = currZ + 1
  797.     newX = currX
  798.   elseif (currOrient == direction.RIGHT) then
  799.     newX = currX - 1
  800.     newZ = currZ
  801.   else
  802.     writeMessage ("Invalid currOrient in turtleBack function", messageLevel.ERROR)
  803.   end
  804.  
  805.   -- First try to move back using the standard function
  806.  
  807.   currX = newX
  808.   currZ = newZ
  809.   saveLocation()
  810.   local returnVal = turtle.back()
  811.  
  812.   if (returnVal == false) then
  813.     -- Didn't move. Reset the co-ordinates to the previous value
  814.     currX = prevX
  815.     currZ = prevZ
  816.  
  817.     -- Reset the location back to the previous location (because the turn takes 0.8 of a second
  818.     -- so could be stopped before getting to the forward function)
  819.     saveLocation()
  820.  
  821.     turtle.turnRight()
  822.     turtle.turnRight()
  823.  
  824.     -- Try to move by using the forward function (note, the orientation will be set as
  825.     -- the same way as this function started because if the function stops, that is the
  826.     -- direction that we want to consider the turtle to be pointing)
  827.  
  828.     returnVal = moveTurtle(turtle.forward, turtle.detect, turtle.dig, turtle.attack, turtle.compare, turtle.suck, maximumGravelStackSupported, newX, currY, newZ)
  829.  
  830.     turtle.turnRight()
  831.     turtle.turnRight()
  832.   end
  833.  
  834.   if (returnVal == true) then
  835.     -- Check that there is sufficient inventory space as may have picked up a block
  836.     ensureInventorySpace()
  837.   end
  838.    
  839.   return returnVal
  840. end
  841.  
  842. -- ********************************************************************************** --
  843. -- Turns the turtle (updating the current orientation at the same time)
  844. -- ********************************************************************************** --
  845. function turtleTurn(turnDir)
  846.  
  847.   if (turnDir == direction.LEFT) then
  848.     if (currOrient == direction.FORWARD) then
  849.       currOrient = direction.LEFT
  850.     elseif (currOrient == direction.LEFT) then
  851.       currOrient = direction.BACK
  852.     elseif (currOrient == direction.BACK) then
  853.       currOrient = direction.RIGHT
  854.     elseif (currOrient == direction.RIGHT) then
  855.       currOrient = direction.FORWARD
  856.     else
  857.       writeMessage ("Invalid currOrient in turtleTurn function", messageLevel.ERROR)
  858.     end
  859.  
  860.     -- If we are resuming, just check to see whether have reached the resume point, otherwise
  861.     -- turn
  862.     if (resuming == true) then
  863.       updateResumingFlag()
  864.     else
  865.       -- Write the new orientation and turn
  866.       saveLocation()
  867.       turtle.turnLeft()
  868.     end
  869.  
  870.   elseif (turnDir == direction.RIGHT) then
  871.     if (currOrient == direction.FORWARD) then
  872.       currOrient = direction.RIGHT
  873.     elseif (currOrient == direction.LEFT) then
  874.       currOrient = direction.FORWARD
  875.     elseif (currOrient == direction.BACK) then
  876.       currOrient = direction.LEFT
  877.     elseif (currOrient == direction.RIGHT) then
  878.       currOrient = direction.BACK
  879.     else
  880.       writeMessage ("Invalid currOrient in turtleTurn function", messageLevel.ERROR)
  881.     end
  882.  
  883.     -- If we are resuming, just check to see whether have reached the resume point, otherwise
  884.     -- turn
  885.     if (resuming == true) then
  886.       updateResumingFlag()
  887.  
  888.       writeMessage("["..currMiningState..", "..currX..", "..currY..", "..currZ..", "..currOrient.."]", messageLevel.DEBUG)
  889.     else
  890.       -- Write the new orientation and turn
  891.       saveLocation()
  892.       turtle.turnRight()
  893.     end
  894.   else
  895.     writeMessage ("Invalid turnDir in turtleTurn function", messageLevel.ERROR)
  896.   end
  897. end
  898.  
  899. -- ********************************************************************************** --
  900. -- Sets the turtle to a specific orientation, irrespective of its current orientation
  901. -- ********************************************************************************** --
  902. function turtleSetOrientation(newOrient)
  903.  
  904.   if (currOrient ~= newOrient) then
  905.     if (currOrient == direction.FORWARD) then
  906.       if (newOrient == direction.RIGHT) then
  907.         currOrient = newOrient
  908.  
  909.         -- If resuming, check whether the resume point has been reached, otherwise turn
  910.         if (resuming == true) then
  911.           updateResumingFlag()
  912.         else
  913.           -- Write the new orientation and turn
  914.           saveLocation()
  915.           turtle.turnRight()
  916.         end
  917.       elseif (newOrient == direction.BACK) then
  918.         currOrient = newOrient
  919.  
  920.         -- If resuming, check whether the resume point has been reached, otherwise turn
  921.         if (resuming == true) then
  922.           updateResumingFlag()
  923.         else
  924.           -- Write the new orientation and turn
  925.           saveLocation()
  926.           turtle.turnRight()
  927.           turtle.turnRight()
  928.         end
  929.       elseif (newOrient == direction.LEFT) then
  930.         currOrient = newOrient
  931.  
  932.         -- If resuming, check whether the resume point has been reached, otherwise turn
  933.         if (resuming == true) then
  934.           updateResumingFlag()
  935.         else
  936.           -- Write the new orientation and turn
  937.           saveLocation()
  938.           turtle.turnLeft()
  939.         end
  940.       else
  941.         writeMessage ("Invalid newOrient in turtleSetOrientation function", messageLevel.ERROR)
  942.       end
  943.     elseif (currOrient == direction.RIGHT) then
  944.       if (newOrient == direction.BACK) then
  945.         currOrient = newOrient
  946.  
  947.         -- If resuming, check whether the resume point has been reached, otherwise turn
  948.         if (resuming == true) then
  949.           updateResumingFlag()
  950.         else
  951.           -- Write the new orientation and turn
  952.           saveLocation()
  953.           turtle.turnRight()
  954.         end
  955.       elseif (newOrient == direction.LEFT) then
  956.         currOrient = newOrient
  957.  
  958.         -- If resuming, check whether the resume point has been reached, otherwise turn
  959.         if (resuming == true) then
  960.           updateResumingFlag()
  961.         else
  962.           -- Write the new orientation and turn
  963.           saveLocation()
  964.           turtle.turnRight()
  965.           turtle.turnRight()
  966.         end
  967.       elseif (newOrient == direction.FORWARD) then
  968.         currOrient = newOrient
  969.  
  970.         -- If resuming, check whether the resume point has been reached, otherwise turn
  971.         if (resuming == true) then
  972.           updateResumingFlag()
  973.         else
  974.           -- Write the new orientation and turn
  975.           saveLocation()
  976.           turtle.turnLeft()
  977.         end
  978.       else
  979.         writeMessage ("Invalid newOrient in turtleSetOrientation function", messageLevel.ERROR)
  980.       end
  981.     elseif (currOrient == direction.BACK) then
  982.       if (newOrient == direction.LEFT) then
  983.         currOrient = newOrient
  984.  
  985.         -- If resuming, check whether the resume point has been reached, otherwise turn
  986.         if (resuming == true) then
  987.           updateResumingFlag()
  988.         else
  989.           -- Write the new orientation and turn
  990.           saveLocation()
  991.           turtle.turnRight()
  992.         end
  993.       elseif (newOrient == direction.FORWARD) then
  994.         currOrient = newOrient
  995.  
  996.         -- If resuming, check whether the resume point has been reached, otherwise turn
  997.         if (resuming == true) then
  998.           updateResumingFlag()
  999.         else
  1000.           -- Write the new orientation and turn
  1001.           saveLocation()
  1002.           turtle.turnRight()
  1003.           turtle.turnRight()
  1004.         end
  1005.       elseif (newOrient == direction.RIGHT) then
  1006.         currOrient = newOrient
  1007.  
  1008.         -- If resuming, check whether the resume point has been reached, otherwise turn
  1009.         if (resuming == true) then
  1010.           updateResumingFlag()
  1011.         else
  1012.           -- Write the new orientation and turn
  1013.           saveLocation()
  1014.           turtle.turnLeft()
  1015.         end
  1016.       else
  1017.         writeMessage ("Invalid newOrient in turtleSetOrientation function", messageLevel.ERROR)
  1018.       end
  1019.     elseif (currOrient == direction.LEFT) then
  1020.       if (newOrient == direction.FORWARD) then
  1021.         currOrient = newOrient
  1022.  
  1023.         -- If resuming, check whether the resume point has been reached, otherwise turn
  1024.         if (resuming == true) then
  1025.           updateResumingFlag()
  1026.         else
  1027.           -- Write the new orientation and turn
  1028.           saveLocation()
  1029.           turtle.turnRight()
  1030.         end
  1031.       elseif (newOrient == direction.RIGHT) then
  1032.         currOrient = newOrient
  1033.  
  1034.         -- If resuming, check whether the resume point has been reached, otherwise turn
  1035.         if (resuming == true) then
  1036.           updateResumingFlag()
  1037.         else
  1038.           -- Write the new orientation and turn
  1039.           saveLocation()
  1040.           turtle.turnRight()
  1041.           turtle.turnRight()
  1042.         end
  1043.       elseif (newOrient == direction.BACK) then
  1044.         currOrient = newOrient
  1045.  
  1046.         -- If resuming, check whether the resume point has been reached, otherwise turn
  1047.         if (resuming == true) then
  1048.           updateResumingFlag()
  1049.         else
  1050.           -- Write the new orientation and turn
  1051.           saveLocation()
  1052.           turtle.turnLeft()
  1053.         end
  1054.       else
  1055.         writeMessage ("Invalid newOrient in turtleSetOrientation function", messageLevel.ERROR)
  1056.       end
  1057.     else
  1058.       writeMessage ("Invalid currOrient in turtleTurn function", messageLevel.ERROR)
  1059.     end
  1060.   end
  1061. end
  1062.  
  1063. -- ********************************************************************************** --
  1064. -- Determines if a particular block is considered a noise block or not. A noise
  1065. -- block is one that is a standard block in the game (stone, dirt, gravel etc.) and
  1066. -- is one to ignore as not being an ore. Function works by comparing the block
  1067. -- in question against a set of blocks in the turtle's inventory which are known not to
  1068. -- be noise blocks. Param is the function to use to compare the block for a noise block
  1069. -- ********************************************************************************** --
  1070. function isNoiseBlock(compareFn)
  1071.  
  1072.   -- Consider air to be a noise block
  1073.   local returnVal = false
  1074.  
  1075.   if (resuming == true) then
  1076.     returnVal = true
  1077.   else
  1078.     local seamLoop = 1
  1079.     local prevSelectedSlot  
  1080.  
  1081.     -- If the currently selected slot is a noise block, then compare against this first
  1082.     -- so that the slot doesn't need to be selected again (there is a 0.05s cost to do
  1083.     -- this even if it is the currently selected slot)
  1084.     if (currentlySelectedSlot <= noiseBlocksCount) then
  1085.       returnVal = compareFn()
  1086.     end
  1087.  
  1088.     if (returnVal == false) then
  1089.       prevSelectedSlot = currentlySelectedSlot
  1090.       while((returnVal == false) and (seamLoop <= noiseBlocksCount)) do
  1091.         if (seamLoop ~= prevSelectedSlot) then
  1092.           turtle.select(seamLoop)
  1093.           currentlySelectedSlot = seamLoop
  1094.           returnVal = compareFn()
  1095.         end
  1096.         seamLoop = seamLoop + 1
  1097.       end
  1098.     end
  1099.   end
  1100.  
  1101.   -- Return the calculated value
  1102.   return returnVal
  1103.  
  1104. end
  1105.  
  1106. -- ********************************************************************************** --
  1107. -- Determines if a particular block is a chest. Returns false if it is not a chest
  1108. -- or chests are not being detected
  1109. -- ********************************************************************************** --
  1110. function isChestBlock(compareFn)
  1111.  
  1112.   -- Check the block in the appropriate direction to see whether it is a chest. Only
  1113.   -- do this if we are looking for chests
  1114.   local returnVal = false
  1115.   if (lookForChests == true) then
  1116.     turtle.select(15)
  1117.     currentlySelectedSlot = 15
  1118.     returnVal = compareFn()
  1119.   end
  1120.  
  1121.   -- Return the calculated value
  1122.   return returnVal
  1123.  
  1124. end
  1125.  
  1126. -- ********************************************************************************** --
  1127. -- Function to calculate the number of non seam blocks in the turtle's inventory. This
  1128. -- is all of the blocks at the start of the inventory (before the first empty slot is
  1129. -- found
  1130. -- ********************************************************************************** --
  1131. function determineNoiseBlocksCountCount()
  1132.   -- Determine the location of the first empty inventory slot. All items before this represent
  1133.   -- noise items.
  1134.   local foundFirstBlankInventorySlot = false
  1135.   noiseBlocksCount = 1
  1136.   while ((noiseBlocksCount < 16) and (foundFirstBlankInventorySlot == false)) do
  1137.     if (turtle.getItemCount(noiseBlocksCount) > 0) then
  1138.       noiseBlocksCount = noiseBlocksCount + 1
  1139.     else
  1140.       foundFirstBlankInventorySlot = true
  1141.     end
  1142.   end
  1143.   noiseBlocksCount = noiseBlocksCount - 1
  1144.  
  1145.   -- Determine whether a chest was provided, and hence whether we should support
  1146.   -- looking for chests
  1147.   if (turtle.getItemCount(15) > 0) then
  1148.     lookForChests = true
  1149.     lastEmptySlot = 14
  1150.     miningOffset = 0
  1151.     writeMessage("Looking for chests...", messageLevel.DEBUG)
  1152.   else
  1153.     lastEmptySlot = 15
  1154.     miningOffset = 1
  1155.     writeMessage("Ignoring chests...", messageLevel.DEBUG)
  1156.   end
  1157. end
  1158.  
  1159. -- ********************************************************************************** --
  1160. -- Creates a quarry mining out only ores and leaving behind any noise blocks
  1161. -- ********************************************************************************** --
  1162. function createQuarry()
  1163.  
  1164.   -- Determine the top mining layer layer. The turtle mines in layers of 3, and the bottom layer
  1165.   -- is the layer directly above bedrock.
  1166.   --
  1167.   -- The actual layer that the turtle operates in is the middle of these three layers,
  1168.   -- so determine the top layer
  1169.   local topMiningLayer = startHeight + ((bottomLayer - startHeight - 2) % 3) - 1 + miningOffset
  1170.  
  1171.   -- If the top layer is up, then ignore it and move to the next layer
  1172.   if (topMiningLayer > currY) then
  1173.     topMiningLayer = topMiningLayer - 3
  1174.   end
  1175.  
  1176.   local startedLayerToRight = true -- Only used where the quarry is of an odd width
  1177.  
  1178.   -- Loop over each mining row
  1179.   local miningLevel
  1180.   for miningLevel = (bottomLayer + miningOffset), topMiningLayer, 3 do
  1181.     writeMessage("Mining Layer: "..miningLevel, messageLevel.INFO)
  1182.     haveBeenAtZeroZeroOnLayer = false
  1183.  
  1184.     -- While the initial shaft is being dug out, set the level to return to in order to unload
  1185.     -- to the just take the turtle straight back up
  1186.     if (miningLevel == (bottomLayer + miningOffset)) then
  1187.       levelToReturnTo = startHeight
  1188.     end
  1189.  
  1190.     -- Move to the correct level to start mining
  1191.     if (currY > miningLevel) then
  1192.       while (currY > miningLevel) do
  1193.         turtleDown()
  1194.       end
  1195.     elseif (currY < miningLevel) then
  1196.       while (currY < miningLevel) do
  1197.         turtleUp()
  1198.       end
  1199.     end
  1200.  
  1201.     -- Am now mining the levels (update the mining state to reflect that fact)
  1202.     currMiningState = miningState.LAYER
  1203.  
  1204.     -- Set the layer to return via when returning to the surface as the one below the currently
  1205.     -- mined one
  1206.     if (miningLevel == (bottomLayer + miningOffset)) then
  1207.       levelToReturnTo = (bottomLayer + miningOffset)
  1208.     else
  1209.       levelToReturnTo = miningLevel - 3
  1210.     end
  1211.  
  1212.     -- Move turtle into the correct orientation to start mining (if this is the
  1213.     -- first row to be mined, then don't need to turn, otherwise turn towards the next
  1214.     -- mining section)
  1215.  
  1216.     writeMessage("Mining Level: "..miningLevel..", Bottom Layer: "..bottomLayer..", Mining Offset: "..miningOffset, messageLevel.DEBUG)
  1217.  
  1218.     if (miningLevel > (bottomLayer + miningOffset)) then
  1219.       -- Turn towards the next mining layer
  1220.       if (quarryWidth % 2 == 0) then
  1221.         -- An even width quarry, always turn right
  1222.         turtleTurn(direction.RIGHT)
  1223.       else
  1224.         -- Turn the opposite direction to that which we turned before
  1225.         if (startedLayerToRight == true) then
  1226.           turtleTurn(direction.LEFT)
  1227.           startedLayerToRight = false
  1228.         else
  1229.           turtleTurn(direction.RIGHT)
  1230.           startedLayerToRight = true
  1231.         end
  1232.       end
  1233.     end
  1234.  
  1235.     local mineRows
  1236.     local onNearSideOfQuarry = true
  1237.     local diggingAway = true
  1238.     for mineRows = 1, quarryWidth do
  1239.  
  1240.       -- If this is not the first row, then get into position to mine the next row
  1241.       if ((mineRows == 1) and (lookForChests == false)) then
  1242.         -- Not looking for chests, check the block below for being an ore. Only do this
  1243.         -- if we're not looking for chests since the program doesn't support chests in
  1244.         -- bedrock
  1245.         if (isNoiseBlock(turtle.compareDown) == false) then
  1246.           turtle.digDown()
  1247.           ensureInventorySpace()
  1248.         end
  1249.       elseif (mineRows > 1) then
  1250.         -- Move into position for mining the next row
  1251.         if (onNearSideOfQuarry == diggingAway) then
  1252.           if (startedLayerToRight == true) then
  1253.             turtleTurn(direction.LEFT)
  1254.           else
  1255.             turtleTurn(direction.RIGHT)
  1256.           end
  1257.         else
  1258.           if (startedLayerToRight == true) then
  1259.             turtleTurn(direction.RIGHT)
  1260.           else
  1261.             turtleTurn(direction.LEFT)
  1262.           end
  1263.         end
  1264.  
  1265.         turtleForward()
  1266.  
  1267.         -- Before making the final turn, check the block below. Do this
  1268.         -- now because if it is a chest, then we want to back up and
  1269.         -- approach it from the side (so that we don't lose items if we
  1270.         -- have to return to the start through it).
  1271.         --
  1272.         -- This is the point at which it is safe to back up without moving
  1273.         -- out of the quarry area (unless at bedrock in which case don't bother
  1274.         -- as we'll be digging down anyway)
  1275.         if (miningLevel ~= bottomLayer) then
  1276.           if (isNoiseBlock(turtle.compareDown) == false) then
  1277.             -- If we are not looking for chests, then just dig it (it takes
  1278.             -- less time to try to dig and fail as it does to do detect and
  1279.             -- only dig if there is a block there)
  1280.             if (lookForChests == false) then
  1281.               turtle.digDown()
  1282.               ensureInventorySpace()
  1283.             elseif (turtle.detectDown() == true) then
  1284.               if (isChestBlock(turtle.compareDown) == true) then
  1285.                 -- There is a chest block below. Move back and approach
  1286.                 -- from the side to ensure that we don't need to return to
  1287.                 -- start through the chest itself (potentially losing items)
  1288.                 turtleBack()
  1289.                 turtleDown()
  1290.                 currMiningState = miningState.EMPTYCHESTDOWN
  1291.                 emptyChest(turtle.suck)
  1292.                 currMiningState = miningState.LAYER
  1293.                 turtleUp()
  1294.                 turtleForward()
  1295.                 turtle.digDown()
  1296.                 ensureInventorySpace()
  1297.               else
  1298.                 turtle.digDown()
  1299.                 ensureInventorySpace()
  1300.               end
  1301.             end
  1302.           end
  1303.         end
  1304.  
  1305.         -- Move into final position for mining the next row
  1306.         if (onNearSideOfQuarry == diggingAway) then
  1307.           if (startedLayerToRight == true) then
  1308.             turtleTurn(direction.LEFT)
  1309.           else
  1310.             turtleTurn(direction.RIGHT)
  1311.           end
  1312.         else
  1313.           if (startedLayerToRight == true) then
  1314.             turtleTurn(direction.RIGHT)
  1315.           else
  1316.             turtleTurn(direction.LEFT)
  1317.           end
  1318.         end
  1319.       end
  1320.  
  1321.       -- Dig to the other side of the quarry
  1322.       local blocksMined
  1323.       for blocksMined = 0, (quarryWidth - 1) do
  1324.         if (blocksMined > 0) then
  1325.           -- Only move forward if this is not the first space
  1326.           turtleForward()
  1327.         end
  1328.  
  1329.         -- If the current block is (0,0), then record the fact that the
  1330.         -- turtle has been through this block and what it's orientation was and update the layer
  1331.         -- that it should return via to get back to the surface (it no longer needs to go down
  1332.         -- a level to prevent losing ores).
  1333.         if ((currX == 0) and (currZ == 0)) then
  1334.           -- Am at (0, 0). Remember this, and what direction I was facing so that the quickest route
  1335.           -- to the surface can be taken
  1336.           levelToReturnTo = miningLevel
  1337.           haveBeenAtZeroZeroOnLayer = true
  1338.           orientationAtZeroZero = currOrient
  1339.         end
  1340.  
  1341.         -- If currently at bedrock, just move down until the turtle can't go any
  1342.         -- further. This allows the blocks within the bedrock to be mined
  1343.         if (miningLevel == bottomLayer) then
  1344.           -- Temporarily turn off looking for chests to increase bedrock mining speed (this
  1345.           -- means that the program doesn't support chests below level 5 - but I think
  1346.           -- they they don't exist anyway)
  1347.           local lookForChestsPrev = lookForChests
  1348.           lookForChests = false
  1349.  
  1350.           -- Manually set the flag to determine whether the turtle should try to move first or
  1351.           -- dig first. At bedrock, is very rarely any space
  1352.  
  1353.           -- Just above bedrock layer, dig down until can't dig any lower, and then
  1354.           -- come back up. This replicates how the quarry functions
  1355.           lastMoveNeededDig = true
  1356.           local moveDownSuccess = turtleDown()
  1357.           while (moveDownSuccess == true) do
  1358.             moveDownSuccess = turtleDown()
  1359.           end
  1360.  
  1361.           -- Know that we are moving back up through air, therefore set the flag to force the
  1362.           -- turtle to try moving first
  1363.           lastMoveNeededDig = false
  1364.  
  1365.           -- Have now hit bedrock, move back to the mining layer
  1366.           while (currY < bottomLayer) do
  1367.             turtleUp()
  1368.           end
  1369.  
  1370.           -- Now back at the level above bedrock, again reset the flag to tell the turtle to
  1371.           -- try digging again (because it is rare to find air at bedrock level)
  1372.           lastMoveNeededDig = false
  1373.  
  1374.           -- Reset the look for chests value
  1375.           lookForChests = lookForChestsPrev
  1376.         elseif ((blocksMined > 0) and ((currX ~= 0) or (currZ ~= 0))) then
  1377.           -- This isn't the first block of the row, nor are we at (0, 0) so we need to check the
  1378.           -- block below
  1379.  
  1380.           -- Check the block down for being a noise block (don't need to check the first
  1381.           -- block as it has already been checked in the outer loop)
  1382.           if (isNoiseBlock(turtle.compareDown) == false) then
  1383.             -- If we are not looking for chests, then just dig it (it takes
  1384.             -- less time to try to dig and fail as it does to do detect and
  1385.             -- only dig if there is a block there)
  1386.             if (lookForChests == false) then
  1387.               turtle.digDown()
  1388.               ensureInventorySpace()
  1389.             elseif (turtle.detectDown() == true) then
  1390.               if (isChestBlock(turtle.compareDown) == true) then
  1391.                 -- There is a chest block below. Move back and approach
  1392.                 -- from the side to ensure that we don't need to return to
  1393.                 -- start through the chest itself (potentially losing items)
  1394.                 turtleBack()
  1395.                 currMiningState = miningState.EMPTYCHESTDOWN
  1396.                 turtleDown()
  1397.                 emptyChest(turtle.suck)
  1398.                 currMiningState = miningState.LAYER
  1399.                 turtleUp()
  1400.                 turtleForward()
  1401.                 turtle.digDown()
  1402.                 ensureInventorySpace()
  1403.               else
  1404.                 turtle.digDown()
  1405.                 ensureInventorySpace()
  1406.               end
  1407.             end
  1408.           end
  1409.         end
  1410.        
  1411.         -- Check the block above for ores (if we're not a (0, 0) in which case
  1412.         -- we know it's air)
  1413.         if ((currX ~= 0) or (currZ ~= 0)) then
  1414.           if (isNoiseBlock(turtle.compareUp) == false) then
  1415.             -- If we are not looking for chests, then just dig it (it takes
  1416.             -- less time to try to dig and fail as it does to do detect and
  1417.             -- only dig if there is a block there)
  1418.             if (lookForChests == false) then
  1419.               turtle.digUp()
  1420.               ensureInventorySpace()
  1421.             elseif (turtle.detectUp() == true) then
  1422.               -- Determine if it is a chest before digging it
  1423.               if (isChestBlock(turtle.compareUp) == true) then
  1424.                 -- There is a chest block above. Empty it before digging it
  1425.                 emptyChest(turtle.suckUp)
  1426.                 turtle.digUp()
  1427.                 ensureInventorySpace()
  1428.               else
  1429.                 turtle.digUp()
  1430.                 ensureInventorySpace()
  1431.               end
  1432.             end
  1433.           end
  1434.         end
  1435.       end
  1436.  
  1437.       -- Am now at the other side of the quarry
  1438.       onNearSideOfQuarry = not onNearSideOfQuarry
  1439.     end
  1440.  
  1441.     -- If we were digging away from the starting point, will be digging
  1442.     -- back towards it on the next layer
  1443.     diggingAway = not diggingAway
  1444.   end
  1445.  
  1446.   -- Return to the start
  1447.   returnToStartAndUnload(false)
  1448.  
  1449.   -- Face forward
  1450.   turtleSetOrientation(direction.FORWARD)
  1451. end
  1452.  
  1453. -- ********************************************************************************** --
  1454. -- Reads the next number from a given file
  1455. -- ********************************************************************************** --
  1456. function readNumber(inputFile)
  1457.  
  1458.   local returnVal
  1459.   local nextLine = inputFile.readLine()
  1460.   if (nextLine ~= nil) then
  1461.     returnVal = tonumber(nextLine)
  1462.   end
  1463.  
  1464.   return returnVal
  1465. end
  1466.  
  1467. -- ********************************************************************************** --
  1468. -- Startup function to support resuming mining turtle
  1469. -- ********************************************************************************** --
  1470. function isResume()
  1471.  
  1472.   local returnVal = false
  1473.  
  1474.   -- Try to open the resume file
  1475.   local resumeFile = fs.open(startupParamsFile, "r")
  1476.   if (resumeFile == nil) then
  1477.     -- No resume file (presume that we are not supporting it)
  1478.     supportResume = false
  1479.   else
  1480.     writeMessage("Found startup params file", messageLevel.DEBUG)
  1481.  
  1482.     -- Read in the startup params
  1483.     quarryWidth = readNumber(resumeFile)
  1484.     startHeight = readNumber(resumeFile)
  1485.     noiseBlocksCount = readNumber(resumeFile)
  1486.     lastEmptySlot = readNumber(resumeFile)
  1487.     resumeFile.close()
  1488.  
  1489.     -- If the parameters were successfully read, then set the resuming flag to true
  1490.     if ((quarryWidth ~= nil) and (startHeight ~= nil) and (noiseBlocksCount ~= nil) and (lastEmptySlot ~= nil)) then
  1491.  
  1492.       resuming = true
  1493.       writeMessage("Read params", messageLevel.DEBUG)
  1494.  
  1495.       -- Determine the look for chest and mining offset
  1496.       if (lastEmptySlot == 14) then
  1497.         lookForChests = true
  1498.         miningOffset = 0
  1499.       else
  1500.         lookForChests = false
  1501.         miningOffset = 1
  1502.       end
  1503.  
  1504.       -- Get the turtle resume location
  1505.       resumeFile = fs.open(oreQuarryLocation, "r")
  1506.       if (resumeFile ~= nil) then
  1507.  
  1508.         resumeMiningState = readNumber(resumeFile)
  1509.         resumeX = readNumber(resumeFile)
  1510.         resumeY = readNumber(resumeFile)
  1511.         resumeZ = readNumber(resumeFile)
  1512.         resumeOrient = readNumber(resumeFile)
  1513.         resumeFile.close()
  1514.  
  1515.         -- Ensure that the resume location has been found
  1516.         if ((resumeMiningState ~= nil) and (resumeX ~= nil) and (resumeY ~= nil) and (resumeZ ~= nil) and (resumeOrient ~= nil)) then
  1517.           returnVal = true
  1518.           local emptiedInventory = false
  1519.  
  1520.           -- Perform any mining state specific startup
  1521.           if (resumeMiningState == miningState.EMPTYINVENTORY) then
  1522.             -- Am mid way through an empty inventory cycle. Complete it before
  1523.             -- starting the main Quarry function
  1524.             returnToStartAndUnload(true)
  1525.             resuming = true
  1526.  
  1527.             -- Continue from the current position
  1528.             resumeX = currX
  1529.             resumeY = currY
  1530.             levelToReturnTo = resumeY
  1531.             resumeZ = currZ
  1532.             resumeOrient = currOrient
  1533.  
  1534.             writeMessage("Resuming with state of "..currMiningState, messageLevel.DEBUG)
  1535.             resumeMiningState = currMiningState
  1536.             emptiedInventory = true
  1537.           end
  1538.  
  1539.           -- If was emptying a chest when the program stopped, then move back
  1540.           -- to a point which the Quarry
  1541.           if (resumeMiningState == miningState.EMPTYCHESTDOWN) then
  1542.  
  1543.             -- Set the current X, Y, Z and orientation to the true position that
  1544.             -- the turtle is at
  1545.             if (emptiedInventory == false) then
  1546.               currX = resumeX
  1547.               currY = resumeY
  1548.               currZ = resumeZ
  1549.               currOrient = resumeOrient
  1550.             end
  1551.  
  1552.             -- Set the mining state as layer, assume haven't been through zero
  1553.             -- zero and set the level to return to as the one below the current one
  1554.             currMiningState = miningState.LAYER
  1555.             levelToReturnTo = currY - 2
  1556.             haveBeenAtZeroZeroOnLayer = false
  1557.  
  1558.             -- Temporarily disable resuming (so that the new location is written to the file
  1559.             -- in case the program stops again)
  1560.             resuming = false
  1561.             turtleUp()
  1562.             resuming = true
  1563.  
  1564.             resumeY = currY
  1565.             resumeMiningState = miningState.LAYER
  1566.           end
  1567.         end
  1568.       end
  1569.     end
  1570.  
  1571.     if (returnVal == false) then
  1572.       writeMessage("Failed to resume", messageLevel.ERROR)
  1573.     end
  1574.   end
  1575.  
  1576.   return returnVal
  1577. end
  1578.  
  1579. -- ********************************************************************************** --
  1580. -- Main Function                                          
  1581. -- ********************************************************************************** --
  1582. -- Process the input arguments - storing them to global variables
  1583. local args = { ... }
  1584. local paramsOK = true
  1585.  
  1586. -- Detect whether this is a wireless turtle, and if so, open the modem
  1587. local peripheralConnected = peripheral.getType("right")
  1588. if (peripheralConnected == "modem") then
  1589.   isWirelessTurtle = true
  1590. end
  1591.  
  1592. -- If a wireless turtle, open the modem
  1593. if (isWirelessTurtle == true) then
  1594.   turtleId = os.getComputerLabel()
  1595.   rednet.open("right")
  1596. end
  1597.  
  1598. if (#args == 0) then
  1599.   -- Is this a resume?
  1600.   if (isResume() == false) then
  1601.     paramsOK = false
  1602.   end
  1603. elseif (#args == 1) then
  1604.   quarryWidth = tonumber(args[1])
  1605.   local x, y, z = gps.locate(5)
  1606.   startHeight = y
  1607.   if (startHeight == nil) then
  1608.     writeMessage("Can't locate GPS", messageLevel.FATAL)
  1609.     paramsOK = false
  1610.   end
  1611. elseif (#args == 2) then
  1612.   if (args[2] == "/r") then
  1613.     quarryWidth = tonumber(args[1])
  1614.     supportResume = false
  1615.   else
  1616.     quarryWidth = tonumber(args[1])
  1617.     startHeight = tonumber(args[2])
  1618.   end
  1619. elseif (#args == 3) then
  1620.   quarryWidth = tonumber(args[1])
  1621.   startHeight = tonumber(args[2])
  1622.   if (args[3] == "/r") then
  1623.     supportResume = false
  1624.   else
  1625.     paramsOK = false
  1626.   end
  1627. end
  1628.  
  1629. if ((paramsOK == false) and (resuming == false)) then
  1630.   writeMessage("Usage: "..shell.getRunningProgram().." <diameter> [turtleY] [/r]", messageLevel.FATAL)
  1631.   paramsOK = false
  1632. end
  1633.  
  1634. if (paramsOK == true) then
  1635.   if ((startHeight < 6) or (startHeight > 128)) then
  1636.     writeMessage("turtleY must be between 6 and 128", messageLevel.FATAL)
  1637.     paramsOK = false
  1638.   end
  1639.  
  1640.   if ((quarryWidth < 2) or (quarryWidth > 64)) then
  1641.     writeMessage("diameter must be between 2 and 64", messageLevel.FATAL)
  1642.     paramsOK = false
  1643.   end
  1644. end
  1645.  
  1646. if (paramsOK == true) then
  1647.   if (resuming == true) then
  1648.     writeMessage("Resuming Ore Quarry...", messageLevel.INFO)
  1649.   else
  1650.     writeMessage("----------------------------------", messageLevel.INFO)
  1651.     writeMessage("** Ore Quarry v0.71 by AustinKK **", messageLevel.INFO)
  1652.     writeMessage("----------------------------------", messageLevel.INFO)
  1653.   end
  1654.  
  1655.   -- Set the turtle's starting position
  1656.   currX = 0
  1657.   currY = startHeight
  1658.   currZ = 0
  1659.   currOrient = direction.FORWARD
  1660.  
  1661.   -- Calculate which blocks in the inventory signify noise blocks
  1662.   if (resuming == false) then
  1663.     determineNoiseBlocksCountCount()
  1664.   end
  1665.  
  1666.   if ((noiseBlocksCount == 0) or (noiseBlocksCount > 13)) then
  1667.     writeMessage("No noise blocks have been been added. Please place blocks that the turtle should not mine (e.g. Stone, Dirt, Gravel etc.) in the first few slots of the turtle\'s inventory. The first empty slot signifies the end of the noise blocks.", messageLevel.FATAL)
  1668.   else
  1669.     -- If we are supporting resume (and are not currently in the process of resuming)
  1670.     -- then store startup parameters in appropriate files
  1671.     if ((supportResume == true) and (resuming == false)) then
  1672.       -- Write the startup parameters to  file
  1673.       local outputFile = io.open(startupParamsFile, "w")
  1674.       outputFile:write(quarryWidth)
  1675.       outputFile:write("\n")
  1676.       outputFile:write(startHeight)
  1677.       outputFile:write("\n")
  1678.       outputFile:write(noiseBlocksCount)
  1679.       outputFile:write("\n")
  1680.       outputFile:write(lastEmptySlot)
  1681.       outputFile:write("\n")
  1682.       outputFile:close()
  1683.  
  1684.       -- Setup the startup file
  1685.  
  1686.       -- Take a backup of the current startup file
  1687.       if (fs.exists("startup") == true) then
  1688.         fs.copy("startup", startupBackup)
  1689.         outputFile = io.open("startup", "a")
  1690.       else
  1691.         outputFile = io.open("startup", "w")
  1692.       end
  1693.      
  1694.       -- Write an info message so that people know how to get out of auto-resume
  1695.       outputFile:write("\nprint(\"Running auto-restart...\")\n")
  1696.       outputFile:write("print(\"If you want to stop auto-resume and restore original state:\")\n")
  1697.       outputFile:write("print(\"1) Hold Ctrl-T until the program terminates\")\n")
  1698.       outputFile:write("print(\"2) Type \\\"rm startup\\\" (without quotes) and hit Enter\")\n")
  1699.       outputFile:write("print(\"\")\n\n")
  1700.  
  1701.       -- Write the code required to restart the turtle
  1702.       outputFile:write("shell.run(\"")
  1703.       outputFile:write(shell.getRunningProgram())
  1704.       outputFile:write("\")\n")
  1705.       outputFile:close()
  1706.  
  1707.     end
  1708.  
  1709.     -- Create a Quarry
  1710.     turtle.select(1)
  1711.     currentlySelectedSlot = 1
  1712.     createQuarry()
  1713.  
  1714.     -- Restore the file system to its original configuration
  1715.     if (supportResume == true) then
  1716.       fs.delete("startup")
  1717.       if (fs.exists(startupBackup) == true) then
  1718.         fs.move(startupBackup, "startup")
  1719.       end
  1720.  
  1721.       if (fs.exists(startupParamsFile) == true) then
  1722.         fs.delete(startupParamsFile)
  1723.       end
  1724.  
  1725.       if (fs.exists(oreQuarryLocation) == true) then
  1726.         fs.delete(oreQuarryLocation)
  1727.       end
  1728.  
  1729.       if (fs.exists(returnToStartFile) == true) then
  1730.         fs.delete(returnToStartFile)
  1731.       end
  1732.     end
  1733.   end
  1734. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement