LazyNub

Ore Quarry v0.7 with compression and padding v0.2

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