KeldonSlayer

OreQuarry 1.0 1.18+

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