ravneravn

oreQuarry

Jun 3rd, 2013
86
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- ********************************************************************************** --
  2. -- ** ** --
  3. -- ** Minecraft Mining Turtle Ore Quarry v0.53 by AustinKK ** --
  4. -- ** ---------------------------------------------------- ** --
  5. -- ** ** --
  6. -- ** For instructions on how to use: ** --
  7. -- ** ** --
  8. -- ** http://www.youtube.com/watch?v=PIugLVzUz3g ** --
  9. -- ** ** --
  10. -- ** Change Log: ** --
  11. -- ** 27th Dec 2012: [v0.2] Initial Draft Release ** --
  12. -- ** 29th Dec 2012: [v0.3] Minor Performance Improvements ** --
  13. -- ** 30th Dec 2012: [v0.4] Further Performance Improvements ** --
  14. -- ** 9th Jan 2013: [v0.5] Debug Version (dropping off chest) ** --
  15. -- ** 10th Jan 2013: [v0.51] Further Debug (dropping off chest) ** --
  16. -- ** 10th Jan 2013: [v0.52] Fix for dropping off chest bug ** --
  17. -- ** 11th Jan 2013: [v0.53] Released fix for chest bug ** --
  18. -- ** ** --
  19. -- ********************************************************************************** --
  20.  
  21. -- Enumeration to store the the different types of message that can be written
  22. messageLevel = { DEBUG=0, INFO=1, WARNING=2, ERROR=3, FATAL=4 }
  23.  
  24. -- Enumeration to store names for the 6 directions
  25. direction = { FORWARD=0, RIGHT=1, BACK=2, LEFT=3, UP=4, DOWN=5 }
  26.  
  27. local messageOutputLevel = messageLevel.INFO
  28. local messageOutputFileName
  29. local fuelLevelToRefuelAt = 5
  30. local refuelItemsToUseWhenRefuelling = 63
  31. local emergencyFuelToRetain = 0
  32. local maximumGravelStackSupported = 25 -- The number of stacked gravel or sand blocks supported
  33. local noiseBlocksCount
  34. local bottomLayer = 5 -- The y co-ords of the layer immediately above bedrock
  35. local returningToStart = false
  36. local lookForChests = false -- Determines if chests should be located as part of the quarrying
  37. local miningOffset -- The offset to the mining layer. This is set depending on whether chests are being looked for or not
  38. 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)
  39. local turtleId
  40. local currentlySelectedSlot = 0 -- The slot that the last noise block was found in
  41. local lastMoveNeededDig = true -- Determines whether the last move needed a dig first
  42. local haveBeenAtZeroZeroOnLayer -- Determines whether the turtle has been at (0, 0) in this mining layer
  43. local orientationAtZeroZero -- The turtle's orientation when it was at (0, 0)
  44. local levelToReturnTo -- The level that the turtle should return to in order to head back to the start to unload
  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.  
  54. -- Command line parameters
  55. local startHeight -- Represents the height (y co-ord) that the turtle started at
  56. local quarryWidth -- Represents the length of the mines that the turtle will dig
  57.  
  58. -- ********************************************************************************** --
  59. -- Writes an output message
  60. -- ********************************************************************************** --
  61. function writeMessage(message, msgLevel)
  62. if (msgLevel >= messageOutputLevel) then
  63. print(message)
  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.  
  71. if (messageOutputFileName ~= nil) then
  72. -- Open file, write message and close file (flush doesn't seem to work!)
  73. local outputFile = io.open(messageOutputFileName, "a")
  74. outputFile:write(message)
  75. outputFile:write("\n")
  76. outputFile:close()
  77. end
  78. end
  79. end
  80.  
  81. -- ********************************************************************************** --
  82. -- Ensures that the turtle has fuel
  83. -- ********************************************************************************** --
  84. function ensureFuel()
  85.  
  86. -- Determine whether a refuel is required
  87. local fuelLevel = turtle.getFuelLevel()
  88. if (fuelLevel ~= "unlimited") then
  89. if (fuelLevel < fuelLevelToRefuelAt) then
  90. -- Need to refuel
  91. turtle.select(16)
  92. currentlySelectedSlot = 16
  93. local fuelItems = turtle.getItemCount(16)
  94.  
  95. -- Do we need to impact the emergency fuel to continue? (always
  96. -- keep one fuel item in slot 16)
  97. if (fuelItems == 0) then
  98. writeMessage("Completely out of fuel!", messageLevel.FATAL)
  99. elseif (fuelItems == 1) then
  100. writeMessage("Out of Fuel!", messageLevel.ERROR)
  101. turtle.refuel()
  102. elseif (fuelItems <= (emergencyFuelToRetain + 1)) then
  103. writeMessage("Consuming emergency fuel supply. "..(fuelItems - 2).." emergency fuel items remain", messageLevel.WARNING)
  104. turtle.refuel(1)
  105. else
  106. -- Refuel the lesser of the refuelItemsToUseWhenRefuelling and the number of items more than
  107. -- the emergency fuel level
  108. if (fuelItems - (emergencyFuelToRetain + 1) < refuelItemsToUseWhenRefuelling) then
  109. turtle.refuel(fuelItems - (emergencyFuelToRetain + 1))
  110. else
  111. turtle.refuel(refuelItemsToUseWhenRefuelling)
  112. end
  113. end
  114. end
  115. end
  116. end
  117.  
  118. -- ********************************************************************************** --
  119. -- Checks that the turtle has inventory space by checking for spare slots and returning
  120. -- to the starting point to empty out if it doesn't.
  121. --
  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.  
  148. -- Store the current location and orientation so that it can be returned to
  149. local storedX = currX
  150. local storedY = currY
  151. local storedZ = currZ
  152. local storedOrient = currOrient
  153.  
  154. writeMessage("Return to start, return level: "..levelToReturnTo, messageLevel.DEBUG)
  155.  
  156. -- Move down to the correct layer to return via
  157. if (currY > levelToReturnTo) then
  158. while (currY > levelToReturnTo) do
  159. turtleDown()
  160. end
  161. elseif (currY < levelToReturnTo) then
  162. while (currY < levelToReturnTo) do
  163. turtleUp()
  164. end
  165. end
  166.  
  167. if ((haveBeenAtZeroZeroOnLayer == false) or (orientationAtZeroZero == direction.FORWARD)) then
  168. -- Move back to the correct X position first
  169. if (currX > 0) then
  170. turtleSetOrientation(direction.LEFT)
  171. while (currX > 0) do
  172. turtleForward()
  173. end
  174. elseif (currX < 0) then
  175. -- This should never happen
  176. writeMessage("Current x is less than 0 in returnToStartAndUnload", messageLevel.ERROR)
  177. end
  178.  
  179. -- Then move back to the correct Z position
  180. if (currZ > 0) then
  181. turtleSetOrientation(direction.BACK)
  182. while (currZ > 0) do
  183. turtleForward()
  184. end
  185. elseif (currZ < 0) then
  186. -- This should never happen
  187. writeMessage("Current z is less than 0 in returnToStartAndUnload", messageLevel.ERROR)
  188. end
  189. else
  190. -- Move back to the correct Z position first
  191. if (currZ > 0) then
  192. turtleSetOrientation(direction.BACK)
  193. while (currZ > 0) do
  194. turtleForward()
  195. end
  196. elseif (currZ < 0) then
  197. -- This should never happen
  198. writeMessage("Current z is less than 0 in returnToStartAndUnload", messageLevel.ERROR)
  199. end
  200.  
  201. -- Then move back to the correct X position
  202. if (currX > 0) then
  203. turtleSetOrientation(direction.LEFT)
  204. while (currX > 0) do
  205. turtleForward()
  206. end
  207. elseif (currX < 0) then
  208. -- This should never happen
  209. writeMessage("Current x is less than 0 in returnToStartAndUnload", messageLevel.ERROR)
  210. end
  211. end
  212.  
  213. -- Return to the starting layer
  214. if (currY < startHeight) then
  215. while (currY < startHeight) do
  216. turtleUp()
  217. end
  218. elseif (currY > startHeight) then
  219. -- This should never happen
  220. writeMessage("Current height is greater than start height in returnToStartAndUnload", messageLevel.ERROR)
  221. end
  222.  
  223. -- Empty the inventory
  224. local slotLoop = 1
  225.  
  226. -- Face the chest
  227. turtleSetOrientation(direction.BACK)
  228.  
  229. -- Loop over each of the slots (except the 16th one which stores fuel)
  230. while (slotLoop < 16) do
  231. -- If this is one of the slots that contains a noise block, empty all blocks except
  232. -- one
  233. turtle.select(slotLoop) -- Don't bother updating selected slot variable as it will set later in this function
  234. if ((slotLoop <= noiseBlocksCount) or ((slotLoop == 15) and (lastEmptySlot == 14))) then
  235. writeMessage("Dropping (n-1) from slot "..slotLoop.." ["..turtle.getItemCount(slotLoop).."]", messageLevel.DEBUG)
  236. turtle.drop(turtle.getItemCount(slotLoop) - 1)
  237. else
  238. -- Not a noise block, drop all of the items in this slot
  239. writeMessage("Dropping (all) from slot "..slotLoop.." ["..turtle.getItemCount(slotLoop).."]", messageLevel.DEBUG)
  240. turtle.drop()
  241. end
  242.  
  243. slotLoop = slotLoop + 1
  244. end
  245.  
  246. -- While we are here, refill the fuel items if there is capacity
  247. if (turtle.getItemCount(16) < 64) then
  248. turtleSetOrientation(direction.LEFT)
  249. turtle.select(16) -- Don't bother updating selected slot variable as it will set later in this function
  250. local currFuelItems = turtle.getItemCount(16)
  251. turtle.suck()
  252. while ((currFuelItems ~= turtle.getItemCount(16)) and (turtle.getItemCount(16) < 64)) do
  253. currFuelItems = turtle.getItemCount(16)
  254. turtle.suck()
  255. end
  256.  
  257. slotLoop = noiseBlocksCount + 1
  258. -- Have now picked up all the items that we can. If we have also picked up some
  259. -- additional fuel in some of the other slots, then drop it again
  260. while (slotLoop <= lastEmptySlot) do
  261. -- Drop any items found in this slot
  262. turtle.select(slotLoop) -- Don't bother updating selected slot variable as it will set later in this function
  263. turtle.drop()
  264. slotLoop = slotLoop + 1
  265. end
  266. end
  267.  
  268. -- Select the 1st slot because sometimes when leaving the 15th or 16th slots selected it can result
  269. -- in that slot being immediately filled (resulting in the turtle returning to base again too soon)
  270. turtle.select(1)
  271. currentlySelectedSlot = 1
  272.  
  273. -- If required, move back to the point that we were mining at before returning to the start
  274. if (returnBackToMiningPoint == true) then
  275. -- Return back to the required layer
  276. while (currY > levelToReturnTo) do
  277. turtleDown()
  278. end
  279.  
  280. if ((haveBeenAtZeroZeroOnLayer == false) or (orientationAtZeroZero == direction.FORWARD)) then
  281. -- Move back to the correct Z position first
  282. writeMessage("Stored Z: "..storedZ..", currZ: "..currZ, messageLevel.DEBUG)
  283. if (storedZ > currZ) then
  284. writeMessage("Orienting forward", messageLevel.DEBUG)
  285. writeMessage("Moving in z direction", messageLevel.DEBUG)
  286. turtleSetOrientation(direction.FORWARD)
  287. while (storedZ > currZ) do
  288. turtleForward()
  289. end
  290. elseif (storedZ < currZ) then
  291. -- This should never happen
  292. writeMessage("Stored z is less than current z in returnToStartAndUnload", messageLevel.ERROR)
  293. end
  294.  
  295. -- Then move back to the correct X position
  296. if (storedX > currX) then
  297. writeMessage("Stored X: "..storedX..", currX: "..currX, messageLevel.DEBUG)
  298. writeMessage("Orienting right", messageLevel.DEBUG)
  299. writeMessage("Moving in x direction", messageLevel.DEBUG)
  300. turtleSetOrientation(direction.RIGHT)
  301. while (storedX > currX) do
  302. turtleForward()
  303. end
  304. elseif (storedX < currX) then
  305. -- This should never happen
  306. writeMessage("Stored x is less than current x in returnToStartAndUnload", messageLevel.ERROR)
  307. end
  308. else
  309. -- Move back to the correct X position first
  310. if (storedX > currX) then
  311. writeMessage("Stored X: "..storedX..", currX: "..currX, messageLevel.DEBUG)
  312. writeMessage("Orienting right", messageLevel.DEBUG)
  313. writeMessage("Moving in x direction", messageLevel.DEBUG)
  314. turtleSetOrientation(direction.RIGHT)
  315. while (storedX > currX) do
  316. turtleForward()
  317. end
  318. elseif (storedX < currX) then
  319. -- This should never happen
  320. writeMessage("Stored x is less than current x in returnToStartAndUnload", messageLevel.ERROR)
  321. end
  322.  
  323. -- Then move back to the correct Z position
  324. writeMessage("Stored Z: "..storedZ..", currZ: "..currZ, messageLevel.DEBUG)
  325. if (storedZ > currZ) then
  326. writeMessage("Orienting forward", messageLevel.DEBUG)
  327. writeMessage("Moving in z direction", messageLevel.DEBUG)
  328. turtleSetOrientation(direction.FORWARD)
  329. while (storedZ > currZ) do
  330. turtleForward()
  331. end
  332. elseif (storedZ < currZ) then
  333. -- This should never happen
  334. writeMessage("Stored z is less than current z in returnToStartAndUnload", messageLevel.ERROR)
  335. end
  336. end
  337.  
  338. -- Move back to the correct layer
  339. if (storedY < currY) then
  340. while (storedY < currY) do
  341. turtleDown()
  342. end
  343. elseif (storedY > currY) then
  344. while (storedY > currY) do
  345. turtleUp()
  346. end
  347. end
  348.  
  349. -- Finally, set the correct orientation
  350. turtleSetOrientation(storedOrient)
  351.  
  352. writeMessage("Have returned to the mining point", messageLevel.DEBUG)
  353. end
  354.  
  355. returningToStart = false
  356.  
  357. end
  358.  
  359. -- ********************************************************************************** --
  360. -- Empties a chest's contents
  361. -- ********************************************************************************** --
  362. function emptyChest(suckFn)
  363.  
  364. local prevInventoryCount = {}
  365. local inventoryLoop
  366. local chestEmptied = false
  367.  
  368. -- Record the number of items in each of the inventory slots
  369. for inventoryLoop = 1, 16 do
  370. prevInventoryCount[inventoryLoop] = turtle.getItemCount(inventoryLoop)
  371. end
  372.  
  373. while (chestEmptied == false) do
  374. -- Pick up the next item
  375. suckFn()
  376.  
  377. -- Determine the number of items in each of the inventory slots now
  378. local newInventoryCount = {}
  379. for inventoryLoop = 1, 16 do
  380. newInventoryCount[inventoryLoop] = turtle.getItemCount(inventoryLoop)
  381. end
  382.  
  383. -- Now, determine whether there have been any items taken from the chest
  384. local foundDifferentItemCount = false
  385. inventoryLoop = 1
  386. while ((foundDifferentItemCount == false) and (inventoryLoop <= 16)) do
  387. if (prevInventoryCount[inventoryLoop] ~= newInventoryCount[inventoryLoop]) then
  388. foundDifferentItemCount = true
  389. else
  390. inventoryLoop = inventoryLoop + 1
  391. end
  392. end
  393.  
  394. -- If no items have been found with a different item count, then the chest has been emptied
  395. chestEmptied = not foundDifferentItemCount
  396.  
  397. if (chestEmptied == false) then
  398. prevInventoryCount = newInventoryCount
  399. -- Check that there is sufficient inventory space as may have picked up a block
  400. ensureInventorySpace()
  401. end
  402. end
  403.  
  404. writeMessage("Finished emptying chest", messageLevel.DEBUG)
  405. end
  406.  
  407.  
  408. -- ********************************************************************************** --
  409. -- Generic function to move the Turtle (pushing through any gravel or other
  410. -- things such as mobs that might get in the way).
  411. --
  412. -- The only thing that should stop the turtle moving is bedrock. Where this is
  413. -- found, the function will return after 15 seconds returning false
  414. -- ********************************************************************************** --
  415. function moveTurtle(moveFn, detectFn, digFn, attackFn, compareFn, suckFn, maxDigCount)
  416.  
  417. ensureFuel()
  418.  
  419. -- Flag to determine whether digging has been tried yet. If it has
  420. -- then pause briefly before digging again to allow sand or gravel to
  421. -- drop
  422. local digCount = 0
  423. local moveSuccess = false
  424.  
  425. if (lastMoveNeededDig == false) then
  426. -- Didn't need to dig last time the turtle moved, so try moving first
  427. moveSuccess = moveFn()
  428.  
  429. -- Don't need to set the last move needed dig. It is already false, if
  430. -- move success is now true, then it won't be changed
  431. else
  432. -- If we are looking for chests, then check that this isn't a chest before trying to dig it
  433. if (lookForChests == true) then
  434. if (isNoiseBlock(compareFn) == false) then
  435. if (detectFn() == true) then
  436. -- Determine if it is a chest before digging it
  437. if (isChestBlock(compareFn) == true) then
  438. -- Have found a chest, empty it before continuing
  439. emptyChest (suckFn)
  440. end
  441. end
  442. end
  443. end
  444.  
  445. -- Try to dig (without doing a detect as it is quicker)
  446. local digSuccess = digFn()
  447. if (digSuccess == true) then
  448. digCount = 1
  449. end
  450. moveSuccess = moveFn()
  451.  
  452. if (moveSuccess == true) then
  453. lastMoveNeededDig = digSuccess
  454. end
  455. end
  456.  
  457. -- Loop until we've successfully moved
  458. if (moveSuccess == false) then
  459. while ((moveSuccess == false) and (digCount < maxDigCount)) do
  460.  
  461. -- If there is a block in front, dig it
  462. if (detectFn() == true) then
  463.  
  464. -- If we've already tried digging, then pause before digging again to let
  465. -- any sand or gravel drop, otherwise check for a chest before digging
  466. if(digCount == 0) then
  467. -- Am about to dig a block - check that it is not a chest if necessary
  468. -- If we are looking for chests, then check that this isn't a chest before moving
  469. if (lookForChests == true) then
  470. if (isNoiseBlock(compareFn) == false) then
  471. if (detectFn() == true) then
  472. -- Determine if it is a chest before digging it
  473. if (isChestBlock(compareFn) == true) then
  474. -- Have found a chest, empty it before continuing
  475. emptyChest (suckFn)
  476. end
  477. end
  478. end
  479. end
  480. else
  481. sleep(0.1)
  482. end
  483.  
  484. digFn()
  485. digCount = digCount + 1
  486. else
  487. -- Am being stopped from moving by a mob, attack it
  488. attackFn()
  489. end
  490.  
  491. -- Try the move again
  492. moveSuccess = moveFn()
  493. end
  494.  
  495. if (digCount == 0) then
  496. lastMoveNeededDig = false
  497. else
  498. lastMoveNeededDig = true
  499. end
  500. end
  501.  
  502. -- Return the move success
  503. return moveSuccess
  504.  
  505. end
  506.  
  507. -- ********************************************************************************** --
  508. -- Move the turtle forward one block (updating the turtle's position)
  509. -- ********************************************************************************** --
  510. function turtleForward()
  511. local returnVal = moveTurtle(turtle.forward, turtle.detect, turtle.dig, turtle.attack, turtle.compare, turtle.suck, maximumGravelStackSupported)
  512. if (returnVal == true) then
  513. -- Update the current co-ordinates
  514. if (currOrient == direction.FORWARD) then
  515. currZ = currZ + 1
  516. elseif (currOrient == direction.LEFT) then
  517. currX = currX - 1
  518. elseif (currOrient == direction.BACK) then
  519. currZ = currZ - 1
  520. elseif (currOrient == direction.RIGHT) then
  521. currX = currX + 1
  522. else
  523. writeMessage ("Invalid currOrient in turtleForward function", messageLevel.ERROR)
  524. end
  525.  
  526. -- Check that there is sufficient inventory space as may have picked up a block
  527. ensureInventorySpace()
  528. end
  529.  
  530. return returnVal
  531. end
  532.  
  533. -- ********************************************************************************** --
  534. -- Move the turtle up one block (updating the turtle's position)
  535. -- ********************************************************************************** --
  536. function turtleUp()
  537. local returnVal = moveTurtle(turtle.up, turtle.detectUp, turtle.digUp, turtle.attackUp, turtle.compareUp, turtle.suckUp, maximumGravelStackSupported)
  538. if (returnVal == true) then
  539. currY = currY + 1
  540.  
  541. -- Check that there is sufficient inventory space as may have picked up a block
  542. ensureInventorySpace()
  543. end
  544. return returnVal
  545. end
  546.  
  547. -- ********************************************************************************** --
  548. -- Move the turtle down one block (updating the turtle's position)
  549. -- ********************************************************************************** --
  550. function turtleDown()
  551. local returnVal
  552.  
  553. -- Because the turtle is digging down, can fail fast (only allow 1 dig attempt).
  554. returnVal = moveTurtle(turtle.down, turtle.detectDown, turtle.digDown, turtle.attackDown, turtle.compareDown, turtle.suckDown, 1)
  555. if (returnVal == true) then
  556. currY = currY - 1
  557.  
  558. -- Check that there is sufficient inventory space as may have picked up a block
  559. ensureInventorySpace()
  560. end
  561. return returnVal
  562. end
  563.  
  564. -- ********************************************************************************** --
  565. -- Move the turtle back one block (updating the turtle's position)
  566. -- ********************************************************************************** --
  567. function turtleBack()
  568. -- First try to move back using the standard function
  569. local returnVal = turtle.back()
  570.  
  571. -- Moving back didn't work (might be a block or a mob in the way). Turn round and move
  572. -- forward instead (whereby anything in the way can be cleared)
  573. if(returnVal == false) then
  574. turtle.turnRight()
  575. turtle.turnRight()
  576. returnVal = turtleForward()
  577. turtle.turnRight()
  578. turtle.turnRight()
  579. end
  580.  
  581. if (returnVal == true) then
  582. -- Update the current co-ordinates
  583. if (currOrient == direction.FORWARD) then
  584. currZ = currZ - 1
  585. elseif (currOrient == direction.LEFT) then
  586. currX = currX + 1
  587. elseif (currOrient == direction.BACK) then
  588. currZ = currZ + 1
  589. elseif (currOrient == direction.RIGHT) then
  590. currX = currX - 1
  591. else
  592. writeMessage ("Invalid currOrient in turtleBack function", messageLevel.ERROR)
  593. end
  594.  
  595. -- Check that there is sufficient inventory space as may have picked up a block
  596. ensureInventorySpace()
  597. end
  598.  
  599. return returnVal
  600. end
  601.  
  602. -- ********************************************************************************** --
  603. -- Turns the turtle (updating the current orientation at the same time)
  604. -- ********************************************************************************** --
  605. function turtleTurn(turnDir)
  606.  
  607. if (turnDir == direction.LEFT) then
  608. if (currOrient == direction.FORWARD) then
  609. currOrient = direction.LEFT
  610. turtle.turnLeft()
  611. elseif (currOrient == direction.LEFT) then
  612. currOrient = direction.BACK
  613. turtle.turnLeft()
  614. elseif (currOrient == direction.BACK) then
  615. currOrient = direction.RIGHT
  616. turtle.turnLeft()
  617. elseif (currOrient == direction.RIGHT) then
  618. currOrient = direction.FORWARD
  619. turtle.turnLeft()
  620. else
  621. writeMessage ("Invalid currOrient in turtleTurn function", messageLevel.ERROR)
  622. end
  623. elseif (turnDir == direction.RIGHT) then
  624. if (currOrient == direction.FORWARD) then
  625. currOrient = direction.RIGHT
  626. turtle.turnRight()
  627. elseif (currOrient == direction.LEFT) then
  628. currOrient = direction.FORWARD
  629. turtle.turnRight()
  630. elseif (currOrient == direction.BACK) then
  631. currOrient = direction.LEFT
  632. turtle.turnRight()
  633. elseif (currOrient == direction.RIGHT) then
  634. currOrient = direction.BACK
  635. turtle.turnRight()
  636. else
  637. writeMessage ("Invalid currOrient in turtleTurn function", messageLevel.ERROR)
  638. end
  639. else
  640. writeMessage ("Invalid turnDir in turtleTurn function", messageLevel.ERROR)
  641. end
  642. end
  643.  
  644. -- ********************************************************************************** --
  645. -- Sets the turtle to a specific orientation, irrespective of its current orientation
  646. -- ********************************************************************************** --
  647. function turtleSetOrientation(newOrient)
  648.  
  649. if (currOrient ~= newOrient) then
  650. if (currOrient == direction.FORWARD) then
  651. if (newOrient == direction.RIGHT) then
  652. turtle.turnRight()
  653. currOrient = newOrient
  654. elseif (newOrient == direction.BACK) then
  655. turtle.turnRight()
  656. turtle.turnRight()
  657. currOrient = newOrient
  658. elseif (newOrient == direction.LEFT) then
  659. turtle.turnLeft()
  660. currOrient = newOrient
  661. else
  662. writeMessage ("Invalid newOrient in turtleSetOrientation function", messageLevel.ERROR)
  663. end
  664. elseif (currOrient == direction.RIGHT) then
  665. if (newOrient == direction.BACK) then
  666. turtle.turnRight()
  667. currOrient = newOrient
  668. elseif (newOrient == direction.LEFT) then
  669. turtle.turnRight()
  670. turtle.turnRight()
  671. currOrient = newOrient
  672. elseif (newOrient == direction.FORWARD) then
  673. turtle.turnLeft()
  674. currOrient = newOrient
  675. else
  676. writeMessage ("Invalid newOrient in turtleSetOrientation function", messageLevel.ERROR)
  677. end
  678. elseif (currOrient == direction.BACK) then
  679. if (newOrient == direction.LEFT) then
  680. turtle.turnRight()
  681. currOrient = newOrient
  682. elseif (newOrient == direction.FORWARD) then
  683. turtle.turnRight()
  684. turtle.turnRight()
  685. currOrient = newOrient
  686. elseif (newOrient == direction.RIGHT) then
  687. turtle.turnLeft()
  688. currOrient = newOrient
  689. else
  690. writeMessage ("Invalid newOrient in turtleSetOrientation function", messageLevel.ERROR)
  691. end
  692. elseif (currOrient == direction.LEFT) then
  693. if (newOrient == direction.FORWARD) then
  694. turtle.turnRight()
  695. currOrient = newOrient
  696. elseif (newOrient == direction.RIGHT) then
  697. turtle.turnRight()
  698. turtle.turnRight()
  699. currOrient = newOrient
  700. elseif (newOrient == direction.BACK) then
  701. turtle.turnLeft()
  702. currOrient = newOrient
  703. else
  704. writeMessage ("Invalid newOrient in turtleSetOrientation function", messageLevel.ERROR)
  705. end
  706. else
  707. writeMessage ("Invalid currOrient in turtleTurn function", messageLevel.ERROR)
  708. end
  709. end
  710. end
  711.  
  712. -- ********************************************************************************** --
  713. -- Determines if a particular block is considered a noise block or not. A noise
  714. -- block is one that is a standard block in the game (stone, dirt, gravel etc.) and
  715. -- is one to ignore as not being an ore. Function works by comparing the block
  716. -- in question against a set of blocks in the turtle's inventory which are known not to
  717. -- be noise blocks. Param is the function to use to compare the block for a noise block
  718. -- ********************************************************************************** --
  719. function isNoiseBlock(compareFn)
  720.  
  721. -- Consider air to be a noise block
  722. local returnVal = false
  723. local seamLoop = 1
  724. local prevSelectedSlot
  725.  
  726. -- If the currently selected slot is a noise block, then compare against this first
  727. -- so that the slot doesn't need to be selected again (there is a 0.05s cost to do
  728. -- this even if it is the currently selected slot)
  729. if (currentlySelectedSlot <= noiseBlocksCount) then
  730. returnVal = compareFn()
  731. end
  732.  
  733. if (returnVal == false) then
  734. prevSelectedSlot = currentlySelectedSlot
  735. while((returnVal == false) and (seamLoop <= noiseBlocksCount)) do
  736. if (seamLoop ~= prevSelectedSlot) then
  737. turtle.select(seamLoop)
  738. currentlySelectedSlot = seamLoop
  739. returnVal = compareFn()
  740. end
  741. seamLoop = seamLoop + 1
  742. end
  743. end
  744.  
  745. -- Return the calculated value
  746. return returnVal
  747.  
  748. end
  749.  
  750. -- ********************************************************************************** --
  751. -- Determines if a particular block is a chest. Returns false if it is not a chest
  752. -- or chests are not being detected
  753. -- ********************************************************************************** --
  754. function isChestBlock(compareFn)
  755.  
  756. -- Check the block in the appropriate direction to see whether it is a chest. Only
  757. -- do this if we are looking for chests
  758. local returnVal = false
  759. if (lookForChests == true) then
  760. turtle.select(15)
  761. currentlySelectedSlot = 15
  762. returnVal = compareFn()
  763. end
  764.  
  765. -- Return the calculated value
  766. return returnVal
  767.  
  768. end
  769.  
  770. -- ********************************************************************************** --
  771. -- Function to calculate the number of non seam blocks in the turtle's inventory. This
  772. -- is all of the blocks at the start of the inventory (before the first empty slot is
  773. -- found
  774. -- ********************************************************************************** --
  775. function determineNoiseBlocksCountCount()
  776. -- Determine the location of the first empty inventory slot. All items before this represent
  777. -- noise items.
  778. local foundFirstBlankInventorySlot = false
  779. noiseBlocksCount = 1
  780. while ((noiseBlocksCount < 16) and (foundFirstBlankInventorySlot == false)) do
  781. if (turtle.getItemCount(noiseBlocksCount) > 0) then
  782. noiseBlocksCount = noiseBlocksCount + 1
  783. else
  784. foundFirstBlankInventorySlot = true
  785. end
  786. end
  787. noiseBlocksCount = noiseBlocksCount - 1
  788.  
  789. -- Determine whether a chest was provided, and hence whether we should support
  790. -- looking for chests
  791. if (turtle.getItemCount(15) > 0) then
  792. lookForChests = true
  793. lastEmptySlot = 14
  794. miningOffset = 0
  795. writeMessage("Looking for chests...", messageLevel.DEBUG)
  796. else
  797. lastEmptySlot = 15
  798. miningOffset = 1
  799. writeMessage("Ignoring chests...", messageLevel.DEBUG)
  800. end
  801. end
  802.  
  803. -- ********************************************************************************** --
  804. -- Creates a quarry mining out only ores and leaving behind any noise blocks
  805. -- ********************************************************************************** --
  806. function createQuarry()
  807.  
  808. -- Determine the top mining layer layer. The turtle mines in layers of 3, and the bottom layer
  809. -- is the layer directly above bedrock.
  810. --
  811. -- The actual layer that the turtle operates in is the middle of these three layers,
  812. -- so determine the top layer
  813. local topMiningLayer = startHeight + ((bottomLayer - startHeight - 2) % 3) - 1 + miningOffset
  814.  
  815. -- If the top layer is up, then ignore it and move to the next layer
  816. if (topMiningLayer > currY) then
  817. topMiningLayer = topMiningLayer - 3
  818. end
  819.  
  820. local startedLayerToRight = true -- Only used where the quarry is of an odd width
  821.  
  822. -- Loop over each mining row
  823. local miningLevel
  824. for miningLevel = (bottomLayer + miningOffset), topMiningLayer, 3 do
  825. writeMessage("Mining Layer: "..miningLevel, messageLevel.INFO)
  826. haveBeenAtZeroZeroOnLayer = false
  827.  
  828. -- While the initial shaft is being dug out, set the level to return to in order to unload
  829. -- to the just take the turtle straight back up
  830. if (miningLevel == (bottomLayer + miningOffset)) then
  831. levelToReturnTo = startHeight
  832. end
  833.  
  834. -- Move to the correct level to start mining
  835. if (currY > miningLevel) then
  836. while (currY > miningLevel) do
  837. turtleDown()
  838. end
  839. elseif (currY < miningLevel) then
  840. while (currY < miningLevel) do
  841. turtleUp()
  842. end
  843. end
  844.  
  845. -- Set the layer to return via when returning to the surface as the one below the currently
  846. -- mined one
  847. if (miningLevel == (bottomLayer + miningOffset)) then
  848. levelToReturnTo = (bottomLayer + miningOffset)
  849. else
  850. levelToReturnTo = miningLevel - 3
  851. end
  852.  
  853. -- Move turtle into the correct orientation to start mining (if this is the
  854. -- first row to be mined, then don't need to turn, otherwise turn towards the next
  855. -- mining section)
  856.  
  857. writeMessage("Mining Level: "..miningLevel..", Bottom Layer: "..bottomLayer..", Mining Offset: "..miningOffset, messageLevel.DEBUG)
  858.  
  859. if (miningLevel > (bottomLayer + miningOffset)) then
  860. -- Turn towards the next mining layer
  861. if (quarryWidth % 2 == 0) then
  862. -- An even width quarry, always turn right
  863. turtleTurn(direction.RIGHT)
  864. else
  865. -- Turn the opposite direction to that which we turned before
  866. if (startedLayerToRight == true) then
  867. turtleTurn(direction.LEFT)
  868. startedLayerToRight = false
  869. else
  870. turtleTurn(direction.RIGHT)
  871. startedLayerToRight = true
  872. end
  873. end
  874. end
  875.  
  876. local mineRows
  877. local onNearSideOfQuarry = true
  878. local diggingAway = true
  879. for mineRows = 1, quarryWidth do
  880.  
  881. -- If this is not the first row, then get into position to mine the next row
  882. if ((mineRows == 1) and (lookForChests == false)) then
  883. -- Not looking for chests, check the block below for being an ore. Only do this
  884. -- if we're not looking for chests since the program doesn't support chests in
  885. -- bedrock
  886. if (isNoiseBlock(turtle.compareDown) == false) then
  887. turtle.digDown()
  888. ensureInventorySpace()
  889. end
  890. elseif (mineRows > 1) then
  891. -- Move into position for mining the next row
  892. if (onNearSideOfQuarry == diggingAway) then
  893. if (startedLayerToRight == true) then
  894. turtleTurn(direction.LEFT)
  895. else
  896. turtleTurn(direction.RIGHT)
  897. end
  898. else
  899. if (startedLayerToRight == true) then
  900. turtleTurn(direction.RIGHT)
  901. else
  902. turtleTurn(direction.LEFT)
  903. end
  904. end
  905.  
  906. turtleForward()
  907.  
  908. -- Before making the final turn, check the block below. Do this
  909. -- now because if it is a chest, then we want to back up and
  910. -- approach it from the side (so that we don't lose items if we
  911. -- have to return to the start through it).
  912. --
  913. -- This is the point at which it is safe to back up without moving
  914. -- out of the quarry area (unless at bedrock in which case don't bother
  915. -- as we'll be digging down anyway)
  916. if (miningLevel ~= bottomLayer) then
  917. if (isNoiseBlock(turtle.compareDown) == false) then
  918. -- If we are not looking for chests, then just dig it (it takes
  919. -- less time to try to dig and fail as it does to do detect and
  920. -- only dig if there is a block there)
  921. if (lookForChests == false) then
  922. turtle.digDown()
  923. ensureInventorySpace()
  924. elseif (turtle.detectDown() == true) then
  925. if (isChestBlock(turtle.compareDown) == true) then
  926. -- There is a chest block below. Move back and approach
  927. -- from the side to ensure that we don't need to return to
  928. -- start through the chest itself (potentially losing items)
  929. turtleBack()
  930. turtleDown()
  931. emptyChest(turtle.suck)
  932. turtleUp()
  933. turtleForward()
  934. turtle.digDown()
  935. ensureInventorySpace()
  936. else
  937. turtle.digDown()
  938. ensureInventorySpace()
  939. end
  940. end
  941. end
  942. end
  943.  
  944. -- Move into final position for mining the next row
  945. if (onNearSideOfQuarry == diggingAway) then
  946. if (startedLayerToRight == true) then
  947. turtleTurn(direction.LEFT)
  948. else
  949. turtleTurn(direction.RIGHT)
  950. end
  951. else
  952. if (startedLayerToRight == true) then
  953. turtleTurn(direction.RIGHT)
  954. else
  955. turtleTurn(direction.LEFT)
  956. end
  957. end
  958. end
  959.  
  960. -- Dig to the other side of the quarry
  961. local blocksMined
  962. for blocksMined = 0, (quarryWidth - 1) do
  963. if (blocksMined > 0) then
  964. -- Only move forward if this is not the first space
  965. turtleForward()
  966. end
  967.  
  968. -- If the current block is (0,0), then record the fact that the
  969. -- turtle has been through this block and what it's orientation was and update the layer
  970. -- that it should return via to get back to the surface (it no longer needs to go down
  971. -- a level to prevent losing ores).
  972. if ((currX == 0) and (currZ == 0)) then
  973. -- Am at (0, 0). Remember this, and what direction I was facing so that the quickest route
  974. -- to the surface can be taken
  975. levelToReturnTo = miningLevel
  976. haveBeenAtZeroZeroOnLayer = true
  977. orientationAtZeroZero = currOrient
  978. end
  979.  
  980. -- If currently at bedrock, just move down until the turtle can't go any
  981. -- further. This allows the blocks within the bedrock to be mined
  982. if (miningLevel == bottomLayer) then
  983. -- Temporarily turn off looking for chests to increase bedrock mining speed (this
  984. -- means that the program doesn't support chests below level 5 - but I think
  985. -- they they don't exist anyway)
  986. local lookForChestsPrev = lookForChests
  987. lookForChests = false
  988.  
  989. -- Manually set the flag to determine whether the turtle should try to move first or
  990. -- dig first. At bedrock, is very rarely any space
  991.  
  992. -- Just above bedrock layer, dig down until can't dig any lower, and then
  993. -- come back up. This replicates how the quarry functions
  994. lastMoveNeededDig = true
  995. local moveDownSuccess = turtleDown()
  996. while (moveDownSuccess == true) do
  997. moveDownSuccess = turtleDown()
  998. end
  999.  
  1000. -- Know that we are moving back up through air, therefore set the flag to force the
  1001. -- turtle to try moving first
  1002. lastMoveNeededDig = false
  1003.  
  1004. -- Have now hit bedrock, move back to the mining layer
  1005. while (currY < bottomLayer) do
  1006. turtleUp()
  1007. end
  1008.  
  1009. -- Now back at the level above bedrock, again reset the flag to tell the turtle to
  1010. -- try digging again (because it is rare to find air at bedrock level)
  1011. lastMoveNeededDig = false
  1012.  
  1013. -- Reset the look for chests value
  1014. lookForChests = lookForChestsPrev
  1015. elseif ((blocksMined > 0) and ((currX ~= 0) or (currZ ~= 0))) then
  1016. -- This isn't the first block of the row, nor are we at (0, 0) so we need to check the
  1017. -- block below
  1018.  
  1019. -- Check the block down for being a noise block (don't need to check the first
  1020. -- block as it has already been checked in the outer loop)
  1021. if (isNoiseBlock(turtle.compareDown) == false) then
  1022. -- If we are not looking for chests, then just dig it (it takes
  1023. -- less time to try to dig and fail as it does to do detect and
  1024. -- only dig if there is a block there)
  1025. if (lookForChests == false) then
  1026. turtle.digDown()
  1027. ensureInventorySpace()
  1028. elseif (turtle.detectDown() == true) then
  1029. if (isChestBlock(turtle.compareDown) == true) then
  1030. -- There is a chest block below. Move back and approach
  1031. -- from the side to ensure that we don't need to return to
  1032. -- start through the chest itself (potentially losing items)
  1033. turtleBack()
  1034. turtleDown()
  1035. emptyChest(turtle.suck)
  1036. turtleUp()
  1037. turtleForward()
  1038. turtle.digDown()
  1039. ensureInventorySpace()
  1040. else
  1041. turtle.digDown()
  1042. ensureInventorySpace()
  1043. end
  1044. end
  1045. end
  1046. end
  1047.  
  1048. -- Check the block above for ores (if we're not a (0, 0) in which case
  1049. -- we know it's air)
  1050. if ((currX ~= 0) or (currZ ~= 0)) then
  1051. if (isNoiseBlock(turtle.compareUp) == false) then
  1052. -- If we are not looking for chests, then just dig it (it takes
  1053. -- less time to try to dig and fail as it does to do detect and
  1054. -- only dig if there is a block there)
  1055. if (lookForChests == false) then
  1056. turtle.digUp()
  1057. ensureInventorySpace()
  1058. elseif (turtle.detectUp() == true) then
  1059. -- Determine if it is a chest before digging it
  1060. if (isChestBlock(turtle.compareUp) == true) then
  1061. -- There is a chest block above. Empty it before digging it
  1062. emptyChest(turtle.suckUp)
  1063. turtle.digUp()
  1064. ensureInventorySpace()
  1065. else
  1066. turtle.digUp()
  1067. ensureInventorySpace()
  1068. end
  1069. end
  1070. end
  1071. end
  1072. end
  1073.  
  1074. -- Am now at the other side of the quarry
  1075. onNearSideOfQuarry = not onNearSideOfQuarry
  1076. end
  1077.  
  1078. -- If we were digging away from the starting point, will be digging
  1079. -- back towards it on the next layer
  1080. diggingAway = not diggingAway
  1081. end
  1082.  
  1083. -- Return to the start
  1084. returnToStartAndUnload(false)
  1085.  
  1086. -- Face forward
  1087. turtleSetOrientation(direction.FORWARD)
  1088. end
  1089.  
  1090. -- ********************************************************************************** --
  1091. -- Main Function
  1092. -- ********************************************************************************** --
  1093. -- Process the input arguments - storing them to global variables
  1094. local args = { ... }
  1095. local paramsOK = true
  1096.  
  1097. turtleId = os.getComputerLabel()
  1098. rednet.open("right")
  1099.  
  1100. if (#args == 1) then
  1101. quarryWidth = tonumber(args[1])
  1102. local x, y, z = gps.locate(5)
  1103. startHeight = y
  1104. if (startHeight == nil) then
  1105. writeMessage("Can't locate GPS", messageLevel.FATAL)
  1106. paramsOK = false
  1107. end
  1108. elseif (#args == 2) then
  1109. quarryWidth = tonumber(args[1])
  1110. startHeight = tonumber(args[2])
  1111. else
  1112. writeMessage("Usage: OreQuarry <diameter> <turtleY>", messageLevel.FATAL)
  1113. paramsOK = false
  1114. end
  1115.  
  1116. if (paramsOK == true) then
  1117. if ((startHeight < 6) or (startHeight > 128)) then
  1118. writeMessage("turtleY must be between 6 and 128", messageLevel.FATAL)
  1119. paramsOK = false
  1120. end
  1121.  
  1122. if ((quarryWidth < 2) or (quarryWidth > 64)) then
  1123. writeMessage("diameter must be between 2 and 64", messageLevel.FATAL)
  1124. paramsOK = false
  1125. end
  1126. end
  1127.  
  1128. if (paramsOK == true) then
  1129. writeMessage("----------------------------------", messageLevel.INFO)
  1130. writeMessage("** Ore Quarry v0.53 by AustinKK **", messageLevel.INFO)
  1131. writeMessage("----------------------------------", messageLevel.INFO)
  1132.  
  1133. -- Set the turtle's starting position
  1134. currX = 0
  1135. currY = startHeight
  1136. currZ = 0
  1137. currOrient = direction.FORWARD
  1138.  
  1139. -- Calculate which blocks in the inventory signify noise blocks
  1140. determineNoiseBlocksCountCount()
  1141.  
  1142. if ((noiseBlocksCount == 0) or (noiseBlocksCount > 13)) then
  1143. 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)
  1144. else
  1145. -- Create a Quarry
  1146. turtle.select(1)
  1147. currentlySelectedSlot = 1
  1148. createQuarry()
  1149. end
  1150. end
RAW Paste Data