Visual_Studio

AustinKK Ore Quarry - 6/14/25

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