Aeolun

OreQuarry Upgrade

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