Godleydemon

OreQuarry

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