Thanateros

Untitled

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