Advertisement
pulchroxloom

Turtle Scripting based on Michael Reeves' Work

Dec 22nd, 2020 (edited)
296
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- == Movement Constants ==
  2. local FORWARD = 1
  3. local BACK = 2
  4. local UP = 4
  5. local DOWN = 8
  6. local TURN_RIGHT = 16
  7. local TURN_LEFT = 32
  8. -- == Data ==
  9. -- Constants
  10. local SLOT_COUNT = 16
  11. local LABEL = os.getComputerLabel()
  12. local WIRELESS = false
  13. local SERVER_CHANNEL = 65534
  14. local ERROR_SERVER_CHANNEL = 65535
  15. local CHANNEL = nil
  16. -- Mutable Data
  17. local moves = {}
  18. local dt = "right" -- Direction Tangent (right, left)
  19. local dv = "up" -- Direction Vertical (up, down)
  20. local refill_lava = false -- Consume picked up lava
  21. local width, depth, height = 10, 10, 2
  22. -- == Peripherals ==
  23. local modem = nil
  24. local peripherals = peripheral.getNames()
  25. for name = 1, #peripherals, 1 do
  26.     if(peripheral.getType(peripherals[name]) == "modem") then
  27.         modem = peripheral.wrap(peripherals[name])
  28.         WIRELESS = true
  29.         break
  30.     end
  31. end
  32.  
  33. if(WIRELESS) then
  34.     if(LABEL == "white") then CHANNEL = 0
  35.     elseif(LABEL == "orange") then CHANNEL = 1
  36.     elseif(LABEL == "magenta") then CHANNEL = 2
  37.     elseif(LABEL == "light_blue") then CHANNEL = 3
  38.     elseif(LABEL == "yellow") then CHANNEL = 4
  39.     elseif(LABEL == "lime") then CHANNEL = 5
  40.     elseif(LABEL == "pink") then CHANNEL = 6
  41.     elseif(LABEL == "gray" or LABEL == "grey") then CHANNEL = 7
  42.     elseif(LABEL == "light_gray" or LABEL == "light_grey") then CHANNEL = 8
  43.     elseif(LABEL == "cyan") then CHANNEL = 9
  44.     elseif(LABEL == "purple") then CHANNEL = 10
  45.     elseif(LABEL == "blue") then CHANNEL = 11
  46.     elseif(LABEL == "brown") then CHANNEL = 12
  47.     elseif(LABEL == "green") then CHANNEL = 13
  48.     elseif(LABEL == "red") then CHANNEL = 14
  49.     elseif(LABEL == "black") then CHANNEL = 15
  50.     end
  51.  
  52.     if(CHANNEL == nil) then
  53.         c = term.getTextColor()
  54.         term.setTextColor(colors.red)
  55.         print("Modem without a label. This robot has no channel!")
  56.         term.setTextColor(c)
  57.         WIRELESS = false
  58.     else
  59.         modem.open(CHANNEL)
  60.     end
  61. end
  62.  
  63. -- Stolen From: http://lua-users.org/wiki/SimpleRound
  64. function round(num, numDecimalPlaces)
  65.     local mult = 10^(numDecimalPlaces or 0)
  66.     return math.floor(num * mult + 0.5) / mult
  67. end
  68.  
  69. function transmit(message)
  70.     if(WIRELESS) then
  71.         modem.transmit(SERVER_CHANNEL, CHANNEL, message)
  72.     end
  73. end
  74.  
  75. function transmitError(message, forward)
  76.     if(WIRELESS) then
  77.         modem.transmit(ERROR_SERVER_CHANNEL, CHANNEL, message)
  78.         if(forward) then
  79.             transmit(message)
  80.         end
  81.     end
  82. end
  83.  
  84. function get_file_name(file)
  85.     file = file or debug.getinfo(1,'S').source
  86.     return file:match("^@(.+)$")
  87. end
  88.  
  89. HOLD_ITEMS = {
  90.     "minecraft:coal",
  91.     "minecraft:coal_block",
  92.     "minecraft:bucket"
  93. }
  94.  
  95. DROPPED_ITEMS = {
  96.     "minecraft:stone",
  97.     "minecraft:dirt",
  98.     "minecraft:cobblestone",
  99.     "minecraft:sand",
  100.     "minecraft:gravel",
  101.     "minecraft:redstone",
  102.     "minecraft:flint",
  103.     "minecraft:clay_ball",
  104.     "railcraft:ore_metal",
  105.     "railcraft:ore_metal_poor",
  106.     "extrautils2:ingredients",
  107.     "chisel:marble2",
  108.     "chisel:limestone2",
  109.     "chisel:basalt2",
  110. --    "minecraft:dye", -- Lapis Lazuli
  111.     "thaumcraft:nugget",
  112.     "thaumcraft:crystal_essence",
  113.     "thermalfoundation:material",
  114.     "projectred-core:resource_item",
  115.     "thaumcraft:ore_cinnabar",
  116.     "deepresonance:resonating_ore",
  117.     "forestry:apatite"
  118. }
  119.  
  120. function dropItems()
  121.     print("Purging Inventory...")
  122.     for slot = 1, SLOT_COUNT, 1 do
  123.         local item = turtle.getItemDetail(slot)
  124.         if(item ~= nil) then
  125.             for filterIndex = 1, #DROPPED_ITEMS, 1 do
  126.                 if(item["name"] == DROPPED_ITEMS[filterIndex]) then
  127.                     print("Dropping - " .. item["name"])
  128.                     turtle.select(slot)
  129.                     turtle.dropDown()
  130.                 end
  131.             end
  132.         end
  133.     end
  134. end
  135.  
  136. function getItemIndex(find_item)
  137.     if(type(find_item) ~= "string") then
  138.         error("Expected string but got " .. type(find_item))
  139.     end
  140.     for slot = 1, SLOT_COUNT, 1 do
  141.         local item = turtle.getItemDetail(slot)
  142.         if(item ~= nil) then
  143.             if(item["name"] == find_item) then
  144.                 return slot
  145.             end
  146.         end
  147.     end
  148.     return nil
  149. end
  150.  
  151. function countAllOf(search_item)
  152.     if(type(search_item) ~= "string") then
  153.         error("Expected string but got " .. type(search_item))
  154.     end
  155.     count = 0
  156.     for slot = 1, SLOT_COUNT, 1 do
  157.         local item = turtle.getItemDetail(slot)
  158.         if(item ~= nil) then
  159.             if(item["name"] == search_item) then
  160.                 count = count + turtle.getItemCount()
  161.             end
  162.         end
  163.     end
  164.     return count
  165. end
  166.  
  167. function countStoredFuel()
  168.     return countAllOf("minecraft:coal") * 80 + countAllOf("minecraft:coal_block") * 720 + countAllOf("minecraft:lava_bucket") * 1000
  169. end
  170.  
  171. function coalesce()
  172.     for slot = 1, SLOT_COUNT - 1, 1 do
  173.         local base_item = turtle.getItemDetail(slot)
  174.         if(base_item ~= nil) then
  175.             for i = slot + 1, SLOT_COUNT, 1 do
  176.                 local item = turtle.getItemDetail(slot)
  177.                 if(item ~= nil and base_item["name"] == item["name"]) then
  178.                     turtle.select(i)
  179.                     turtle.transferTo(slot)
  180.                 end
  181.             end
  182.         end
  183.     end
  184. end
  185.  
  186. function getNumberFreeSlots()
  187.     local freeSlots = 0
  188.     for slot = 1, SLOT_COUNT, 1 do
  189.         local item = turtle.getItemDetail(slot)
  190.         if(item == nil) then
  191.             freeSlots = freeSlots + 1
  192.         end
  193.     end
  194.     return freeSlots
  195. end
  196.  
  197. function shouldReturnItem(item)
  198.     if(refill_lava and item["name"] == "minecraft:lava_bucket") then
  199.         return false
  200.     end
  201.     for filterIndex = 1, #HOLD_ITEMS, 1 do
  202.         if(item["name"] == HOLD_ITEMS[filterIndex]) then
  203.             return false
  204.         end
  205.     end
  206.     return true
  207. end
  208.  
  209. function manageInventory(dumpAll)
  210.     transmit("Managing Inventory")
  211.     index = turtle.getSelectedSlot()
  212.     while(index ~= nil) do
  213.         index = getItemIndex("enderstorage:ender_storage")
  214.         if(index == nil) then break end
  215.         digUp()
  216.         dropItems()
  217.         turtle.select(index)
  218.         if(turtle.placeUp()) then
  219.             break
  220.         else
  221.             print("Chest not placed correctly... Trying again")
  222.         end
  223.     end
  224.     local success, data = turtle.inspectUp()
  225.     if(index == nil or (success and data.name ~= "enderstorage:ender_storage")) then
  226.         transmitError("Ender Storage Missing")
  227.         return false
  228.     end
  229.     -- Chest is now deployed
  230.     coalesce()
  231.     for slot = 1, SLOT_COUNT, 1 do
  232.         local item = turtle.getItemDetail(slot)
  233.         if(item ~= nil) then
  234.             if(dumpAll or shouldReturnItem(item)) then
  235.                 turtle.select(slot)
  236.                 turtle.dropUp()
  237.             elseif not shouldReturnItem(item) and turtle.getItemSpace(slot) <= 0 then
  238.                 for i = slot + 1, SLOT_COUNT, 1 do
  239.                     local dump = turtle.getItemDetail(i)
  240.                     if(dump ~= nil and item["name"] == dump["name"]) then
  241.                         turtle.select(i)
  242.                         turtle.dropUp()
  243.                     end
  244.                 end
  245.             end
  246.         end
  247.     end
  248.     -- Items are now stored
  249.     turtle.select(1)
  250.     if(getNumberFreeSlots() >= 1) then
  251.         digUp()
  252.     else
  253.         transmitError("Cannot Pick Up Ender Storage, Full Inventory")
  254.         print("Cannot pick up Ender Storage, full inventory")
  255.         return false
  256.     end
  257.     return true
  258. end
  259.  
  260. function checkFuel()
  261.     if(turtle.getFuelLevel() < 25) then
  262.         -- transmit("Attempting Refuel...")
  263.         print("Attempting Refuel...")
  264.         for slot = 1, SLOT_COUNT, 1 do
  265.             turtle.select(slot)
  266.             if(turtle.refuel(1)) then
  267.                 -- transmit("Refuel Success!   Fuel: " .. turtle.getFuelLevel())
  268.                 return true
  269.             end
  270.         end
  271.         return false
  272.     else
  273.         return true
  274.     end
  275. end
  276.  
  277. function digUp()
  278.     local success, data = turtle.inspectUp()
  279.     if(success and data.name == "minecraft:lava" and bucket_index ~= nil and getNumberFreeSlots() > 1) then
  280.         -- transmit("Bucketing Lava Up...")
  281.         turtle.select(bucket_index)
  282.         turtle.placeUp()
  283.         lava_index = getItemIndex("minecraft:lava_bucket")
  284.         if(refill_lava and lava_index and turtle.getFuelLevel() + 1000 < turtle.getFuelLimit()) then
  285.             -- transmit("Consumed newly bucketed lava.   Fuel: " .. turtle.getFuelLevel())
  286.             turtle.select(getItemIndex("minecraft:lava_bucket"))
  287.             turtle.refuel()
  288.             turtle.transferTo(bucket_index)
  289.         end
  290.         bucket_index = getItemIndex("minecraft:bucket")
  291.     end
  292.     local block_above = data.name
  293.     while(turtle.detectUp()) do
  294.         local success, data = turtle.inspectUp()
  295.         if(success) then
  296.             block_above = data.name
  297.         end
  298.         if(block_above == "minecraft:gravel" or block_above == "minecraft:sand") then
  299.             turtle.digUp()
  300.             os.sleep(0.75)
  301.         else
  302.             turtle.digUp()
  303.         end
  304.     end
  305. end
  306.  
  307. function detectAndDig()
  308.     slot = turtle.getSelectedSlot()
  309.     bucket_index = getItemIndex("minecraft:bucket")
  310.     local success, data = turtle.inspect()
  311.     if(success and data.name == "minecraft:lava" and bucket_index ~= nil and getNumberFreeSlots() > 1) then
  312.         -- transmit("Bucketing Lava...")
  313.         turtle.select(bucket_index)
  314.         turtle.place()
  315.         lava_index = getItemIndex("minecraft:lava_bucket")
  316.         if(refill_lava and lava_index and turtle.getFuelLevel() + 1000 < turtle.getFuelLimit()) then
  317.             -- transmit("Consumed newly bucketed lava.   Fuel: " .. turtle.getFuelLevel())
  318.             turtle.select(lava_index)
  319.             turtle.refuel()
  320.             turtle.transferTo(bucket_index)
  321.         end
  322.         bucket_index = getItemIndex("minecraft:bucket")
  323.     end
  324.     while(turtle.detect()) do
  325.         turtle.dig()
  326.     end
  327.     digUp()
  328.     local success, data = turtle.inspectDown()
  329.     if(success and data.name == "minecraft:lava" and bucket_index ~= nil and getNumberFreeSlots() > 1) then
  330.         -- transmit("Bucketing Lava Down...")
  331.         turtle.select(bucket_index)
  332.         turtle.placeDown()
  333.         lava_index = getItemIndex("minecraft:lava_bucket")
  334.         if(refill_lava and lava_index and turtle.getFuelLevel() + 1000 < turtle.getFuelLimit()) then
  335.             -- transmit("Consumed newly bucketed lava.   Fuel: " .. turtle.getFuelLevel())
  336.             turtle.select(getItemIndex("minecraft:lava_bucket"))
  337.             turtle.refuel()
  338.             turtle.transferTo(bucket_index)
  339.         end
  340.         bucket_index = getItemIndex("minecraft:bucket")
  341.     end
  342.     if(turtle.detectDown()) then
  343.         turtle.digDown()
  344.     end
  345.     turtle.select(slot)
  346. end
  347.  
  348. function invertMove(move)
  349.     if move == FORWARD or move == UP or move == TURN_RIGHT then
  350.         return move * 2
  351.     elseif move == BACK or move == DOWN or move == TURN_LEFT then
  352.         return move / 2
  353.     end
  354.     return move
  355. end
  356.  
  357. function stackSmash()
  358.     local i = 1
  359.     while i <= #moves do
  360.         if(moves[i] == invertMove(moves[i + 1])) then
  361.             for j = 1, 2, 1 do
  362.                 table.remove(moves, i)
  363.             end
  364.             i = i - (2 - 1)
  365.         end
  366.         if(moves[i] == moves[i+1] and moves[i] == moves[i+2] and moves[i] == moves[i+3] and (moves[i] == TURN_LEFT or moves[i] == TURN_RIGHT)) then
  367.             for j = 1, 4, 1 do
  368.                 table.remove(moves, i)
  369.             end
  370.             i = i - (4 - 1)
  371.         end
  372.         i = i + 1
  373.     end
  374. end
  375.  
  376. function forward(times)
  377.     times = times or 1
  378.     for i = 1, times, 1 do
  379.         if(not checkFuel()) then
  380.             transmitError("Turtle is out of fuel, Powering Down...")
  381.             error("Turtle is out of fuel, Powering Down...")
  382.         end
  383.         if(turtle.forward()) then
  384.             table.insert(moves, FORWARD)
  385.             stackSmash()
  386.         else
  387.             return false
  388.         end
  389.     end
  390.     return true
  391. end
  392.  
  393. function back(times)
  394.     times = times or 1
  395.     for i = 1, times, 1 do
  396.         if(not checkFuel()) then
  397.             transmitError("Turtle is out of fuel, Powering Down...")
  398.             error("Turtle is out of fuel, Powering Down...")
  399.         end
  400.         if(turtle.back()) then
  401.             table.insert(moves, BACK)
  402.             stackSmash()
  403.         else
  404.             return false
  405.         end
  406.     end
  407.     return true
  408. end
  409.  
  410. function up(times)
  411.     times = times or 1
  412.     for i = 1, times, 1 do
  413.         if(not checkFuel()) then
  414.             transmitError("Turtle is out of fuel, Powering Down...")
  415.             error("Turtle is out of fuel, Powering Down...")
  416.         end
  417.         if(turtle.up()) then
  418.             table.insert(moves, UP)
  419.             stackSmash()
  420.         else
  421.             return false
  422.         end
  423.     end
  424.     return true
  425. end
  426.  
  427. function down(times)
  428.     times = times or 1
  429.     for i = 1, times, 1 do
  430.         if(not checkFuel()) then
  431.             transmitError("Turtle is out of fuel, Powering Down...")
  432.             error("Turtle is out of fuel, Powering Down...")
  433.         end
  434.         if(turtle.down()) then
  435.             table.insert(moves, DOWN)
  436.             stackSmash()
  437.         else
  438.             return false
  439.         end
  440.     end
  441.     return true
  442. end
  443.  
  444. function turnLeft(times)
  445.     times = times or 1
  446.     for i = 1, times, 1 do
  447.         if(not checkFuel()) then
  448.             transmitError("Turtle is out of fuel, Powering Down...")
  449.             error("Turtle is out of fuel, Powering Down...")
  450.         end
  451.         if(turtle.turnLeft()) then
  452.             table.insert(moves, TURN_LEFT)
  453.             stackSmash()
  454.         else
  455.             return false
  456.         end
  457.     end
  458.     return true
  459. end
  460.  
  461. function turnRight(times)
  462.     times = times or 1
  463.     for i = 1, times, 1 do
  464.         if(not checkFuel()) then
  465.             transmitError("Turtle is out of fuel, Powering Down...")
  466.             error("Turtle is out of fuel, Powering Down...")
  467.         end
  468.         if(turtle.turnRight()) then
  469.             table.insert(moves, TURN_RIGHT)
  470.             stackSmash()
  471.         else
  472.             return false
  473.         end
  474.     end
  475.     return true
  476. end
  477.  
  478. function leftTurn()
  479.     turnLeft()
  480.     detectAndDig()
  481.     forward()
  482.     turnLeft()
  483.     detectAndDig()
  484. end
  485.  
  486.  
  487. function rightTurn()
  488.     turnRight()
  489.     detectAndDig()
  490.     forward()
  491.     turnRight()
  492.     detectAndDig()
  493. end
  494.  
  495. function flipDirection(logging)
  496.     if(logging == nil) then logging = true end
  497.     if(logging) then
  498.         turnLeft(2)
  499.     else
  500.         turtle.turnLeft()
  501.         turtle.turnLeft()
  502.     end
  503. end
  504.  
  505. function flipDirectionTangent()
  506.     if(dt == "right") then
  507.         dt = "left"
  508.     elseif(dt == "left") then
  509.         dt = "right"
  510.     end
  511. end
  512.  
  513. function flipDirectionVertical()
  514.     if(dv == "up") then
  515.         dv = "down"
  516.     elseif(dv == "down") then
  517.         dv = "up"
  518.     end
  519. end
  520.  
  521. function turnAround()
  522.     if(dt == "right") then
  523.         rightTurn()
  524.     elseif(dt == "left") then
  525.         leftTurn()
  526.     end
  527.     flipDirectionTangent()
  528. end
  529.  
  530. function riseTier(delta)
  531.     flipDirection()
  532.     delta = delta or 1 -- Default delta is 1
  533.     for step = 1, delta, 1 do
  534.         digUp()
  535.         turtle.digDown()
  536.         if(dv == "up") then
  537.             up()
  538.         elseif(dv == "down") then
  539.             down()
  540.         end
  541.     end
  542. end
  543.  
  544. function returnToStart()
  545.     flipDirection(false)
  546.     for i = #moves, 1, -1 do
  547.         move = moves[i]
  548.         if move == UP or move == DOWN or move == TURN_LEFT or move == TURN_RIGHT then
  549.             move = invertMove(move)
  550.         end
  551.         if move == FORWARD then
  552.             detectAndDig()
  553.             forward()
  554.         elseif move == BACK then back()
  555.         elseif move == UP then up()
  556.         elseif move == DOWN then down()
  557.         elseif move == TURN_LEFT then turnLeft()
  558.         elseif move == TURN_RIGHT then turnRight()
  559.         end
  560.     end
  561.     flipDirection(false)
  562. end
  563.  
  564. function start()
  565.     transmit("Begin " .. depth .. "x" .. width .. "x" .. height .. " " .. dv .. " and " .. dt)
  566.     print("Volume: D x W x H = " .. depth .. " x " .. width .. " x " .. height)
  567.     print("Direction: " .. dv .. " and to the " .. dt)
  568.     if(WIRELESS) then
  569.         print("Wireless is Enabled")
  570.     end
  571.     count = 0
  572.     delta = 3
  573.     total = depth * width * height
  574.     height = math.max(height - 1, 1)
  575.     tier = math.min(height, 2)
  576.     while tier <= height do
  577.         for col = 1, width, 1 do
  578.             for row = 1, depth - 1, 1 do
  579.                 if(not checkFuel()) then
  580.                     transmitError("Turtle is out of fuel, Powering Down...")
  581.                     error("Turtle is out of fuel, Powering Down...")
  582.                     return
  583.                 end
  584.                 if(getNumberFreeSlots() < 1) then
  585.                     -- transmit("Inventory Full, Dropping Items...")
  586.                     coalesce()
  587.                     dropItems()
  588.                     if(getNumberFreeSlots() < 1) then
  589.                         if(not manageInventory()) then
  590.                             transmitError("Turtle cannot find ender chest... Returning to Start")
  591.                             print("Turtle cannot find ender chest...")
  592.                             returnToStart()
  593.                             return
  594.                         end
  595.                     end
  596.                 end
  597.                 detectAndDig()
  598.                 count = count + delta
  599.                 while not forward() do
  600.                     checkFuel()
  601.                     if turtle.detect() then
  602.                         turtle.dig()
  603.                     else
  604.                         turtle.attack()
  605.                     end
  606.                 end
  607.                 print(string.format("Row: %d   Col: %d   Tier: %d   Fuel: %d", row, col, tier, turtle.getFuelLevel()))
  608.             end
  609.             if(col ~= width) then
  610.                 turnAround()
  611.             end
  612.             transmit("Completed Column #" .. col .. "   Fuel: " .. turtle.getFuelLevel() .. "   Completion: " .. count .. "/" .. total .. " (" .. round(100*count/total, 3) .. "%)")
  613.         end
  614.         transmit("Completed Layer #" .. tier .. "   Fuel: " .. turtle.getFuelLevel() .. "   Completion: " .. count .. "/" .. total .. " (" .. round(100*count/total) .. "%)")
  615.         if(tier < height) then
  616.             if(tier + 2 < height) then
  617.                 delta = 3
  618.                 tier = tier + 2
  619.                 riseTier(3)
  620.             elseif(tier + 1 < height) then
  621.                 delta = 2
  622.                 tier = tier + 1
  623.                 riseTier(2)
  624.             else
  625.                 delta = 1
  626.                 riseTier()
  627.             end
  628.         end
  629.         tier = tier + 1
  630.     end
  631.     transmit("Completed All Layers, Returning to Start" .. "   Fuel: " .. turtle.getFuelLevel())
  632.     returnToStart()
  633.     transmit("At Start" .. "   Fuel: " .. turtle.getFuelLevel())
  634.     if(not manageInventory(true)) then
  635.         transmit("Turtle cannot find ender chest, This is a serious issue...")
  636.         print("Turtle cannot find ender chest, This is a serious issue...")
  637.     end
  638.     transmit("End " .. depth .. "x" .. width .. "x" .. height .. " " .. dv .. " and " .. dt)
  639. end
  640.  
  641. if (#arg >= 3) then
  642.     depth = tonumber(arg[1])
  643.     width = tonumber(arg[2])
  644.     height = tonumber(arg[3])
  645.     for i = 4, #arg, 1 do
  646.         if arg[i] == "flip" then flipDirection()
  647.         elseif arg[i] == "up" or arg[i] == "down" then dv = arg[i]
  648.         elseif arg[i] == "left" or arg[i] == "right" then dt = arg[i]
  649.         elseif arg[i] == "refill" then refill_lava = true
  650.         else error("Unkown Argument #" .. i .. ": " .. arg[i])
  651.         end
  652.     end
  653. else
  654.     error("Usage: " .. get_file_name() .. " depth width height [left] [right] [up] [down] [flip]\n - left -- robot goes left (overrides right)\n - right -- robot goes right [default] (overrides left)\n - up -- robot goes up [default] (overrides down)\n - down -- robot goes down (overrides up)\n - flip -- robot immediately rotates 180 degrees\n - refill -- robot consumes lava buckets [disabled by default]")
  655. end
  656.  
  657. start()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement