Advertisement
Timcard30

[CC] OreQuarry

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