rithrin

Tmine

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