Advertisement
kreezxil

Ore Quarry with Resume

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