Advertisement
AustinKK

OreQuarry with Resume

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