Advertisement
Guest User

Untitled

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