Want more features on Pastebin? Sign Up, it's FREE!
Guest

OreQuarry

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