soulgriever

Ore Quarry v0.71

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