Advertisement
Guest User

Untitled

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