Advertisement
AXMAN43

Quarry 2

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