Advertisement
guamie

Turtle - AdvOreQuarry

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