Advertisement
mondayx

Untitled

Jan 22nd, 2017
622
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.14 KB | None | 0 0
  1. --[[
  2. Branch mining program for OpenComputers robots.
  3.  
  4. This program is designed to dig out branches, in a fashion that allows
  5. players to easily navigate the dug out tunnels. The primary concern was
  6. not the performance of the mining, only a good detection rate, and nice
  7. tunnels. Suggested upgrades for this are the geolyzer and inventory
  8. controller upgrade, and depending on your world gen (ravines?) a hover
  9. upgrade might be necessary. The rest is up to you (chunkloading, more
  10. inventory, battery upgrades).
  11.  
  12. By Sangar, 2015
  13.  
  14. This program is licensed under the MIT license.
  15. http://opensource.org/licenses/mit-license.php
  16. ]]
  17.  
  18. local component = require("component")
  19. local computer = require("computer")
  20. local robot = require("robot")
  21. local shell = require("shell")
  22. local sides = require("sides")
  23. local args, options = shell.parse(...)
  24.  
  25. --[[ Config ]]-----------------------------------------------------------------
  26.  
  27. -- Every how many blocks to dig a side shaft. The default makes for a
  28. -- two wide wall between tunnels, making sure we don't miss anything.
  29. local shaftInterval = 3
  30.  
  31. -- Max recursion level for mining ore veins. We abort early because we
  32. -- assume we'll encounter the same vein again from an adjacent tunnel.
  33. local maxVeinRecursion = 8
  34.  
  35. -- Every how many blocks to place a torch when placing torches.
  36. local torchInverval = 11
  37.  
  38. --[[ Constants ]]--------------------------------------------------------------
  39.  
  40. -- Quick look-up table for inverting directions.
  41. local oppositeSides = {
  42. [sides.north] = sides.south,
  43. [sides.south] = sides.north,
  44. [sides.east] = sides.west,
  45. [sides.west] = sides.east,
  46. [sides.up] = sides.down,
  47. [sides.down] = sides.up
  48. }
  49.  
  50. -- For pushTurn() readability.
  51. local left = false
  52. local right = not left
  53.  
  54. --[[ State ]]------------------------------------------------------------------
  55.  
  56. -- Slots we don't want to drop. Filled in during initialization, based
  57. -- on items already in the inventory. Useful for stuff like /dev/null.
  58. local keepSlot = {}
  59.  
  60. -- Slots that we keep torches in, updated when stocking up on torches.
  61. local torchSlots = {}
  62.  
  63. --[[ "Passive" logic ]]--------------------------------------------------------
  64.  
  65. -- Keep track of moves we're away from our origin, and average energy used per
  66. -- move. This is used to compute the threshold at which we have to return to
  67. -- maintenance to recharge.
  68. local preMoveEnergy, averageMoveCost, distanceToOrigin = 0, 15, 0
  69.  
  70. -- The actual callback called in postMove().
  71. local onMove
  72.  
  73. -- Called whenever we're about to move, used to compute move cost.
  74. local function preMove()
  75. preMoveEnergy = computer.energy()
  76. end
  77.  
  78. -- Called whenever we're done moving, used for automatic torch placement an digging.
  79. local function postMove()
  80. local moveCost = preMoveEnergy - computer.energy()
  81. if moveCost > 0 then
  82. averageMoveCost = (averageMoveCost + moveCost) / 2
  83. end
  84. if onMove then
  85. onMove()
  86. end
  87. end
  88.  
  89. --[[ Utility ]]----------------------------------------------------------------
  90.  
  91. local function prompt(message)
  92. io.write(message .. " [Y/n] ")
  93. local result = io.read()
  94. return result and (result == "" or result:lower() == "y")
  95. end
  96.  
  97. -- Check if a block with the specified info should be mined.
  98. local function shouldMine(info)
  99. return info and info.name and (info.name:match(".*ore.*") or info.name:match(".*Ore.*"))
  100. end
  101.  
  102. -- Number of stacks of torches to keep; default is 1 per inventory upgrade.
  103. local function torchStacks()
  104. return math.max(1, math.ceil(robot.inventorySize() / 16))
  105. end
  106.  
  107. -- Look for the first empty slot in our inventory.
  108. local function findEmptySlot()
  109. for slot = 1, robot.inventorySize() do
  110. if robot.count(slot) == 0 then
  111. return slot
  112. end
  113. end
  114. end
  115.  
  116. -- Find the first torch slot that still contains torches.
  117. local function findTorchSlot()
  118. for _, slot in ipairs(torchSlots) do
  119. if robot.count(slot) > 0 then
  120. return slot
  121. end
  122. end
  123. end
  124.  
  125. -- Since robot.select() is an indirect call, we can speed things up a bit.
  126. local selectedSlot
  127. local function cachedSelect(slot)
  128. if slot ~= selectedSlot then
  129. robot.select(slot)
  130. selectedSlot = slot
  131. end
  132. end
  133.  
  134. -- Place a single torch above the robot, if there are any torches left.
  135. local function placeTorch()
  136. local slot = findTorchSlot()
  137. local result = false
  138. if slot then
  139. cachedSelect(slot)
  140. result = robot.placeUp()
  141. cachedSelect(1)
  142. end
  143. return result
  144. end
  145.  
  146. -- Dig out a block on the specified side, without tool if possible.
  147. local function dig(side, callback)
  148. repeat
  149. -- Check for maintenance first, to make sure we make the return trip when
  150. -- our batteries are running low.
  151. local emptySlot = findEmptySlot()
  152. if callback then
  153. callback(not emptySlot) -- Parameter: is inventory full.
  154. emptySlot = findEmptySlot()
  155. end
  156. cachedSelect(1)
  157.  
  158. local something, what = component.robot.detect(side)
  159. if not something or what == "replaceable" or what == "liquid" then
  160. return true -- We can just move into whatever is there.
  161. end
  162.  
  163. local brokeSomething
  164.  
  165. local info = component.isAvailable("geolyzer") and
  166. component.geolyzer.analyze(side)
  167. if info and info.name == "OpenComputers:robot" then
  168. brokeSomething = true -- Wait for other robot to go away.
  169. os.sleep(0.5)
  170. elseif component.isAvailable("inventory_controller") and emptySlot then
  171. cachedSelect(emptySlot)
  172. component.inventory_controller.equip() -- Save some tool durability.
  173. cachedSelect(1)
  174. brokeSomething = component.robot.swing(side)
  175. cachedSelect(emptySlot)
  176. component.inventory_controller.equip()
  177. cachedSelect(1)
  178. end
  179. if not brokeSomething then
  180. brokeSomething = component.robot.swing(side)
  181. end
  182. until not brokeSomething
  183. end
  184.  
  185. -- Force a move towards in the specified direction.
  186. local function forceMove(side, delta)
  187. preMove()
  188. local result = component.robot.move(side)
  189. if result then
  190. distanceToOrigin = distanceToOrigin + delta
  191. postMove()
  192. else
  193. -- Obstructed, try to clear the way.
  194. if side == sides.back then
  195. -- Moving backwards, turn around.
  196. component.robot.turn(left)
  197. component.robot.turn(left)
  198. repeat
  199. dig(sides.forward)
  200. preMove()
  201. until robot.forward()
  202. distanceToOrigin = distanceToOrigin + delta
  203. component.robot.turn(left)
  204. component.robot.turn(left)
  205. postMove() -- Slightly falsifies move cost, but must ensure we're rotated
  206. -- correctly in case postMove() triggers going to maintenance.
  207. else
  208. repeat
  209. dig(side)
  210. preMove()
  211. until component.robot.move(side)
  212. distanceToOrigin = distanceToOrigin + delta
  213. postMove()
  214. end
  215. end
  216. return true
  217. end
  218.  
  219. --[[ Navigation ]]-------------------------------------------------------------
  220.  
  221. -- Keeps track of our moves to allow "undoing" them for returning to the
  222. -- docking station. Format is a list of moves, represented as tables
  223. -- containing the type of move and distance to move, e.g.
  224. -- {move=sides.back, count=10},
  225. -- {turn=true, count=2}
  226. -- means we first moved back 10 blocks, then turned around.
  227. local moves = {}
  228.  
  229. -- Undo a *single* move, i.e. reduce the count of the latest move type.
  230. local function undoMove(move)
  231. if move.move then
  232. local side = oppositeSides[move.move]
  233. forceMove(side, -1)
  234. else
  235. local direction = not move.turn
  236. component.robot.turn(direction)
  237. end
  238. move.count = move.count - 1
  239. end
  240.  
  241. -- Make a turn in the specified direction.
  242. local function pushTurn(direction)
  243. component.robot.turn(direction)
  244. if moves[#moves] and moves[#moves].turn == direction then
  245. moves[#moves].count = moves[#moves].count + 1
  246. else
  247. moves[#moves + 1] = {turn=direction, count=1}
  248. end
  249. return true -- Allows for `return pushMove() and pushTurn() and pushMove()`.
  250. end
  251.  
  252. -- Try to make a move towards the specified side.
  253. local function pushMove(side, force)
  254. preMove()
  255. local result, reason = (force and forceMove or component.robot.move)(side, 1)
  256. if result then
  257. if moves[#moves] and moves[#moves].move == side then
  258. moves[#moves].count = moves[#moves].count + 1
  259. else
  260. moves[#moves + 1] = {move=side, count=1}
  261. end
  262. if not force then
  263. distanceToOrigin = distanceToOrigin + 1
  264. end
  265. postMove()
  266. end
  267. return result, reason
  268. end
  269.  
  270. -- Undo the most recent move *type*. I.e. will undo all moves of the most
  271. -- recent type (say we moved forwards twice, this will go back twice).
  272. local function popMove()
  273. -- Deep copy the move for returning it.
  274. local move = moves[#moves] and {move=moves[#moves].move,
  275. turn=moves[#moves].turn,
  276. count=moves[#moves].count}
  277. while moves[#moves] and moves[#moves].count > 0 do
  278. undoMove(moves[#moves])
  279. end
  280. moves[#moves] = nil
  281. return move
  282. end
  283.  
  284. -- Get the current top and count values, to be used as a position snapshot
  285. -- that can be restored later on by calling setTop().
  286. local function getTop()
  287. if moves[#moves] then
  288. return #moves, moves[#moves].count
  289. else
  290. return 0, 0
  291. end
  292. end
  293.  
  294. -- Undo some moves based on a stored top and count received from getTop().
  295. local function setTop(top, count, unsafe)
  296. assert(top >= 0)
  297. assert(top <= #moves)
  298. assert(count >= 0)
  299. assert(top < #moves or count <= moves[#moves].count)
  300. while #moves > top do
  301. if unsafe then
  302. if moves[#moves].move then
  303. distanceToOrigin = distanceToOrigin - moves[#moves].count
  304. end
  305. moves[#moves] = nil
  306. else
  307. popMove()
  308. end
  309. end
  310. local move = moves[#moves]
  311. if move then
  312. while move.count > count do
  313. if unsafe then
  314. move.count = move.count - 1
  315. distanceToOrigin = distanceToOrigin - 1
  316. else
  317. undoMove(move)
  318. end
  319. end
  320. if move.count < 1 then
  321. moves[#moves] = nil
  322. end
  323. end
  324. end
  325.  
  326. -- Undo *all* moves made since program start, return the list of moves.
  327. local function popMoves()
  328. local result = {}
  329. local move = popMove()
  330. while move do
  331. table.insert(result, 1, move)
  332. move = popMove()
  333. end
  334. return result
  335. end
  336.  
  337. -- Repeat the specified set of moves.
  338. local function pushMoves(moves)
  339. for _, move in ipairs(moves) do
  340. if move.move then
  341. for _ = 1, move.count do
  342. pushMove(move.move, true)
  343. end
  344. else
  345. for _ = 1, move.count do
  346. pushTurn(move.turn)
  347. end
  348. end
  349. end
  350. end
  351.  
  352. --[[ Maintenance ]]------------------------------------------------------------
  353.  
  354. -- Energy required to return to docking bay.
  355. local function costToReturn()
  356. -- Overestimate a bit, to account for obstacles such as gravel or mobs.
  357. return 5000 + averageMoveCost * distanceToOrigin * 1.25
  358. end
  359.  
  360. -- Checks whether we need maintenance.
  361. local function needsMaintenance()
  362. return not robot.durability() or -- Tool broken?
  363. computer.energy() < costToReturn() or -- Out of juice?
  364. not findTorchSlot() -- No more torches?
  365. end
  366.  
  367. -- Drops all inventory contents that are not marked for keeping.
  368. local function dropMinedBlocks()
  369. if component.isAvailable("inventory_controller") then
  370. if not component.inventory_controller.getInventorySize(sides.down) then
  371. io.write("There doesn't seem to be an inventory below me! Waiting to avoid spilling stuffs into the world.\n")
  372. end
  373. repeat os.sleep(5) until component.inventory_controller.getInventorySize(sides.down)
  374. end
  375. io.write("Dropping what I found.\n")
  376. for slot = 1, robot.inventorySize() do
  377. while not keepSlot[slot] and robot.count(slot) > 0 do
  378. cachedSelect(slot)
  379. robot.dropDown()
  380. end
  381. end
  382. cachedSelect(1)
  383. end
  384.  
  385. -- Ensures we have a tool with durability.
  386. local function checkTool()
  387. if not robot.durability() then
  388. io.write("Tool is broken, getting a new one.\n")
  389. if component.isAvailable("inventory_controller") then
  390. cachedSelect(findEmptySlot()) -- Select an empty slot for working.
  391. repeat
  392. component.inventory_controller.equip() -- Drop whatever's in the tool slot.
  393. while robot.count() > 0 do
  394. robot.dropDown()
  395. end
  396. robot.suckUp(1) -- Pull something from above and equip it.
  397. component.inventory_controller.equip()
  398. until robot.durability()
  399. cachedSelect(1)
  400. else
  401. -- Can't re-equip autonomously, wait for player to give us a tool.
  402. io.write("HALP! I need a new tool.\n")
  403. repeat
  404. event.pull(10, "inventory_changed")
  405. until robot.durability()
  406. end
  407. end
  408. end
  409.  
  410. -- Ensures we have some torches.
  411. local function checkTorches()
  412. -- First, clean up our list and look for empty slots.
  413. io.write("Getting my fill of torches.\n")
  414. local oldTorchSlots = torchSlots
  415. torchSlots = {}
  416. for _, slot in ipairs(oldTorchSlots) do
  417. keepSlot[slot] = nil
  418. if robot.count(slot) > 0 then
  419. torchSlots[#torchSlots + 1] = slot
  420. end
  421. end
  422. while #torchSlots < torchStacks() do
  423. local slot = findEmptySlot()
  424. if not slot then
  425. break -- This should never happen...
  426. end
  427. torchSlots[#torchSlots + 1] = slot
  428. end
  429. -- Then fill the slots with torches.
  430. robot.turnLeft()
  431. for _, slot in ipairs(torchSlots) do
  432. keepSlot[slot] = true
  433. if robot.space(slot) > 0 then
  434. cachedSelect(slot)
  435. repeat
  436. local before = robot.space()
  437. robot.suck(robot.space())
  438. if robot.space() == before then
  439. os.sleep(5) -- Don't busy idle.
  440. end
  441. until robot.space() < 1
  442. cachedSelect(1)
  443. end
  444. end
  445. robot.turnRight()
  446. end
  447.  
  448. -- Recharge our batteries.
  449. local function recharge()
  450. io.write("Waiting until my batteries are full.\n")
  451. while computer.maxEnergy() - computer.energy() > 100 do
  452. os.sleep(1)
  453. end
  454. end
  455.  
  456. -- Go back to the docking bay for general maintenance if necessary.
  457. local function gotoMaintenance(force)
  458. if not force and not needsMaintenance() then
  459. return -- No need yet.
  460. end
  461.  
  462. -- Save some values for later, temporarily remove onMove callback.
  463. local returnCost = costToReturn()
  464. local moveCallback = onMove
  465. onMove = nil
  466.  
  467. local top, count = getTop()
  468.  
  469. io.write("Going back for maintenance!\n")
  470. local moves = popMoves()
  471.  
  472. assert(distanceToOrigin == 0)
  473.  
  474. dropMinedBlocks()
  475. checkTool()
  476. checkTorches()
  477. recharge() -- Last so we can charge some during the other operations.
  478.  
  479. if moves and #moves > 0 then
  480. if returnCost * 2 > computer.maxEnergy() and
  481. not options.f and
  482. not prompt("Going back will cost me half my energy. There's a good chance I will not return. Do you want to send me to my doom anyway?")
  483. then
  484. os.exit()
  485. end
  486. io.write("Returning to where I left off.\n")
  487. pushMoves(moves)
  488. end
  489.  
  490. local newTop, newCount = getTop()
  491. assert(top == newTop)
  492. assert(count == newCount)
  493.  
  494. onMove = moveCallback
  495. end
  496.  
  497. --[[ Mining ]]-----------------------------------------------------------------
  498.  
  499. -- Move towards the specified direction, digging out blocks as necessary.
  500. -- This is a "soft" version of forceMove in that it will try to clear its path,
  501. -- but fail if it can't.
  502. local function move(side)
  503. local result, reason, retry
  504. repeat
  505. retry = false
  506. if side ~= sides.back then
  507. retry = dig(side, gotoMaintenance)
  508. else
  509. gotoMaintenance()
  510. end
  511. result, reason = pushMove(side)
  512. until result or not retry
  513. return result, reason
  514. end
  515.  
  516. -- Turn to face the specified, relative orientation.
  517. local function turnTowards(side)
  518. if side == sides.left then
  519. pushTurn(left)
  520. elseif side == sides.right then
  521. pushTurn(right)
  522. elseif side == sides.back then
  523. pushTurn(left)
  524. pushTurn(left)
  525. end
  526. end
  527.  
  528. --[[ On move callbacks ]]------------------------------------------------------
  529.  
  530. -- Start automatically placing torches in the configured interval.
  531. local function beginPlacingTorches()
  532. local counter = 2
  533. onMove = function()
  534. if counter < 1 then
  535. if placeTorch() then
  536. counter = torchInverval
  537. end
  538. else
  539. counter = counter - 1
  540. end
  541. end
  542. end
  543.  
  544. -- Start digging out the block below us after each move.
  545. local function beginDigginTrench()
  546. onMove = function()
  547. dig(sides.down, gotoMaintenance)
  548. end
  549. end
  550.  
  551. -- Stop automatically placing torches.
  552. local function clearMoveCallback()
  553. onMove = nil
  554. end
  555.  
  556. --[[ Moving ]]-----------------------------------------------------------------
  557.  
  558. -- Dig out any interesting ores adjacent to the current position, recursively.
  559. -- POST: back to the starting position and facing.
  560. local function digVein(maxDepth)
  561. if maxDepth < 1 then return end
  562. for _, side in ipairs(sides) do
  563. side = sides[side]
  564. if shouldMine(component.geolyzer.analyze(side)) then
  565. local top, count = getTop()
  566. turnTowards(side)
  567. if side == sides.up or side == sides.down then
  568. move(side)
  569. else
  570. move(sides.forward)
  571. end
  572. digVein(maxDepth - 1)
  573. setTop(top, count)
  574. end
  575. end
  576. end
  577.  
  578. -- Dig out any interesting ores adjacent to the current position, recursively.
  579. -- Also checks blocks adjacent to above block in exhaustive mode.
  580. -- POST: back at the starting position and facing.
  581. local function digVeins(exhaustive)
  582. if component.isAvailable("geolyzer") then
  583. digVein(maxVeinRecursion)
  584. if exhaustive and move(sides.up) then
  585. digVein(maxVeinRecursion)
  586. popMove()
  587. end
  588. end
  589. end
  590.  
  591. -- Dig a 1x2 tunnel of the specified length. Checks for ores.
  592. -- Also checks upper row for ores in exhaustive mode.
  593. -- PRE: bottom front of tunnel to dig.
  594. -- POST: at the end of the tunnel.
  595. local function dig1x2(length, exhaustive)
  596. while length > 0 and move(sides.forward) do
  597. dig(sides.up, gotoMaintenance)
  598. digVeins(exhaustive)
  599. length = length - 1
  600. end
  601. return length < 1
  602. end
  603.  
  604. -- Dig a 1x3 tunnel of the specified length.
  605. -- PRE: center front of tunnel to dig.
  606. -- POST: at the end of the tunnel.
  607. local function dig1x3(length)
  608. while length > 0 and move(sides.forward) do
  609. dig(sides.up, gotoMaintenance)
  610. dig(sides.down, gotoMaintenance)
  611. length = length - 1
  612. end
  613. return length < 1
  614. end
  615.  
  616. -- Dig out a main shaft.
  617. -- PRE: bottom front of main shaft.
  618. -- POST: bottom front of main shaft.
  619. local function digMainShaft(length)
  620. io.write("Digging main shaft.\n")
  621.  
  622. if not move(sides.up) then
  623. return false
  624. end
  625.  
  626. local top, count = getTop()
  627.  
  628. if not (dig1x3(length) and
  629. pushTurn(left) and
  630. dig1x3(1) and
  631. pushTurn(left) and
  632. dig1x3(length - 1) and
  633. (placeTorch() or true) and -- Just keep going...
  634. pushTurn(left) and
  635. dig1x3(1))
  636. then
  637. return false
  638. end
  639.  
  640. -- Create snapshot for shortcut below.
  641. local midTop, midCount = getTop()
  642.  
  643. if not (dig1x3(1) and
  644. pushTurn(left) and
  645. dig1x3(length - 1))
  646. then
  647. return false
  648. end
  649. placeTorch()
  650.  
  651. -- Shortcut: manually move back to start, do an unsafe setTop.
  652. -- Otherwise we'd have to retrace all three rows.
  653. setTop(midTop, midCount)
  654. if pushTurn(left) and move(sides.back) then
  655. setTop(top, count, true)
  656. return true
  657. end
  658.  
  659. return false
  660. end
  661.  
  662. -- Dig all shafts in one cardinal direction (the one we're facing).
  663. -- PRE: bottom front of a main shaft.
  664. -- POST: bottom front of a main shaft.
  665. local function digShafts(length)
  666. local top, count = getTop() -- Remember start of main shaft.
  667. local ok = digMainShaft(length)
  668. setTop(top, count)
  669. if not ok then
  670. io.write("Failed digging main shaft, skipping.\n")
  671. return
  672. end
  673.  
  674. io.write("Beginning work on side shafts.\n")
  675. for i = shaftInterval, length, shaftInterval do
  676. io.write("Working on shafts #" .. (i / shaftInterval) .. ".\n")
  677.  
  678. if not dig1x2(shaftInterval) then -- Move to height of shaft.
  679. break
  680. end
  681. local sideTop, sideCount = getTop() -- Remember position.
  682.  
  683. pushTurn(left) -- Dig left shaft.
  684. dig1x2(i + 2, true)
  685. beginPlacingTorches()
  686. setTop(sideTop, sideCount)
  687. clearMoveCallback()
  688.  
  689. pushTurn(right) -- Dig right shaft.
  690. dig1x2(i + 2, true)
  691. beginPlacingTorches()
  692. setTop(sideTop, sideCount)
  693. clearMoveCallback()
  694. end
  695.  
  696. -- Go back to start of main shaft. Dig out the center of the main shaft
  697. -- while we're at it, so we break through the ceiling between levels.
  698. beginDigginTrench()
  699. setTop(top, count)
  700. clearMoveCallback()
  701. end
  702.  
  703. -- Moves to the next main shaft, clockwise.
  704. -- PRE: bottom front of nth main shaft.
  705. -- POST: bottom front of (n+1)th main shaft.
  706. local function gotoNextMainShaft()
  707. return pushTurn(right) and
  708. dig1x2(2) and
  709. pushTurn(right) and
  710. dig1x2(2) and
  711. pushTurn(left)
  712. end
  713.  
  714. --[[ Main ]]-------------------------------------------------------------------
  715.  
  716. local function main(radius, levels, full)
  717. -- We dig tunnels every three blocks, to have a spacing of
  718. -- two blocks between them (so we don't really have to follow
  719. -- veins but can just break the blocks in the wall that are
  720. -- interesting to us). So adjust the length accordingly.
  721. radius = radius - radius % shaftInterval
  722.  
  723. -- Flag slots that contain something as do-not-drop and check
  724. -- that we have some free inventory space at all.
  725. local freeSlots = robot.inventorySize()
  726. for slot = 1, robot.inventorySize() do
  727. if robot.count(slot) > 0 then
  728. keepSlot[slot] = true
  729. freeSlots = freeSlots - 1
  730. end
  731. end
  732. if freeSlots < 2 + torchStacks() then -- Place for mined blocks + torches.
  733. io.write("Sorry, but I need more empty inventory space to work.\n")
  734. os.exit()
  735. end
  736. gotoMaintenance(true)
  737.  
  738. if not move(sides.forward) then
  739. io.write("Exit from docking bay obstructed, aborting.\n")
  740. os.exit()
  741. end
  742.  
  743. for level = 1, levels do
  744. if level > 1 then
  745. for _ = 1, 4 do
  746. if not move(sides.down) then
  747. io.write("Access to level " .. level .. " obstructed, aborting.\n")
  748. popMoves()
  749. gotoMaintenance(true)
  750. os.exit()
  751. end
  752. end
  753. end
  754.  
  755. local top, count = getTop()
  756.  
  757. for shaft = 1, full and 4 or 1 do
  758. if shaft > 1 and not gotoNextMainShaft() then
  759. break
  760. end
  761. digShafts(radius)
  762. end
  763. if full then
  764. gotoNextMainShaft() -- Finish the circle.
  765. end
  766.  
  767. setTop(top, count)
  768. end
  769.  
  770. io.write("All done! Going home to clean up.\n")
  771. popMoves()
  772. gotoMaintenance(true)
  773. end
  774.  
  775. if options.h or options.help then
  776. io.write("Usage: miner [-hsf] [radius [levels [full]]]\n")
  777. io.write(" -h: this help listing.\n")
  778. io.write(" -s: start without prompting.\n")
  779. io.write(" -f: force mining to continue even if max\n")
  780. io.write(" fuel may be insufficient to return.\n")
  781. io.write(" radius: the radius in blocks of the area to\n")
  782. io.write(" mine. Adjusted to be a multiple of\n")
  783. io.write(" three. Default: 9.\n")
  784. io.write(" levels: the number of vertical levels to mine.\n")
  785. io.write(" Default: 1.\n")
  786. io.write(" full: whether to mine a full level (all four\n")
  787. io.write(" cardinal directions). Default: false.\n")
  788. os.exit()
  789. end
  790.  
  791. local radius = tonumber(args[1]) or 9
  792. local levels = tonumber(args[2]) or 1
  793. local full = args[3] and args[3] == "true" or args[3] == "yes"
  794.  
  795. io.write("Will mine " .. levels .. " levels in a radius of " .. radius .. ".\n")
  796. if full then
  797. io.write("Will mine all four cardinal directions.\n")
  798. end
  799. if not component.isAvailable("geolyzer") then
  800. io.write("Installing a geolyzer upgrade is strongly recommended.\n")
  801. end
  802. if not component.isAvailable("inventory_controller") then
  803. io.write("Installing an inventory controller upgrade is strongly recommended.\n")
  804. end
  805.  
  806. io.write("I'll drop mined out stuff below me.\n")
  807. io.write("I'll be looking for torches on my left.\n")
  808. if component.isAvailable("inventory_controller") then
  809. io.write("I'll try to get new tools from above me.\n")
  810. else
  811. io.write("You'll need to manually provide me with new tools if they break.\n")
  812. end
  813.  
  814. io.write("Run with -h or --help for parameter info.\n")
  815.  
  816. if options.s or prompt("Shall we begin?") then
  817. main(radius, levels, full)
  818. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement