npexception

CC TurtleQuarry

Dec 19th, 2014 (edited)
4,212
0
Never
2
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 24.36 KB | None | 0 0
  1. local version = 3.22
  2.  
  3. -- >TODO<
  4. --[[
  5.   * add more status prints
  6.   * replace parameter 'burnfuel' with 'fuel.list' file
  7.     for checkFuel and isInventoryFull (fuelSources)
  8.   * allow "tag@" prefix in ignore/allow list to compare with block tags (e.g. "forge:stone")
  9.   * switch to using position data from BetterTurtleAPI to check if we need to dig a hole:
  10.     local function isHole(x,y)
  11.       return (y + x * 3) % 5 == 0
  12.     end
  13.   * maybe check if dropoff point has/is inventory?
  14. ]]--
  15.  
  16. --  +------------------------+  --
  17. --  |-->  INITIALIZATION  <--|  --
  18. --  +------------------------+  --
  19. if not turtle then
  20.   print("This program can only be")
  21.   print("  executed by a turtle!")
  22.   return
  23. end
  24.  
  25. -- UPDATE HANDLING --
  26. if _UD and _UD.su(version, "HqXCPzCg", {...}) then return end
  27.  
  28. local ARGS = {...}
  29.  
  30. -- INITIALIZING NECESSARY FUNCTIONS
  31. local startswith = function(text, piece)
  32.   return string.sub(text, 1, string.len(piece)) == piece
  33. end
  34.  
  35. local function isTableEmpty(tbl)
  36.   for k,v in pairs(tbl) do
  37.     return false
  38.   end
  39.   return true
  40. end
  41.  
  42. local function itemName(slot)
  43.   local details = turtle.getItemDetail(slot)
  44.   return details and details.name
  45. end
  46.  
  47. local function itemDetails(slot)
  48.   local details = turtle.getItemDetail(slot)
  49.   return details and details.name.."#"..tostring(details.damage)
  50. end
  51.  
  52.  
  53. local oreDictPeripheral = peripheral.find("oreDictionary")
  54.  
  55.  
  56. -- possible drop-off blocks
  57. -- (everything else with "chest" in the name will work too)
  58. local dropSpots = {
  59.   ["Railcraft:tile.railcraft.machine.beta"] = true,
  60.   ["quark:pipe"] = true,
  61. }
  62.  
  63. -- directions in relation to initial placement direction (which is 0, or north)
  64. local direction = {front=0, right=1, back=2, left=3}
  65.  
  66. -- INITIAL VARIABLE SETUP --
  67. local quarry = {
  68.   -- width and length of the quarry site
  69.   width = 16,
  70.   length = 16,
  71.  
  72.   -- offsets
  73.   offsetH = 0,
  74.  
  75.   -- maximum depth the turtle will dig down, starting at offsetH
  76.   maxDepth = 0,
  77.  
  78.   -- table with valid fuel source items
  79.   fuelSources = nil,
  80.   skipHoles = 0,
  81.  
  82.   -- transmutation targets for known ore dictionary entries
  83.   oreDictData = nil,
  84.  
  85.   -- enable logging status to log.txt
  86.   enableLogging = false,
  87.   -- supresses all status information (takes precedence over enableLogging)
  88.   silent = false,
  89.   -- use delay parameter for the status function
  90.   statusDelay = false,
  91.  
  92.   -- depth in the curren colum
  93.   depth = 0,
  94.   -- x and y position on the specified grid. turtle starts one block in front of the lower left corner of the area
  95.   posx = 1,
  96.   posy = 1,
  97.   facing = direction.front,
  98.  
  99.   -- >TODO< quarry offsets for x,y and depth
  100.  
  101.   -- list of blocks/things to ignore
  102.   ignore = nil,
  103.   -- list of blocks/things to allow (overrules ignore list)
  104.   allow = nil,
  105.  
  106.   -- table of mined blocks
  107.   rememberBlocks = false,
  108.   minedBlocks = {},
  109. }
  110.  
  111. local function log(text)
  112.   if not quarry.enableLogging then
  113.     return
  114.   end
  115.   local f = fs.open("log.txt","a")
  116.   f.write(tostring(os.date()).."\n")
  117.   f.write(text.."\n")
  118.   f.close()
  119. end
  120.  
  121. local function saveMinedBlocks()
  122.   if not quarry.rememberBlocks then
  123.     return
  124.   end
  125.   local f = fs.open("mined-blocks.txt","w")
  126.   for name,_ in pairs(quarry.minedBlocks) do
  127.     f.write(name.."\n")
  128.   end
  129.   f.close()
  130. end
  131.  
  132. -- READ OUT COMMAND LINE PARAMETERS --
  133.  
  134. for _,par in pairs(ARGS) do
  135.   if startswith(par, "w:") then
  136.     quarry.width = tonumber(string.sub(par, string.len("w:")+1))
  137.     print("Quarry width: "..tostring(quarry.width))
  138.    
  139.   elseif startswith(par, "l:") then
  140.     quarry.length = tonumber(string.sub(par, string.len("l:")+1))
  141.     print("Quarry length: "..tostring(quarry.length))
  142.    
  143.   elseif startswith(par, "offh:") then
  144.     quarry.offsetH = tonumber(string.sub(par, string.len("offh:")+1))
  145.     print("Quarry height offset: "..tostring(quarry.offsetH))
  146.    
  147.   elseif startswith(par, "maxd:") then
  148.     quarry.maxDepth = tonumber(string.sub(par, string.len("maxd:")+1))
  149.     print("Quarry maximum depth: "..tostring(quarry.maxDepth))
  150.    
  151.   elseif startswith(par, "skip:") then
  152.     quarry.skipHoles = tonumber(string.sub(par, string.len("skip:")+1))
  153.     print("Skipping the first "..tostring(quarry.skipHoles).." holes")
  154.    
  155.   elseif par == "burnfuel" then
  156.     quarry.fuelSources = {["minecraft:coal"] = true}
  157.     print("Fuel item usage activated")
  158.  
  159.   elseif par == "oredict" then
  160.     local configFile = "oredict.config"
  161.     if oreDictPeripheral and fs.exists(configFile) then
  162.       local file = fs.open(configFile, "r")
  163.       local content = file.readAll()
  164.       file.close()
  165.       local data = textutils.unserialise(content)
  166.       if not isTableEmpty(data) then
  167.         quarry.oreDictData = data
  168.       end
  169.     end
  170.     if not oreDictPeripheral then
  171.       print("No ore dictionary equipped")
  172.     elseif not quarry.oreDictData then
  173.       print("No useful '"..configFile.."' found")
  174.     else
  175.       print("Using ore dictionary")
  176.     end
  177.  
  178.   elseif par == "enable-logging" then
  179.     quarry.enableLogging = true
  180.     print("Logging enabled")
  181.    
  182.   elseif par == "remember-blocks" then
  183.     quarry.rememberBlocks = true
  184.     print("Remember blocks enabled")
  185.  
  186.   elseif par == "silent" then
  187.     quarry.silent = true
  188.     print("Disabled status information")
  189.  
  190. elseif par == "statusdelay" then
  191.     quarry.statusDelay = true
  192.     print("Enabled status delay")
  193.   end
  194. end
  195.  
  196. -- read ignore file
  197. local ignoreFile = "ignore.list"
  198. if fs.exists(ignoreFile) and not fs.isDir(ignoreFile) then
  199.   local file = fs.open(ignoreFile, "r")
  200.   local ok, list = pcall(textutils.unserialize, file.readAll())
  201.   file.close()
  202.   if ok then
  203.     -- convert list to lookup table
  204.     quarry.ignore = {}
  205.     for _,name in pairs(list) do
  206.       quarry.ignore[name] = true
  207.     end
  208.     print("Ignoring blocks found in \""..ignoreFile.."\"")
  209.   else
  210.     print("Could not unserialize table from file content: "..ignoreFile)
  211.     return
  212.   end
  213. else
  214.   print("No \""..ignoreFile.."\" found.")
  215. end
  216.  
  217. -- read allow file
  218. local allowFile = "allow.list"
  219. if fs.exists(allowFile) and not fs.isDir(allowFile) then
  220.   local file = fs.open(allowFile, "r")
  221.   local ok, list = pcall(textutils.unserialize, file.readAll())
  222.   file.close()
  223.   if ok then
  224.     -- convert list to lookup table
  225.     quarry.allow = {}
  226.     for _,name in pairs(list) do
  227.       quarry.allow[name] = true
  228.     end
  229.     print("Allowing blocks found in \""..allowFile.."\"")
  230.   else
  231.     print("Could not unserialize table from file content: "..allowFile)
  232.     return
  233.   end
  234. else
  235.   print("No \""..allowFile.."\" found.")
  236. end
  237.  
  238.  
  239. term.write("Starting program ")
  240. for i=1,10 do
  241.   term.write(".")
  242.   sleep(1)
  243. end
  244. print(" go")
  245. turtle.select(1)
  246.  
  247.  
  248. -- frequently used globals as locals for performance
  249. local turtle = turtle
  250. local term = term
  251. local colors = colors
  252. local textutils = textutils
  253. local sleep = sleep
  254. local peripheral = peripheral
  255.  
  256. local tostring = tostring
  257. local print = print
  258.  
  259. --  +-------------------+  --
  260. --  |-->  FUNCTIONS  <--|  --
  261. --  +-------------------+  --
  262.  
  263. local function status(text, color, delay)
  264.   if quarry.silent then
  265.     return
  266.   end
  267.   log(text)
  268.   term.clear()
  269.   term.setCursorPos(1,1)
  270.   if term.isColor() then
  271.     term.setTextColor(colors.yellow)
  272.   end
  273.   print(" Turtle-Quarry "..tostring(version))
  274.   print("--------------------")
  275.   print()
  276.   if term.isColor() then
  277.     term.setTextColor(colors.white)
  278.   end
  279.   term.write("--> ")
  280.   if term.isColor() then
  281.     if color == nil then
  282.       color = colors.white
  283.     end
  284.     term.setTextColor(color)
  285.   end
  286.   print(text)
  287.   if term.isColor() and color ~= colors.white then
  288.     term.setTextColor(colors.white)
  289.   end
  290.   if delay and quarry.statusDelay then
  291.     sleep(delay)
  292.   end
  293. end
  294.  
  295. -- selects the given slot if it isn't selected yet
  296. local function select(slot)
  297.   if turtle.getSelectedSlot() == slot then
  298.     return true
  299.   end
  300.   return turtle.select(slot)
  301. end
  302.  
  303.  
  304. local function forward()
  305.   while not turtle.forward() do
  306.     select(1)
  307.     turtle.dig()
  308.     turtle.attack()
  309.   end
  310.   if quarry.facing == direction.front then
  311.     quarry.posy = quarry.posy + 1
  312.   elseif quarry.facing == direction.back then
  313.     quarry.posy = quarry.posy - 1
  314.   elseif quarry.facing == direction.right then
  315.     quarry.posx = quarry.posx + 1
  316.   else
  317.     quarry.posx = quarry.posx - 1
  318.   end
  319. end
  320.  
  321. local function up()
  322.   while not turtle.up() do
  323.     select(1)
  324.     turtle.digUp()
  325.     turtle.attackUp()
  326.   end
  327. end
  328.  
  329. local function down()
  330.   while not turtle.down() do
  331.     select(1)
  332.     turtle.digDown()
  333.     turtle.attackDown()
  334.   end
  335. end
  336.  
  337. local function turnRight()
  338.   turtle.turnRight()
  339.   quarry.facing = quarry.facing+1
  340.   if (quarry.facing > 3) then
  341.     quarry.facing = 0
  342.   end
  343. end
  344.  
  345. local function turnLeft()
  346.   turtle.turnLeft()
  347.   quarry.facing = quarry.facing-1
  348.   if (quarry.facing < 0) then
  349.     quarry.facing = 3
  350.   end
  351. end
  352.  
  353. -- checks if the given item name is on the 'allow' list
  354. local function isAllowed(itemName)
  355.   return quarry.allow[itemName]
  356. end
  357.  
  358. -- checks if the given item name is not on the 'ignore' list
  359. local function isNotIgnored(itemName)
  360.   return not quarry.ignore[itemName]
  361. end
  362.  
  363. local function alwaysTrue()
  364.   return true
  365. end
  366.  
  367. -- checks if a given item name is of interest for the quarry
  368. local isDesired =
  369.     quarry.allow and isAllowed
  370.     or quarry.ignore and isNotIgnored
  371.     or alwaysTrue
  372.  
  373.  
  374. --[[
  375.   Burns the item in the given slot if it is a valid fuel item.
  376. ]]--
  377. local function useFuelItem(slot)
  378.   return quarry.fuelSources
  379.          and quarry.fuelSources[itemName(slot)]
  380.          and select(slot)
  381.          and turtle.refuel()
  382. end
  383.  
  384.  
  385. --[[
  386.   Checks if fuel level is okay
  387.   and refuels if needed.
  388.   Returns TRUE if fuel level is good,
  389.   or FALSE if fuel level is low and
  390.   nothing could get refuelled.
  391.   Fuel check is determined by how much is needed to reach
  392.   the given destination from the starting point (+ safety measure), times the given factor.
  393. ]]--
  394. local function checkFuel(posx, posy, depth, factor, allowAnySource)
  395.   -- if fuel is needed, check if we can consume something
  396.   if turtle.getFuelLevel() <= ((depth + posx + posy + 100) * factor) then
  397.     status("Need fuel, trying to fill up...", colors.lightBlue, 0.5)
  398.     local refuelFn = allowAnySource and turtle.refuel or useFuelItem
  399.     local success = false
  400.     for i=1,16 do
  401.       if turtle.getItemCount(i) > 0 then
  402.         -- turtle.refuel only works on the currently selected slot
  403.         select(i)
  404.         -- lua will evaluate until one of the statements is true. meaning that it would not
  405.         -- execute "turtle.refuel()" if it stood after the "or" once success is true.
  406.         success = refuelFn() or success
  407.       end
  408.     end
  409.     local color = success and colors.lime or colors.orange
  410.     local text = "Refuel success: "..tostring(success)
  411.     if success then
  412.       text = text.." ("..tostring(turtle.getFuelLevel())..")"
  413.     end
  414.     status(text, color, 0.5)
  415.     return success
  416.   end
  417.   return true
  418. end
  419.  
  420. local function isInventoryEmpty()
  421.   for i=1,16 do
  422.     if turtle.getItemCount(i) > 0 then
  423.       return false
  424.     end
  425.   end
  426.   return true
  427. end
  428.  
  429.  
  430. --[[
  431.   Check if the item in the specified slot
  432.   is desired by the quarry. If it's not, tries
  433.   to drop it down, then forward, then up.
  434.   Returns true if waste was dropped,
  435.   and false if it was not waste or could
  436.   not be dropped.
  437. ]]--
  438. local function dropWaste(slot)
  439.   local item = turtle.getItemDetail(slot).name
  440.   return not isDesired(item)
  441.          and select(slot)
  442.          and (turtle.dropDown()
  443.               or turtle.drop()
  444.               or turtle.dropUp())
  445. end
  446.  
  447.  
  448. local function getDropSpotName()
  449.   local ok, data = turtle.inspectUp()
  450.   if ok and (dropSpots[data.name] or data.name:lower():find("chest")) then
  451.     return data.name
  452.   end
  453. end
  454.  
  455.  
  456. local function dropItemsInChest()
  457.   local dropSpotName = getDropSpotName()
  458.   while not dropSpotName do
  459.     status("No inventory to drop items into...", colors.orange)
  460.     sleep(3)
  461.     dropSpotName = getDropSpotName()
  462.   end
  463.  
  464.   status("Dropping into \""..dropSpotName.."\"", colors.lightBlue, 0.5)
  465.   while true do
  466.     for i=1,16 do
  467.       if turtle.getItemCount(i) > 0 then
  468.         -- check if item is waste
  469.         if not dropWaste(i) then
  470.           -- otherwise drop
  471.           select(i)
  472.           turtle.dropUp()
  473.         end
  474.       end
  475.     end
  476.     if isInventoryEmpty() then
  477.       break
  478.     else
  479.       sleep(3)
  480.     end
  481.   end
  482. end
  483.  
  484. --[[
  485.   Attempts to transmute the items in the given slot
  486.   to a potential target item. Returns TRUE if the item
  487.   was transmuted, otherwise FALSE.
  488. ]]--
  489. local function transmuteItem(slot)
  490.   select(slot)
  491.   if not oreDictPeripheral then
  492.     return false
  493.   end
  494.   for _,entry in pairs(oreDictPeripheral.getEntries()) do
  495.     local target = quarry.oreDictData[entry]
  496.     if target then
  497.       local name = itemDetails()
  498.       local seen = {name=true}
  499.       -- transmute to target as necessary
  500.       while name ~= target do
  501.         oreDictPeripheral.transmute()
  502.         name = itemDetails()
  503.         -- check if we tried all possibilities
  504.         if seen[name] then
  505.           print(entry..": can't transmute '"..name.."' to target item")
  506.           return false
  507.         end
  508.         seen[name] = true
  509.       end
  510.       return true
  511.     end
  512.   end
  513.   return false
  514. end
  515.  
  516.  
  517. --[[
  518.   Finds the first empty slot that represents a gap in the inventory
  519. ]]--
  520. local function findInventoryGap()
  521.   local gap = nil
  522.   for i=1,16 do
  523.     local empty = turtle.getItemCount(i) == 0
  524.     if empty then
  525.       gap = gap or i
  526.     elseif gap then
  527.       return gap
  528.     end
  529.   end
  530. end
  531.  
  532. --[[
  533.   Attempts to move the items in slot 'src' to slot 'dest'.
  534.   Returns true if the entire stack was successfully moved,
  535.   false otherwise.
  536. ]]--
  537. local function moveStack(src, dest)
  538.   return
  539.     select(src)
  540.     and turtle.transferTo(dest)
  541.     and turtle.getItemCount(src) == 0
  542. end
  543.  
  544.  
  545. --[[
  546.   Tries to merge stacks, and group all items
  547.   at the beginning of the inventory.
  548. ]]--
  549. local function defragInventory()
  550.   -- first part: merge stacks and fill early empty spots
  551.   for src=16,2,-1 do
  552.     if turtle.getItemCount(src) > 0 then
  553.       local srcName = itemDetails(src)
  554.       for dest=1,src-1 do
  555.         if (turtle.getItemCount(dest) == 0 or srcName == itemDetails(dest))
  556.            and moveStack(src, dest) then
  557.           break
  558.         end
  559.       end
  560.     end
  561.   end
  562.   -- second second: fill gaps caused by merging stacks
  563.   local gap = findInventoryGap()
  564.   if gap then
  565.     for src=16,gap+1,-1 do
  566.       if turtle.getItemCount(src) > 0 then
  567.         for dest=1,src-1 do
  568.           if turtle.getItemCount(dest) == 0 and moveStack(src, dest) then
  569.             break
  570.           end
  571.         end
  572.       end
  573.     end
  574.   end
  575. end
  576.  
  577.  
  578. --[[
  579.   merges stacks and removes gaps in the inventory
  580. ]]--
  581. local function compressInventory()
  582.   -- iterate through inventory
  583.   for i=1,16 do
  584.     if turtle.getItemCount(i) > 0 then
  585.       local success =
  586.           -- try to use item as fuel
  587.           useFuelItem(i)
  588.           -- see if it can be thrown away
  589.           or dropWaste(i)
  590.           -- maybe it can be transmuted
  591.           or transmuteItem(i)
  592.     end
  593.   end
  594.   -- merge stacks and remove gaps
  595.   defragInventory()
  596. end
  597.  
  598.  
  599. --[[
  600.   Returns if inventory is full.
  601.   If it is full, attempts to free up
  602.   some space first.
  603. ]]--
  604. local function isInventoryFull()
  605.   if turtle.getItemCount(16) == 0 then
  606.     return false
  607.   end
  608.   compressInventory()
  609.   -- ensure that some slots are free after cleaning up,
  610.   -- otherwise cleaning up the inventory will eat up more time
  611.   -- than just going home and dropping items
  612.   return turtle.getItemCount(14) > 0
  613. end
  614.  
  615.  
  616. --[[
  617.   Makes the turtle return to the
  618.   starting position and empty
  619.   it's inventory in a chest if
  620.   one is available.
  621. ]]--
  622. local function backHome( continueAfterwards )
  623.   -- move up to depth 0
  624.   local lastDepth = quarry.depth
  625.   local lastFacing = quarry.facing
  626.   while quarry.depth > 0 do
  627.     up()
  628.     quarry.depth = quarry.depth - 1
  629.   end
  630.  
  631.   -- go home in x-direction
  632.   local lastX = quarry.posx
  633.   if lastX > 1 then
  634.     while quarry.facing ~= direction.left do
  635.       turnLeft()
  636.     end
  637.     while quarry.posx > 1 do
  638.       forward()
  639.     end
  640.   end
  641.  
  642.   -- go home in y-direction
  643.   local lastY = quarry.posy
  644.   while quarry.facing ~= direction.back do
  645.     turnLeft()
  646.   end
  647.   while quarry.posy > 1 do
  648.     forward()
  649.   end
  650.  
  651.   -- go up the offset
  652.   if quarry.offsetH > 0 then
  653.     for i=1,quarry.offsetH do
  654.       up()
  655.     end
  656.   end
  657.  
  658.   -- WE ARE HOME NOW
  659.  
  660.   compressInventory()
  661.  
  662.   -- refuel if configured
  663.   if quarry.fuelSources then
  664.     status("Trying to use fuel...", colors.lightBlue)
  665.     for i=1,16 do
  666.       useFuelItem(i)
  667.     end
  668.   end
  669.  
  670.   -- drop items
  671.   local isEmpty = isInventoryEmpty()
  672.   if (not isEmpty) then
  673.     dropItemsInChest() -- empty inventory guaranteed after return
  674.     isEmpty = true
  675.   end
  676.    
  677.   -- save mined blocks list
  678.   saveMinedBlocks()
  679.  
  680.   -- CONTINUE WORK IF NECESSARY
  681.   if continueAfterwards then
  682.     while (not checkFuel(lastX, lastY, lastDepth, 2, true)) or (not isEmpty) do
  683.       sleep(3)
  684.       isEmpty = isInventoryEmpty()
  685.     end
  686.     status("Continuing work...", colors.lime)
  687.    
  688.     -- go down the offset
  689.     if quarry.offsetH > 0 then
  690.       for i=1,quarry.offsetH do
  691.         down()
  692.       end
  693.     end
  694.  
  695.     -- back to hole in y-direction
  696.     while quarry.facing ~= direction.front do
  697.       turnLeft()
  698.     end
  699.     while quarry.posy < lastY do
  700.       forward()
  701.     end
  702.  
  703.     -- back to hole in x-direction
  704.     if lastX > 1 then
  705.       while quarry.facing ~= direction.right do
  706.         turnRight()
  707.       end
  708.       while quarry.posx < lastX do
  709.         forward()
  710.       end
  711.     end
  712.  
  713.     -- back down the hole
  714.     while quarry.depth < lastDepth do
  715.       down()
  716.       quarry.depth = quarry.depth+1
  717.     end
  718.  
  719.     while quarry.facing ~= lastFacing do
  720.       turnLeft()
  721.     end
  722.   end
  723. end
  724.  
  725.  
  726. local inspectBlocks = (quarry.ignore or quarry.allow)
  727.                       and true or false -- convert to boolean
  728.  
  729. --[[
  730.   Checks the blocks on the four adjacent
  731.   sides for desired blocks.
  732.   A block is mined if it does not match
  733.   any block in the ignore table, or
  734.   is listed in the allow table.
  735. ]]--
  736. local function digSides()
  737.   for i=1,4 do
  738.     local digIt = turtle.detect()
  739.     if digIt and inspectBlocks then
  740.       local success, data = turtle.inspect()
  741.       if success then
  742.         digIt = isDesired(data.name)
  743.         if digIt and quarry.rememberBlocks then
  744.           quarry.minedBlocks[data.name] = true
  745.         end
  746.       end
  747.     end
  748.     if digIt then
  749.       select(1)
  750.       turtle.dig()
  751.       if isInventoryFull() then
  752.         backHome(true)
  753.       end
  754.     end
  755.     turnLeft()
  756.   end  
  757. end
  758.  
  759. --[[
  760.   Convenience function to check for a block below before digging down
  761. ]]--
  762. local function drill()
  763.   if turtle.detectDown() then
  764.     select(1)
  765.     turtle.digDown()
  766.     if isInventoryFull() then
  767.       backHome(true)
  768.     end
  769.   end
  770. end
  771.  
  772. --[[
  773.   Digs down a colum, only taking the blocks
  774.   which are not in the compare slots.
  775. ]]--
  776. local function digColumn()
  777.   drill()
  778.   while true do
  779.     if not checkFuel(quarry.posx, quarry.posy, quarry.depth, 1, false) then
  780.       backHome(true)
  781.     end
  782.    
  783.     if not turtle.down() then
  784.       drill()
  785.       if not turtle.down() then
  786.         break
  787.       end
  788.     end
  789.     quarry.depth = quarry.depth + 1
  790.     if isInventoryFull() then
  791.       backHome(true)
  792.     end
  793.     digSides()
  794.    
  795.     -- check if maxDepth is reached
  796.     if (quarry.maxDepth > 0) and (quarry.depth >= quarry.maxDepth) then
  797.       break;
  798.     end
  799.    
  800.     drill()
  801.   end
  802.  
  803.   while quarry.depth > 0 do
  804.     up()
  805.     quarry.depth = quarry.depth - 1
  806.   end
  807.  
  808.   status("Hole at x:"..tostring(quarry.posx).." y:"..tostring(quarry.posy).." is done.", colors.lightBlue)
  809. end
  810.  
  811. -- go forward for a number of steps, and check fuel level and inventory filling on the way
  812. local function stepsForward(count)
  813.   if (count > 0) then
  814.     for i=1,count do
  815.       if not checkFuel(quarry.posx, quarry.posy, quarry.depth, 1, false)
  816.           or isInventoryFull() then
  817.         backHome(true)
  818.       end
  819.       forward()
  820.     end
  821.   end
  822. end
  823.  
  824.  
  825. local function calculateSkipOffset()
  826.   local running = true
  827.  
  828.   local facing = direction.front
  829.   local x = 1
  830.   local y = 1
  831.  
  832.   while running do
  833.     quarry.skipHoles = quarry.skipHoles - 1
  834.    
  835.     -- check for finish condition
  836.     if (x == quarry.width) then
  837.       if ((facing == direction.front) and ((y + 5) > quarry.length))
  838.           or ((facing == direction.back) and ((y-5) < 1)) then
  839.         running = false
  840.       end
  841.     end
  842.    
  843.     if running then
  844.       -- find path and go to next hole
  845.       if facing == direction.front then
  846.         if y+5 <= quarry.length then
  847.           -- next hole in same line
  848.           y = y+5
  849.         elseif y+3 <= quarry.length then
  850.           -- next hole in next column, above the current positon
  851.           y = y+3
  852.           x = x+1
  853.           facing = direction.back
  854.         else
  855.           -- next hole in next column, below the current positon
  856.           x = x+1
  857.           facing = direction.back
  858.           y = y-2
  859.         end
  860.       elseif facing == direction.back then
  861.         if y-5 >= 1 then
  862.           -- next hole in same line
  863.           y = y-5
  864.         elseif y-2 >= 1 then
  865.           -- next hole in next column, below the current positon
  866.           y = y-2
  867.           x = x+1
  868.           facing = direction.front
  869.         else
  870.           -- next hole in next column, above the current positon
  871.           x = x+1
  872.           facing = direction.front
  873.           y = y+3
  874.         end
  875.       end
  876.     end
  877.    
  878.     if (quarry.skipHoles <= 0) then
  879.       break
  880.     end
  881.   end
  882.  
  883.   return x,y,facing,running
  884. end
  885.  
  886.  
  887. local function main()
  888.   status("Working...", colors.lightBlue)
  889.  
  890.   local running = true
  891.  
  892.   -- check initial fuel level
  893.   while (not checkFuel(quarry.posx, quarry.posy, quarry.offsetH, 2, true)) do
  894.     sleep(3)
  895.   end
  896.  
  897.   -- go down the offset
  898.   if quarry.offsetH > 0 then
  899.     for i=1,quarry.offsetH do
  900.       down()
  901.     end
  902.   end
  903.  
  904.   -- are there holes to skip?
  905.   if (quarry.skipHoles > 0) then
  906.     local x,y,facing
  907.     x,y,facing, running = calculateSkipOffset()
  908.     status("Skip offset: x="..tostring(x).." y="..tostring(y), colors.lightBlue)
  909.     if running then
  910.       stepsForward(y-1)
  911.       turnRight()
  912.       stepsForward(x-1)
  913.       while (quarry.facing ~= facing) do
  914.         turnLeft()
  915.       end
  916.     end
  917.   end
  918.  
  919.   while running do
  920.    
  921.     -- remember facing
  922.     local lastFacing = quarry.facing
  923.     digColumn()
  924.     -- restore facing if necessary
  925.     while quarry.facing ~= lastFacing do
  926.       turnLeft()
  927.     end
  928.    
  929.     -- check for finish condition
  930.     if (quarry.posx == quarry.width) then
  931.       if ((quarry.facing == direction.front) and ((quarry.posy + 5) > quarry.length))
  932.           or ((quarry.facing == direction.back) and ((quarry.posy-5) < 1)) then
  933.         running = false
  934.       end
  935.     end
  936.    
  937.     if running then
  938.       -- find path and go to next hole
  939.       if quarry.facing == direction.front then
  940.         if quarry.posy+5 <= quarry.length then
  941.           -- next hole in same line
  942.           stepsForward(5)
  943.         elseif quarry.posy+3 <= quarry.length then
  944.           -- next hole in next column, above the current positon
  945.           stepsForward(3)
  946.           turnRight()
  947.           stepsForward(1)
  948.           turnRight()
  949.         else
  950.           -- next hole in next column, below the current positon
  951.           turnRight()
  952.           stepsForward(1)
  953.           turnRight()
  954.           stepsForward(2)
  955.         end
  956.        
  957.       elseif quarry.facing == direction.back then
  958.         if quarry.posy-5 >= 1 then
  959.           -- next hole in same line
  960.           stepsForward(5)
  961.         elseif quarry.posy-2 >= 1 then
  962.           -- next hole in next column, above the current positon
  963.           stepsForward(2)
  964.           turnLeft()
  965.           stepsForward(1)
  966.           turnLeft()
  967.         else
  968.           -- next hole in next column, below the current positon
  969.           turnLeft()
  970.           stepsForward(1)
  971.           turnLeft()
  972.           stepsForward(3)
  973.         end
  974.       else
  975.         -- this should not happen, but in case it does, we just send the turtle home.
  976.         running = false
  977.       end
  978.     end    
  979.   end
  980.   status("Finished quarry. Returning home...", colors.lime)
  981.  
  982.   backHome(false)
  983.  
  984.   status("Done.", colors.lightBlue)
  985. end
  986.  
  987. --  +-----------------------+  --
  988. --  |-->  program start  <--| --
  989. --  +-----------------------+  --
  990.  
  991. main()
Comments
  • AR0ACE
    357 days
    # text 0.10 KB | 1 0
    1. hey, will this still work if the chunk becomes unloaded? or will I have to fetch the turtle and restart it
    • npexception
      357 days
      # text 0.26 KB | 0 0
      1. Unfortunately the program can't resume after the chunk unloaded. I had planned to add that functionality but couldn't find a reliable way for the turtle to resume work. I rarely play Minecraft anymore, so if I someday add that feature, it will be far in the future.
Add Comment
Please, Sign In to add comment