Advertisement
soee

quarry

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