Advertisement
subzero22

OreQuarry edited

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